    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *     http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017
    018package org.apache.commons.jxpath.ri.model.dom;
    019
    020import java.util.ArrayList;
    021import java.util.List;
    022
    023import org.apache.commons.jxpath.ri.model.NodeIterator;
    024import org.apache.commons.jxpath.ri.model.NodePointer;
    025import org.w3c.dom.Attr;
    026import org.w3c.dom.Document;
    027import org.w3c.dom.NamedNodeMap;
    028import org.w3c.dom.Node;
    029
    030/**
    031 * An iterator of namespaces of a DOM Node.
    032 */
    033public class DOMNamespaceIterator implements NodeIterator {
    034
    035    private final NodePointer parent;
    036    private final List<Attr> attributes;
    037    private int position;
    038
    039    /**
    040     * Constructs a new DOMNamespaceIterator.
    041     *
    042     * @param parent parent pointer
    043     */
    044    public DOMNamespaceIterator(final NodePointer parent) {
    045        this.parent = parent;
    046        attributes = new ArrayList<>();
    047        collectNamespaces(attributes, (Node) parent.getNode());
    048    }
    049
    050    /**
    051     * Collect namespaces from attribute nodes.
    052     *
    053     * @param attributes attribute list
    054     * @param node       target node
    055     */
    056    private void collectNamespaces(final List<Attr> attributes, Node node) {
    057        final Node parent = node.getParentNode();
    058        if (parent != null) {
    059            collectNamespaces(attributes, parent);
    060        }
    061        if (node.getNodeType() == Node.DOCUMENT_NODE) {
    062            node = ((Document) node).getDocumentElement();
    063        }
    064        if (node.getNodeType() == Node.ELEMENT_NODE) {
    065            final NamedNodeMap map = node.getAttributes();
    066            final int count = map.getLength();
    067            for (int i = 0; i < count; i++) {
    068                final Attr attr = (Attr) map.item(i);
    069                final String prefix = DOMNodePointer.getPrefix(attr);
    070                final String name = DOMNodePointer.getLocalName(attr);
    071                if (prefix != null && prefix.equals("xmlns") || prefix == null && name.equals("xmlns")) {
    072                    attributes.add(attr);
    073                }
    074            }
    075        }
    076    }
    077
    078    @Override
    079    public NodePointer getNodePointer() {
    080        if (position == 0) {
    081            if (!setPosition(1)) {
    082                return null;
    083            }
    084            position = 0;
    085        }
    086        int index = position - 1;
    087        if (index < 0) {
    088            index = 0;
    089        }
    090        String prefix = "";
    091        final Attr attr = attributes.get(index);
    092        final String name = attr.getPrefix();
    093        if (name != null && name.equals("xmlns")) {
    094            prefix = DOMNodePointer.getLocalName(attr);
    095        }
    096        return new NamespacePointer(parent, prefix, attr.getValue());
    097    }
    098
    099    @Override
    100    public int getPosition() {
    101        return position;
    102    }
    103
    104    @Override
    105    public boolean setPosition(final int position) {
    106        this.position = position;
    107        return position >= 1 && position <= attributes.size();
    108    }
    109}