View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.jxpath.ri.model.dom;
18  
19  import java.util.ArrayList;
20  import java.util.List;
21  
22  import org.apache.commons.jxpath.ri.QName;
23  import org.apache.commons.jxpath.ri.model.NodeIterator;
24  import org.apache.commons.jxpath.ri.model.NodePointer;
25  import org.w3c.dom.Attr;
26  import org.w3c.dom.Element;
27  import org.w3c.dom.NamedNodeMap;
28  import org.w3c.dom.Node;
29  
30  /**
31   * An iterator of attributes of a DOM Node.
32   *
33   * @author Dmitri Plotnikov
34   * @version $Revision: 652845 $ $Date: 2008-05-02 19:46:46 +0200 (Fr, 02 Mai 2008) $
35   */
36  public class DOMAttributeIterator implements NodeIterator {
37      private NodePointer parent;
38      private QName name;
39      private List attributes;
40      private int position = 0;
41  
42      /**
43       * Create a new DOMAttributeIterator.
44       * @param parent pointer
45       * @param name to test
46       */
47      public DOMAttributeIterator(NodePointer parent, QName name) {
48          this.parent = parent;
49          this.name = name;
50          attributes = new ArrayList();
51          Node node = (Node) parent.getNode();
52          if (node.getNodeType() == Node.ELEMENT_NODE) {
53              String lname = name.getName();
54              if (!lname.equals("*")) {
55                  Attr attr = getAttribute((Element) node, name);
56                  if (attr != null) {
57                      attributes.add(attr);
58                  }
59              }
60              else {
61                  NamedNodeMap map = node.getAttributes();
62                  int count = map.getLength();
63                  for (int i = 0; i < count; i++) {
64                      Attr attr = (Attr) map.item(i);
65                      if (testAttr(attr)) {
66                          attributes.add(attr);
67                      }
68                  }
69              }
70          }
71      }
72  
73      /**
74       * Test an attribute.
75       * @param attr to test
76       * @return whether test succeeded
77       */
78      private boolean testAttr(Attr attr) {
79          String nodePrefix = DOMNodePointer.getPrefix(attr);
80          String nodeLocalName = DOMNodePointer.getLocalName(attr);
81  
82          if (nodePrefix != null && nodePrefix.equals("xmlns")) {
83              return false;
84          }
85  
86          if (nodePrefix == null && nodeLocalName.equals("xmlns")) {
87              return false;
88          }
89  
90          String testLocalName = name.getName();
91          if (testLocalName.equals("*") || testLocalName.equals(nodeLocalName)) {
92              String testPrefix = name.getPrefix();
93  
94              if (testPrefix == null || equalStrings(testPrefix, nodePrefix)) {
95                  return true;
96              }
97              if (nodePrefix == null) {
98                  return false;
99              }
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 }