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 */ 017package org.apache.commons.jxpath.ri.model.dom; 018 019import java.util.ArrayList; 020import java.util.List; 021 022import org.apache.commons.jxpath.ri.QName; 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.Element; 027import org.w3c.dom.NamedNodeMap; 028import 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 19:46:46 +0200 (Fr, 02 Mai 2008) $ 035 */ 036public 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}