    1   /*
    2    * Copyright 1999-2004 The Apache Software Foundation
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *     http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  package org.apache.commons.jxpath.ri.model.dom;
    17
    18  import java.util.ArrayList;
    19  import java.util.List;
    20
    21  import org.apache.commons.jxpath.ri.QName;
    22  import org.apache.commons.jxpath.ri.model.NodeIterator;
    23  import org.apache.commons.jxpath.ri.model.NodePointer;
    24  import org.w3c.dom.Attr;
    25  import org.w3c.dom.Element;
    26  import org.w3c.dom.NamedNodeMap;
    27  import org.w3c.dom.Node;
    28
    29  /***
    30   * An iterator of attributes of a DOM Node.
    31   *
    32   * @author Dmitri Plotnikov
    33   * @version $Revision: 1.11 $ $Date: 2004/02/29 14:17:44 $
    34   */
    35  public class DOMAttributeIterator implements NodeIterator {
    36      private NodePointer parent;
    37      private QName name;
    38      private List attributes;
    39      private int position = 0;
    40
    41      public DOMAttributeIterator(NodePointer parent, QName name) {
    42          this.parent = parent;
    43          this.name = name;
    44          attributes = new ArrayList();
    45          Node node = (Node) parent.getNode();
    46          if (node.getNodeType() == Node.ELEMENT_NODE) {
    47              String lname = name.getName();
    48              if (!lname.equals("*")) {
    49                  Attr attr = getAttribute((Element) node, name);
    50                  if (attr != null) {
    51                      attributes.add(attr);
    52                  }
    53              }
    54              else {
    55                  NamedNodeMap map = node.getAttributes();
    56                  int count = map.getLength();
    57                  for (int i = 0; i < count; i++) {
    58                      Attr attr = (Attr) map.item(i);
    59                      if (testAttr(attr, name)) {
    60                          attributes.add(attr);
    61                      }
    62                  }
    63              }
    64          }
    65      }
    66
    67      private boolean testAttr(Attr attr, QName testName) {
    68          String nodePrefix = DOMNodePointer.getPrefix(attr);
    69          String nodeLocalName = DOMNodePointer.getLocalName(attr);
    70
    71          if (nodePrefix != null && nodePrefix.equals("xmlns")) {
    72              return false;
    73          }
    74
    75          if (nodePrefix == null && nodeLocalName.equals("xmlns")) {
    76              return false;
    77          }
    78
    79          String testLocalName = name.getName();
    80          if (testLocalName.equals("*") || testLocalName.equals(nodeLocalName)) {
    81              String testPrefix = testName.getPrefix();
    82
    83              if (equalStrings(testPrefix, nodePrefix)) {
    84                  return true;
    85              }
    86
    87              String testNS = null;
    88              if (testPrefix != null) {
    89                  testNS = parent.getNamespaceURI(testPrefix);
    90              }
    91
    92              String nodeNS = null;
    93              if (nodePrefix != null) {
    94                  nodeNS = parent.getNamespaceURI(nodePrefix);
    95              }
    96              return equalStrings(testNS, nodeNS);
    97          }
    98          return false;
    99      }
    100
    101     private static boolean equalStrings(String s1, String s2) {
    102         if (s1 == null && s2 != null) {
    103             return false;
    104         }
    105         if (s1 != null && !s1.equals(s2)) {
    106             return false;
    107         }
    108         return true;
    109     }
    110
    111     private Attr getAttribute(Element element, QName name) {
    112         String testPrefix = name.getPrefix();
    113         String testNS = null;
    114
    115         if (testPrefix != null) {
    116             testNS = parent.getNamespaceURI(testPrefix);
    117         }
    118
    119         if (testNS != null) {
    120             Attr attr = element.getAttributeNodeNS(testNS, name.getName());
    121             if (attr != null) {
    122                 return attr;
    123             }
    124
    125             // This may mean that the parser does not support NS for
    126             // attributes, example - the version of Crimson bundled
    127             // with JDK 1.4.0
    128             NamedNodeMap nnm = element.getAttributes();
    129             for (int i = 0; i < nnm.getLength(); i++) {
    130                 attr = (Attr) nnm.item(i);
    131                 if (testAttr(attr, name)) {
    132                     return attr;
    133                 }
    134             }
    135             return null;
    136         }
    137         else {
    138             return element.getAttributeNode(name.getName());
    139         }
    140     }
    141
    142     public NodePointer getNodePointer() {
    143         if (position == 0) {
    144             if (!setPosition(1)) {
    145                 return null;
    146             }
    147             position = 0;
    148         }
    149         int index = position - 1;
    150         if (index < 0) {
    151             index = 0;
    152         }
    153         return new DOMAttributePointer(parent, (Attr) attributes.get(index));
    154     }
    155
    156     public int getPosition() {
    157         return position;
    158     }
    159
    160     public boolean setPosition(int position) {
    161         this.position = position;
    162         return position >= 1 && position <= attributes.size();
    163     }
    164 }