001: /*
002: * Copyright 1999-2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: /*
017: * $Id: DTMNamedNodeMap.java,v 1.11 2005/01/24 00:34:35 mcnamara Exp $
018: */
019: package org.apache.xml.dtm.ref;
020:
021: import org.apache.xml.dtm.DTM;
022:
023: import org.w3c.dom.DOMException;
024: import org.w3c.dom.NamedNodeMap;
025: import org.w3c.dom.Node;
026:
027: /**
028: * DTMNamedNodeMap is a quickie (as opposed to quick) implementation of the DOM's
029: * NamedNodeMap interface, intended to support DTMProxy's getAttributes()
030: * call.
031: * <p>
032: * ***** Note: this does _not_ current attempt to cache any of the data;
033: * if you ask for attribute 27 and then 28, you'll have to rescan the first
034: * 27. It should probably at least keep track of the last one retrieved,
035: * and possibly buffer the whole array.
036: * <p>
037: * ***** Also note that there's no fastpath for the by-name query; we search
038: * linearly until we find it or fail to find it. Again, that could be
039: * optimized at some cost in object creation/storage.
040: * @xsl.usage internal
041: */
042: public class DTMNamedNodeMap implements NamedNodeMap {
043:
044: /** The DTM for this node. */
045: DTM dtm;
046:
047: /** The DTM element handle. */
048: int element;
049:
050: /** The number of nodes in this map. */
051: short m_count = -1;
052:
053: /**
054: * Create a getAttributes NamedNodeMap for a given DTM element node
055: *
056: * @param dtm The DTM Reference, must be non-null.
057: * @param element The DTM element handle.
058: */
059: public DTMNamedNodeMap(DTM dtm, int element) {
060: this .dtm = dtm;
061: this .element = element;
062: }
063:
064: /**
065: * Return the number of Attributes on this Element
066: *
067: * @return The number of nodes in this map.
068: */
069: public int getLength() {
070:
071: if (m_count == -1) {
072: short count = 0;
073:
074: for (int n = dtm.getFirstAttribute(element); n != -1; n = dtm
075: .getNextAttribute(n)) {
076: ++count;
077: }
078:
079: m_count = count;
080: }
081:
082: return (int) m_count;
083: }
084:
085: /**
086: * Retrieves a node specified by name.
087: * @param name The <code>nodeName</code> of a node to retrieve.
088: * @return A <code>Node</code> (of any type) with the specified
089: * <code>nodeName</code>, or <code>null</code> if it does not identify
090: * any node in this map.
091: */
092: public Node getNamedItem(String name) {
093:
094: for (int n = dtm.getFirstAttribute(element); n != DTM.NULL; n = dtm
095: .getNextAttribute(n)) {
096: if (dtm.getNodeName(n).equals(name))
097: return dtm.getNode(n);
098: }
099:
100: return null;
101: }
102:
103: /**
104: * Returns the <code>index</code>th item in the map. If <code>index</code>
105: * is greater than or equal to the number of nodes in this map, this
106: * returns <code>null</code>.
107: * @param i The index of the requested item.
108: * @return The node at the <code>index</code>th position in the map, or
109: * <code>null</code> if that is not a valid index.
110: */
111: public Node item(int i) {
112:
113: int count = 0;
114:
115: for (int n = dtm.getFirstAttribute(element); n != -1; n = dtm
116: .getNextAttribute(n)) {
117: if (count == i)
118: return dtm.getNode(n);
119: else
120: ++count;
121: }
122:
123: return null;
124: }
125:
126: /**
127: * Adds a node using its <code>nodeName</code> attribute. If a node with
128: * that name is already present in this map, it is replaced by the new
129: * one.
130: * <br>As the <code>nodeName</code> attribute is used to derive the name
131: * which the node must be stored under, multiple nodes of certain types
132: * (those that have a "special" string value) cannot be stored as the
133: * names would clash. This is seen as preferable to allowing nodes to be
134: * aliased.
135: * @param newNode node to store in this map. The node will later be
136: * accessible using the value of its <code>nodeName</code> attribute.
137: *
138: * @return If the new <code>Node</code> replaces an existing node the
139: * replaced <code>Node</code> is returned, otherwise <code>null</code>
140: * is returned.
141: * @exception DOMException
142: * WRONG_DOCUMENT_ERR: Raised if <code>arg</code> was created from a
143: * different document than the one that created this map.
144: * <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this map is readonly.
145: * <br>INUSE_ATTRIBUTE_ERR: Raised if <code>arg</code> is an
146: * <code>Attr</code> that is already an attribute of another
147: * <code>Element</code> object. The DOM user must explicitly clone
148: * <code>Attr</code> nodes to re-use them in other elements.
149: */
150: public Node setNamedItem(Node newNode) {
151: throw new DTMException(DTMException.NO_MODIFICATION_ALLOWED_ERR);
152: }
153:
154: /**
155: * Removes a node specified by name. When this map contains the attributes
156: * attached to an element, if the removed attribute is known to have a
157: * default value, an attribute immediately appears containing the
158: * default value as well as the corresponding namespace URI, local name,
159: * and prefix when applicable.
160: * @param name The <code>nodeName</code> of the node to remove.
161: *
162: * @return The node removed from this map if a node with such a name
163: * exists.
164: * @exception DOMException
165: * NOT_FOUND_ERR: Raised if there is no node named <code>name</code> in
166: * this map.
167: * <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this map is readonly.
168: */
169: public Node removeNamedItem(String name) {
170: throw new DTMException(DTMException.NO_MODIFICATION_ALLOWED_ERR);
171: }
172:
173: /**
174: * Retrieves a node specified by local name and namespace URI. HTML-only
175: * DOM implementations do not need to implement this method.
176: * @param namespaceURI The namespace URI of the node to retrieve.
177: * @param localName The local name of the node to retrieve.
178: *
179: * @return A <code>Node</code> (of any type) with the specified local
180: * name and namespace URI, or <code>null</code> if they do not
181: * identify any node in this map.
182: * @since DOM Level 2
183: */
184: public Node getNamedItemNS(String namespaceURI, String localName) {
185: Node retNode = null;
186: for (int n = dtm.getFirstAttribute(element); n != DTM.NULL; n = dtm
187: .getNextAttribute(n)) {
188: if (localName.equals(dtm.getLocalName(n))) {
189: String nsURI = dtm.getNamespaceURI(n);
190: if ((namespaceURI == null && nsURI == null)
191: || (namespaceURI != null && namespaceURI
192: .equals(nsURI))) {
193: retNode = dtm.getNode(n);
194: break;
195: }
196: }
197: }
198: return retNode;
199: }
200:
201: /**
202: * Adds a node using its <code>namespaceURI</code> and
203: * <code>localName</code>. If a node with that namespace URI and that
204: * local name is already present in this map, it is replaced by the new
205: * one.
206: * <br>HTML-only DOM implementations do not need to implement this method.
207: * @param arg A node to store in this map. The node will later be
208: * accessible using the value of its <code>namespaceURI</code> and
209: * <code>localName</code> attributes.
210: *
211: * @return If the new <code>Node</code> replaces an existing node the
212: * replaced <code>Node</code> is returned, otherwise <code>null</code>
213: * is returned.
214: * @exception DOMException
215: * WRONG_DOCUMENT_ERR: Raised if <code>arg</code> was created from a
216: * different document than the one that created this map.
217: * <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this map is readonly.
218: * <br>INUSE_ATTRIBUTE_ERR: Raised if <code>arg</code> is an
219: * <code>Attr</code> that is already an attribute of another
220: * <code>Element</code> object. The DOM user must explicitly clone
221: * <code>Attr</code> nodes to re-use them in other elements.
222: * @since DOM Level 2
223: */
224: public Node setNamedItemNS(Node arg) throws DOMException {
225: throw new DTMException(DTMException.NO_MODIFICATION_ALLOWED_ERR);
226: }
227:
228: /**
229: * Removes a node specified by local name and namespace URI. A removed
230: * attribute may be known to have a default value when this map contains
231: * the attributes attached to an element, as returned by the attributes
232: * attribute of the <code>Node</code> interface. If so, an attribute
233: * immediately appears containing the default value as well as the
234: * corresponding namespace URI, local name, and prefix when applicable.
235: * <br>HTML-only DOM implementations do not need to implement this method.
236: *
237: * @param namespaceURI The namespace URI of the node to remove.
238: * @param localName The local name of the node to remove.
239: *
240: * @return The node removed from this map if a node with such a local
241: * name and namespace URI exists.
242: * @exception DOMException
243: * NOT_FOUND_ERR: Raised if there is no node with the specified
244: * <code>namespaceURI</code> and <code>localName</code> in this map.
245: * <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this map is readonly.
246: * @since DOM Level 2
247: */
248: public Node removeNamedItemNS(String namespaceURI, String localName)
249: throws DOMException {
250: throw new DTMException(DTMException.NO_MODIFICATION_ALLOWED_ERR);
251: }
252:
253: /**
254: * Simple implementation of DOMException.
255: * @xsl.usage internal
256: */
257: public class DTMException extends org.w3c.dom.DOMException {
258: static final long serialVersionUID = -8290238117162437678L;
259:
260: /**
261: * Constructs a DOM/DTM exception.
262: *
263: * @param code
264: * @param message
265: */
266: public DTMException(short code, String message) {
267: super (code, message);
268: }
269:
270: /**
271: * Constructor DTMException
272: *
273: *
274: * @param code
275: */
276: public DTMException(short code) {
277: super (code, "");
278: }
279: }
280: }
|