    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    package org.apache.commons.jxpath.ri.model.dom;
    018
    019    import java.util.ArrayList;
    020    import java.util.List;
    021
    022    import org.apache.commons.jxpath.ri.QName;
    023    import org.apache.commons.jxpath.ri.model.NodeIterator;
    024    import org.apache.commons.jxpath.ri.model.NodePointer;
    025    import org.w3c.dom.Attr;
    026    import org.w3c.dom.Element;
    027    import org.w3c.dom.NamedNodeMap;
    028    import org.w3c.dom.Node;
    029
    030    /**
    031     * An iterator of attributes of a DOM Node.
    032     *
    033     * @author Dmitri Plotnikov
    034     * @version $Revision: 652845 $ $Date: 2008-05-02 12:46:46 -0500 (Fri, 02 May 2008) $
    035     */
    036    public class DOMAttributeIterator implements NodeIterator {
    037        private NodePointer parent;
    038        private QName name;
    039        private List attributes;
    040        private int position = 0;
    041
    042        /**
    043         * Create a new DOMAttributeIterator.
    044         * @param parent pointer
    045         * @param name to test
    046         */
    047        public DOMAttributeIterator(NodePointer parent, QName name) {
    048            this.parent = parent;
    049            this.name = name;
    050            attributes = new ArrayList();
    051            Node node = (Node) parent.getNode();
    052            if (node.getNodeType() == Node.ELEMENT_NODE) {
    053                String lname = name.getName();
    054                if (!lname.equals("*")) {
    055                    Attr attr = getAttribute((Element) node, name);
    056                    if (attr != null) {
    057                        attributes.add(attr);
    058                    }
    059                }
    060                else {
    061                    NamedNodeMap map = node.getAttributes();
    062                    int count = map.getLength();
    063                    for (int i = 0; i < count; i++) {
    064                        Attr attr = (Attr) map.item(i);
    065                        if (testAttr(attr)) {
    066                            attributes.add(attr);
    067                        }
    068                    }
    069                }
    070            }
    071        }
    072
    073        /**
    074         * Test an attribute.
    075         * @param attr to test
    076         * @return whether test succeeded
    077         */
    078        private boolean testAttr(Attr attr) {
    079            String nodePrefix = DOMNodePointer.getPrefix(attr);
    080            String nodeLocalName = DOMNodePointer.getLocalName(attr);
    081
    082            if (nodePrefix != null && nodePrefix.equals("xmlns")) {
    083                return false;
    084            }
    085
    086            if (nodePrefix == null && nodeLocalName.equals("xmlns")) {
    087                return false;
    088            }
    089
    090            String testLocalName = name.getName();
    091            if (testLocalName.equals("*") || testLocalName.equals(nodeLocalName)) {
    092                String testPrefix = name.getPrefix();
    093
    094                if (testPrefix == null || equalStrings(testPrefix, nodePrefix)) {
    095                    return true;
    096                }
    097                if (nodePrefix == null) {
    098                    return false;
    099                }
    100                return equalStrings(parent.getNamespaceURI(testPrefix), parent
    101                        .getNamespaceURI(nodePrefix));
    102            }
    103            return false;
    104        }
    105
    106        /**
    107         * Test whether two strings are == or .equals()
    108         * @param s1 first string
    109         * @param s2 second string
    110         * @return boolean
    111         */
    112        private static boolean equalStrings(String s1, String s2) {
    113            return s1 == s2 || s1 != null && s1.equals(s2);
    114        }
    115
    116        /**
    117         * Get the named attribute.
    118         * @param element to search
    119         * @param name to match
    120         * @return Attr found
    121         */
    122        private Attr getAttribute(Element element, QName name) {
    123            String testPrefix = name.getPrefix();
    124            String testNS = null;
    125
    126            if (testPrefix != null) {
    127                testNS = parent.getNamespaceResolver().getNamespaceURI(testPrefix);
    128            }
    129
    130            if (testNS != null) {
    131                Attr attr = element.getAttributeNodeNS(testNS, name.getName());
    132                if (attr != null) {
    133                    return attr;
    134                }
    135
    136                // This may mean that the parser does not support NS for
    137                // attributes, example - the version of Crimson bundled
    138                // with JDK 1.4.0
    139                NamedNodeMap nnm = element.getAttributes();
    140                for (int i = 0; i < nnm.getLength(); i++) {
    141                    attr = (Attr) nnm.item(i);
    142                    if (testAttr(attr)) {
    143                        return attr;
    144                    }
    145                }
    146                return null;
    147            }
    148            return element.getAttributeNode(name.getName());
    149        }
    150
    151        public NodePointer getNodePointer() {
    152            if (position == 0) {
    153                if (!setPosition(1)) {
    154                    return null;
    155                }
    156                position = 0;
    157            }
    158            int index = position - 1;
    159            if (index < 0) {
    160                index = 0;
    161            }
    162            return new DOMAttributePointer(parent, (Attr) attributes.get(index));
    163        }
    164
    165        public int getPosition() {
    166            return position;
    167        }
    168
    169        public boolean setPosition(int position) {
    170            this.position = position;
    171            return position >= 1 && position <= attributes.size();
    172        }
    173    }