KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > icl > saxon > tree > ElementWithAttributes


1 package com.icl.saxon.tree;
2 import com.icl.saxon.om.NamePool;
3 import com.icl.saxon.om.NodeInfo;
4 import com.icl.saxon.om.NamespaceException;
5 import com.icl.saxon.om.Namespace;
6 import com.icl.saxon.om.DocumentInfo;
7 //import com.icl.saxon.expr.*;
8
import com.icl.saxon.output.Outputter;
9
10 import java.util.Vector JavaDoc;
11 import org.w3c.dom.Node JavaDoc;
12 import org.w3c.dom.Element JavaDoc;
13 import org.w3c.dom.Attr JavaDoc;
14 import org.w3c.dom.NamedNodeMap JavaDoc;
15 import org.w3c.dom.DOMException JavaDoc;
16 import javax.xml.transform.TransformerException JavaDoc;
17
18 /**
19   * A node in the XML parse tree representing an XML element.<P>
20   * This class is an implementation of NodeInfo
21   * @author <A HREF="mailto:mhkay@iclway.co.uk>Michael H. Kay</A>
22   * @version 8 August 2000: separated from ElementImpl
23   */

24
25 // The name of the element and its attributes are now namespace-resolved by the
26
// parser. However, this class retains the ability to do namespace resolution for other
27
// names, for example variable and template names in a stylesheet.
28

29 public class ElementWithAttributes extends ElementImpl
30     implements Element JavaDoc, NamedNodeMap JavaDoc {
31
32     protected AttributeCollection attributeList; // this excludes namespace attributes
33
protected int[] namespaceList = null; // list of namespace codes
34
// note that this namespace list includes only the namespaces actually defined on
35
// this element, not those inherited from outer elements.
36

37
38     /**
39     * Initialise a new ElementWithAttributes with an element name and attribute list
40     * @param name The element name, with namespaces resolved
41     * @param atts The attribute list, after namespace processing
42     * @param parent The parent node
43     */

44
45     public void initialise(int nameCode, AttributeCollection atts, NodeInfo parent,
46                             String JavaDoc baseURI, int lineNumber, int sequenceNumber) {
47         this.nameCode = nameCode;
48         this.attributeList = atts;
49         this.parent = (ParentNodeImpl)parent;
50         this.sequence = sequenceNumber;
51         this.root = (DocumentImpl)parent.getDocumentRoot();
52         root.setLineNumber(sequenceNumber, lineNumber);
53         root.setSystemId(sequenceNumber, baseURI);
54     }
55
56     /**
57     * Set the namespace declarations for the element
58     */

59
60     public void setNamespaceDeclarations(int[] namespaces, int namespacesUsed) {
61         namespaceList = new int[namespacesUsed];
62         System.arraycopy(namespaces, 0, namespaceList, 0, namespacesUsed);
63     }
64
65
66     /**
67     * Search the NamespaceList for a given prefix, returning the corresponding URI.
68     * @param prefix The prefix to be matched. To find the default namespace, supply ""
69     * @return The URI code corresponding to this namespace. If it is an unnamed default namespace,
70     * return Namespace.NULL_CODE.
71     * @throws NamespaceException if the prefix has not been declared on this NamespaceList.
72     */

73
74     public short getURICodeForPrefix(String JavaDoc prefix) throws NamespaceException {
75         if (prefix.equals("xml")) return Namespace.XML_CODE;
76
77         NamePool pool = getNamePool();
78         int prefixCode = pool.getCodeForPrefix(prefix);
79         if (prefixCode==-1) {
80             throw new NamespaceException(prefix);
81         }
82         return getURICodeForPrefixCode(prefixCode);
83     }
84     
85     private short getURICodeForPrefixCode(int prefixCode) throws NamespaceException {
86         if (namespaceList!=null) {
87             for (int i=0; i<namespaceList.length; i++) {
88                 if ((namespaceList[i]>>16) == prefixCode) {
89                     return (short)(namespaceList[i] & 0xffff);
90                 }
91             }
92         }
93         NodeImpl next = parent;
94         while (true) {
95             if (next.getNodeType()==NodeInfo.ROOT) {
96                 // prefixCode==0 represents the empty namespace prefix ""
97
if (prefixCode==0) return Namespace.NULL_CODE;
98                 throw new NamespaceException(getNamePool().getPrefixFromNamespaceCode(prefixCode<<16));
99             } else if (next instanceof ElementWithAttributes) {
100                 return ((ElementWithAttributes)next).getURICodeForPrefixCode(prefixCode);
101             } else {
102                 next = (NodeImpl)next.getParentNode();
103             }
104         }
105     }
106
107     /**
108     * Search the NamespaceList for a given URI, returning the corresponding prefix.
109     * @param uri The URI to be matched.
110     * @return The prefix corresponding to this URI. If not found, return null. If there is
111     * more than one prefix matching the URI, the first one found is returned. If the URI matches
112     * the default namespace, return an empty string.
113     */

114
115     public String JavaDoc getPrefixForURI(String JavaDoc uri) {
116         if (uri.equals(Namespace.XML)) return "xml";
117
118         NamePool pool = getNamePool();
119         int uriCode = pool.getCodeForURI(uri);
120         if (uriCode<0) return null;
121         return getPrefixForURICode(uriCode);
122     }
123
124     private String JavaDoc getPrefixForURICode(int code) {
125         if (namespaceList!=null) {
126             for (int i=0; i<namespaceList.length; i++) {
127                 if ((namespaceList[i] & 0xffff) == code) {
128                     return getNamePool().getPrefixFromNamespaceCode(namespaceList[i]);
129                 }
130             }
131         }
132         NodeImpl next = parent;
133         while (true) {
134             if (next instanceof DocumentInfo) {
135                 return null;
136             } else if (next instanceof ElementWithAttributes) {
137                 return ((ElementWithAttributes)next).getPrefixForURICode(code);
138             } else {
139                 next = (NodeImpl)next.getParentNode();
140             }
141         }
142     }
143
144     /**
145     * Make the set of all namespace nodes associated with this element.
146     * @param owner The element owning these namespace nodes.
147     * @param list a Vector containing NamespaceImpl objects representing the namespaces
148     * in scope for this element; the method appends nodes to this Vector, which should
149     * initially be empty. Note that the returned list will never contain the XML namespace
150     * (to get this, the NamespaceEnumeration class adds it itself). The list WILL include
151     * an entry for the undeclaration xmlns=""; again it is the job of NamespaceEnumeration
152     * to ignore this, since it doesn't represent a true namespace node.
153     * @param addXML Add a namespace node for the XML namespace
154     */

155
156     public void addNamespaceNodes(ElementImpl owner, Vector JavaDoc list, boolean addXML) {
157         if (namespaceList!=null) {
158             int max = list.size();
159             for (int i=0; i<namespaceList.length; i++) {
160                 int nscode = namespaceList[i];
161                 int prefixCode = nscode>>16;
162
163                 boolean found = false;
164
165                 // Don't add a node if the prefix is already in the list
166
for (int j=0; j<max; ) {
167                     NamespaceImpl ns = (NamespaceImpl)list.elementAt(j++);
168                     if (ns.getNamespaceCode() == prefixCode) {
169                         found=true;
170                         break;
171                     }
172                 }
173                 if (!found) {
174                     list.addElement(
175                         new NamespaceImpl(
176                             (ElementImpl)owner, nscode, list.size()+1));
177                 }
178             }
179         }
180
181         // now add the namespaces defined on the ancestor nodes
182

183         if (parent.getNodeType()!=NodeInfo.ROOT) {
184             ((ElementImpl)parent).addNamespaceNodes(owner, list, false);
185         }
186
187         if (addXML) {
188             int nsxml = (1<<16) + 1;
189             list.addElement(
190                 new NamespaceImpl(this, nsxml, list.size()+1)
191                 );
192         }
193     }
194     
195     /**
196     * Output all namespace nodes associated with this element.
197     * @param out The relevant outputter
198     */

199
200     public void outputNamespaceNodes(Outputter out, boolean includeAncestors) throws TransformerException JavaDoc {
201
202         if (namespaceList!=null) {
203             for (int i=0; i<namespaceList.length; i++) {
204                 out.writeNamespaceDeclaration(namespaceList[i]);
205             }
206         }
207
208         // now add the namespaces defined on the ancestor nodes. We rely on the outputter
209
// to eliminate multiple declarations of the same prefix
210

211         if (includeAncestors) {
212             if (parent.getNodeType()!=NodeInfo.ROOT) {
213                 ((ElementImpl)parent).outputNamespaceNodes(out, true);
214             }
215         }
216     }
217
218     /**
219     * Get the list of in-scope namespaces for this element as an array of
220     * namespace codes. (Used by LiteralResultElement)
221     */

222
223     protected int[] getNamespaceCodes() {
224         Vector JavaDoc namespaceNodes = new Vector JavaDoc();
225         addNamespaceNodes(this, namespaceNodes, true);
226
227         // copy to the namespace code list
228
int[] namespaceCodes = new int[namespaceNodes.size()];
229         for (int i=0; i<namespaceNodes.size(); i++) {
230             NamespaceImpl nsi = (NamespaceImpl)namespaceNodes.elementAt(i);
231             namespaceCodes[i] = nsi.getNamespaceCode();
232         }
233         return namespaceCodes;
234     }
235     
236     /**
237     * Get the attribute list for this element.
238     * @return The attribute list. This will not include any
239     * namespace attributes. The attribute names will be in expanded form, with prefixes
240     * replaced by URIs
241     */

242     
243     public AttributeCollection getAttributeList() {
244         return attributeList;
245     }
246
247     /**
248      * Returns whether this node (if it is an element) has any attributes.
249      * @return <code>true</code> if this node has any attributes,
250      * <code>false</code> otherwise.
251      * @since DOM Level 2
252      */

253     
254     public boolean hasAttributes() {
255         return attributeList.getLength() > 0;
256     }
257     
258     /**
259      * Find the value of a given attribute of this node. <BR>
260      * This method is defined on all nodes to meet XSL requirements, but for nodes
261      * other than elements it will always return null.
262      * @param uri the namespace uri of an attribute
263      * @param localName the local name of an attribute
264      * @return the value of the attribute, if it exists, otherwise null
265      */

266
267     public String JavaDoc getAttributeValue( String JavaDoc uri, String JavaDoc localName ) {
268         return attributeList.getValue(uri, localName);
269     }
270
271     /**
272      * Find the value of a given attribute of this element. <BR>
273      * This is a short-cut method; the full capability to examine
274      * attributes is offered via the getAttributeList() method. <BR>
275      * The attribute may either be one that was present in the original XML document,
276      * or one that has been set by the application using setAttribute(). <BR>
277      * @param name the name of an attribute. There must be no prefix in the name.
278      * @return the value of the attribute, if it exists, otherwise null
279      */

280
281     public String JavaDoc getAttributeValue( String JavaDoc name ) {
282         return attributeList.getValue(name);
283     }
284     
285     /**
286     * Get the value of a given attribute of this node
287     * @param fingerprint The fingerprint of the attribute name
288     * @return the attribute value if it exists or null if not
289     */

290     
291     public String JavaDoc getAttributeValue(int fingerprint) {
292         return attributeList.getValueByFingerprint(fingerprint);
293     }
294    
295     /**
296     * Set the value of an attribute on the current element. This affects subsequent calls
297     * of getAttribute() for that element.
298     * @param name The name of the attribute to be set. Any prefix is interpreted relative
299     * to the namespaces defined for this element.
300     * @param value The new value of the attribute. Set this to null to remove the attribute.
301     * @throws DOMException (always): Saxon trees are immutable.
302     */

303     
304     public void setAttribute(String JavaDoc name, String JavaDoc value ) throws DOMException JavaDoc {
305         disallowUpdate();
306     }
307
308     /**
309     * Copy this node to a given outputter (supporting xsl:copy-of)
310     * @param out The outputter
311     * @param allNamespaces true if namespaces for ancestor nodes must be output
312     */

313
314     public void copy(Outputter out, boolean allNamespaces) throws TransformerException JavaDoc {
315         int nc = getNameCode();
316         out.writeStartTag(nc);
317
318         // output the namespaces
319

320         outputNamespaceNodes(out, allNamespaces);
321
322         // output the attributes
323

324         for (int i=0; i<attributeList.getLength(); i++) {
325             out.writeAttribute(attributeList.getNameCode(i),
326                                attributeList.getValue(i));
327         }
328
329         // output the children
330

331         NodeImpl next = (NodeImpl)getFirstChild();
332         while (next!=null) {
333             if (next instanceof ElementImpl) {
334                 ((ElementImpl)next).copy(out, false);
335             } else {
336                 next.copy(out);
337             }
338             next = (NodeImpl)next.getNextSibling();
339         }
340
341         out.writeEndTag(nc);
342     }
343
344     ////////////////////////////////////////////////////////////////////////////
345
// Following interfaces are provided to implement the DOM Element interface
346
////////////////////////////////////////////////////////////////////////////
347

348
349     /**
350      * Retrieves an attribute value by name. Namespace declarations are not
351      * returned.
352      * @param name The name of the attribute to retrieve.
353      * @return The <code>Attr</code> value as a string, or the empty string if
354      * that attribute does not have a specified or default value. (Note the
355      * difference from getAttributeValue(), which returns null if there is no
356      * value).
357      */

358      
359     public String JavaDoc getAttribute(String JavaDoc name) {
360         int index = attributeList.getIndex(name);
361         if (index<0) return "";
362         return attributeList.getValue(index);
363     }
364
365     /**
366      * A <code>NamedNodeMap</code> containing the attributes of this element. This
367      * is a DOM method, so the list of attributes includes namespace declarations.
368      */

369      
370     public NamedNodeMap JavaDoc getAttributes() {
371         return this;
372     }
373
374     /**
375      * Removes an attribute by name.
376      * @param name The name of the attribute to remove.
377      */

378      
379     public void removeAttribute(String JavaDoc name) {
380         setAttribute(name, null);
381     }
382     
383     /**
384      * Retrieves an attribute node by name. Namespace declarations are not
385      * returned.
386      * <br> To retrieve an attribute node by qualified name and namespace URI,
387      * use the <code>getAttributeNodeNS</code> method.
388      * @param name The name (<code>nodeName</code> ) of the attribute to
389      * retrieve.
390      * @return The <code>Attr</code> node with the specified name (
391      * <code>nodeName</code> ) or <code>null</code> if there is no such
392      * attribute.
393      */

394      
395     public Attr JavaDoc getAttributeNode(String JavaDoc name) {
396         int index = getAttributeList().getIndex(name);
397         if (index<0) {
398             return null;
399         }
400         return new AttributeImpl(this, index);
401     }
402
403     /**
404      * Adds a new attribute node. Always fails
405      * @exception DOMException
406      * NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
407      */

408      
409     public Attr JavaDoc setAttributeNode(Attr JavaDoc newAttr) throws DOMException JavaDoc {
410         disallowUpdate();
411         return null;
412     }
413
414     /**
415      * Removes the specified attribute node. Always fails
416      * @exception DOMException
417      * NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
418      */

419
420     public Attr JavaDoc removeAttributeNode(Attr JavaDoc oldAttr) throws DOMException JavaDoc {
421         disallowUpdate();
422         return null;
423     }
424
425     /**
426      * Retrieves an attribute value by local name and namespace URI.
427      * HTML-only DOM implementations do not need to implement this method.
428      * @param namespaceURI The namespace URI of the attribute to retrieve.
429      * @param localName The local name of the attribute to retrieve.
430      * @return The <code>Attr</code> value as a string, or the empty string if
431      * that attribute does not have a specified or default value.
432      * @since DOM Level 2
433      */

434      
435     public String JavaDoc getAttributeNS(String JavaDoc namespaceURI, String JavaDoc localName) {
436         String JavaDoc value = getAttributeValue(namespaceURI, localName);
437         return (value==null ? "" : value);
438     }
439
440     /**
441      * Adds a new attribute. Always fails.
442      * @param namespaceURI The namespace URI of the attribute to create or
443      * alter.
444      * @param qualifiedName The qualified name of the attribute to create or
445      * alter.
446      * @param value The value to set in string form.
447      * @exception DOMException
448      * NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
449      */

450      
451     public void setAttributeNS(String JavaDoc namespaceURI,
452                                String JavaDoc qualifiedName,
453                                String JavaDoc value)
454                                throws DOMException JavaDoc {
455         disallowUpdate();
456     }
457
458     /**
459      * Removes an attribute by local name and namespace URI. Always fails
460      * @exception DOMException
461      * NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
462      * @since DOM Level 2
463      */

464      
465     public void removeAttributeNS(String JavaDoc namespaceURI,
466                                   String JavaDoc localName)
467                                   throws DOMException JavaDoc{
468         disallowUpdate();
469     }
470     
471     /**
472      * Retrieves an <code>Attr</code> node by local name and namespace URI.
473      * DOM method, so namespace declarations count as attributes.
474      * @param namespaceURI The namespace URI of the attribute to retrieve.
475      * @param localName The local name of the attribute to retrieve.
476      * @return The <code>Attr</code> node with the specified attribute local
477      * name and namespace URI or <code>null</code> if there is no such
478      * attribute.
479      * @since DOM Level 2
480      */

481      
482     public Attr JavaDoc getAttributeNodeNS(String JavaDoc namespaceURI, String JavaDoc localName) {
483         int index = attributeList.getIndex(namespaceURI, localName);
484         if (index<0) return null;
485         return new AttributeImpl(this, index);
486     }
487
488     /**
489      * Add a new attribute. Always fails.
490      * @param newAttr The <code>Attr</code> node to add to the attribute list.
491      * @return If the <code>newAttr</code> attribute replaces an existing
492      * attribute with the same local name and namespace URI , the
493      * replaced <code>Attr</code> node is returned, otherwise
494      * <code>null</code> is returned.
495      * @exception DOMException
496      * <br> NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
497      * @since DOM Level 2
498      */

499      
500     public Attr JavaDoc setAttributeNodeNS(Attr JavaDoc newAttr)
501                                    throws DOMException JavaDoc{
502         disallowUpdate();
503         return null;
504     }
505
506     /**
507      * Returns <code>true</code> when an attribute with a given name is
508      * specified on this element or has a default value, <code>false</code>
509      * otherwise. Namespace declarations are not included.
510      * @param name The name of the attribute to look for.
511      * @return <code>true</code> if an attribute with the given name is
512      * specified on this element or has a default value, <code>false</code>
513      * otherwise.
514      * @since DOM Level 2
515      */

516      
517     public boolean hasAttribute(String JavaDoc name) {
518         return attributeList.getIndex(name) >= 0;
519     }
520
521     /**
522      * Returns <code>true</code> when an attribute with a given local name
523      * and namespace URI is specified on this element or has a default value,
524      * <code>false</code> otherwise. This is a DOM method so namespace declarations
525      * are treated as attributes.
526      * @param namespaceURI The namespace URI of the attribute to look for.
527      * @param localName The local name of the attribute to look for.
528      * @return <code>true</code> if an attribute with the given local name and
529      * namespace URI is specified or has a default value on this element,
530      * <code>false</code> otherwise.
531      * @since DOM Level 2
532      */

533      
534     public boolean hasAttributeNS(String JavaDoc namespaceURI, String JavaDoc localName) {
535         return (getAttributeValue(namespaceURI, localName) != null);
536     }
537
538     //////////////////////////////////////////////////////////////////////
539
// Methods to implement DOM NamedNodeMap (the set of attributes)
540
//////////////////////////////////////////////////////////////////////
541

542     /**
543     * Get named attribute (DOM NamedNodeMap method)
544     * Treats namespace declarations as attributes.
545     */

546
547     public Node JavaDoc getNamedItem(String JavaDoc name) {
548         return getAttributeNode(name);
549     }
550
551     /**
552     * Set named attribute (DOM NamedNodeMap method: always fails)
553     */

554
555     public Node JavaDoc setNamedItem(Node JavaDoc arg) throws DOMException JavaDoc {
556         disallowUpdate();
557         return null;
558     }
559
560     /**
561     * Remove named attribute (DOM NamedNodeMap method: always fails)
562     */

563
564     public Node JavaDoc removeNamedItem(String JavaDoc name) throws DOMException JavaDoc {
565         disallowUpdate();
566         return null;
567     }
568
569     /**
570     * Get n'th attribute (DOM NamedNodeMap method). Namespace declarations are
571     * not returned.
572     */

573
574     public Node JavaDoc item(int index) {
575         if (index<0 || index>=attributeList.getLength()) {
576             return null;
577         }
578         return new AttributeImpl(this, index);
579     }
580
581     /**
582     * Get number of attributes (DOM NamedNodeMap method).
583     * Treats namespace declarations as attributes.
584     */

585
586     public int getLength() {
587         return attributeList.getLength();
588     }
589
590     /**
591     * Get named attribute (DOM NamedNodeMap method)
592     * Treats namespace declarations as attributes.
593     */

594
595     public Node JavaDoc getNamedItemNS(String JavaDoc uri, String JavaDoc localName) {
596         return getAttributeNodeNS(uri, localName);
597     }
598
599     /**
600     * Set named attribute (DOM NamedNodeMap method: always fails)
601     */

602
603     public Node JavaDoc setNamedItemNS(Node JavaDoc arg) throws DOMException JavaDoc {
604         disallowUpdate();
605         return null;
606     }
607
608     /**
609     * Remove named attribute (DOM NamedNodeMap method: always fails)
610     */

611
612     public Node JavaDoc removeNamedItemNS(String JavaDoc uri, String JavaDoc localName) throws DOMException JavaDoc {
613         disallowUpdate();
614         return null;
615     }
616         
617 }
618
619 //
620
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
621
// you may not use this file except in compliance with the License. You may obtain a copy of the
622
// License at http://www.mozilla.org/MPL/
623
//
624
// Software distributed under the License is distributed on an "AS IS" basis,
625
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
626
// See the License for the specific language governing rights and limitations under the License.
627
//
628
// The Original Code is: all this file.
629
//
630
// The Initial Developer of the Original Code is
631
// Michael Kay of International Computers Limited (mhkay@iclway.co.uk).
632
//
633
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
634
//
635
// Contributor(s): none.
636
//
637
Popular Tags