KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > tinytree > TinyElementImpl


1 package net.sf.saxon.tinytree;
2 import net.sf.saxon.event.Receiver;
3 import net.sf.saxon.om.NamespaceConstant;
4 import net.sf.saxon.om.NamespaceResolver;
5 import net.sf.saxon.om.Navigator;
6 import net.sf.saxon.om.NodeInfo;
7 import net.sf.saxon.style.StandardNames;
8 import net.sf.saxon.trans.XPathException;
9 import net.sf.saxon.type.Type;
10
11
12 /**
13   * A node in the XML parse tree representing an XML element.<P>
14   * This class is an implementation of NodeInfo. The object is a wrapper around
15   * one entry in the arrays maintained by the TinyTree. Note that the same node
16   * might be represented by different TinyElementImpl objects at different times.
17   * @author Michael H. Kay
18   */

19
20 final class TinyElementImpl extends TinyParentNodeImpl {
21
22     /**
23     * Constructor
24     */

25
26     public TinyElementImpl(TinyTree tree, int nodeNr) {
27         this.tree = tree;
28         this.nodeNr = nodeNr;
29     }
30
31     /**
32     * Return the type of node.
33     * @return Type.ELEMENT
34     */

35
36     public final int getNodeKind() {
37         return Type.ELEMENT;
38     }
39
40     /**
41     * Get the base URI of this element node. This will be the same as the System ID unless
42     * xml:base has been used.
43     */

44
45     public String JavaDoc getBaseURI() {
46         return Navigator.getBaseURI(this);
47     }
48
49     /**
50     * Get the type annotation of this node, if any
51     * Returns Type.UNTYPED_ANY if there is no type annotation
52     */

53
54     public int getTypeAnnotation() {
55         return tree.getTypeAnnotation(nodeNr);
56     }
57
58     /**
59     * Output all namespace nodes associated with this element.
60     * @param out The relevant outputter
61      * @param includeAncestors True if namespaces associated with ancestor
62      */

63
64     public void sendNamespaceDeclarations(Receiver out, boolean includeAncestors)
65                 throws XPathException {
66
67         if (!tree.usesNamespaces) {
68             return;
69         }
70
71         int ns = tree.beta[nodeNr]; // by convention
72
if (ns>0 ) {
73             while (ns < tree.numberOfNamespaces &&
74                     tree.namespaceParent[ns] == nodeNr ) {
75                 int nscode = tree.namespaceCode[ns];
76                 out.namespace(nscode, 0);
77                 ns++;
78             }
79         }
80
81         // now add the namespaces defined on the ancestor nodes. We rely on the receiver
82
// to eliminate multiple declarations of the same prefix
83

84         if (includeAncestors) {
85             NodeInfo parent = getParent();
86             if (parent != null) {
87                 parent.sendNamespaceDeclarations(out, true);
88             }
89             // terminates when the parent is a root node
90
}
91     }
92
93     /**
94      * Get all namespace undeclarations and undeclarations defined on this element.
95      *
96      * @param buffer If this is non-null, and the result array fits in this buffer, then the result
97      * may overwrite the contents of this array, to avoid the cost of allocating a new array on the heap.
98      * @return An array of integers representing the namespace declarations and undeclarations present on
99      * this element. For a node other than an element, return null. Otherwise, the returned array is a
100      * sequence of namespace codes, whose meaning may be interpreted by reference to the name pool. The
101      * top half word of each namespace code represents the prefix, the bottom half represents the URI.
102      * If the bottom half is zero, then this is a namespace undeclaration rather than a declaration.
103      * The XML namespace is never included in the list. If the supplied array is larger than required,
104      * then the first unused entry will be set to -1.
105      * <p/>
106      * <p>For a node other than an element, the method returns null.</p>
107      */

108
109     public int[] getDeclaredNamespaces(int[] buffer) {
110         return getDeclaredNamespaces(tree, nodeNr, buffer);
111     }
112
113     /**
114      * Static method to get all namespace undeclarations and undeclarations defined on a given element,
115      * without instantiating the node object.
116      * @param tree The tree containing the given element node
117      * @param nodeNr The node number of the given element node within the tinyTree
118      * @param buffer If this is non-null, and the result array fits in this buffer, then the result
119      * may overwrite the contents of this array, to avoid the cost of allocating a new array on the heap.
120      * @return An array of integers representing the namespace declarations and undeclarations present on
121      * this element. For a node other than an element, return null. Otherwise, the returned array is a
122      * sequence of namespace codes, whose meaning may be interpreted by reference to the name pool. The
123      * top half word of each namespace code represents the prefix, the bottom half represents the URI.
124      * If the bottom half is zero, then this is a namespace undeclaration rather than a declaration.
125      * The XML namespace is never included in the list. If the supplied array is larger than required,
126      * then the first unused entry will be set to -1.
127      * <p/>
128      * <p>For a node other than an element, the method returns null.</p>
129      */

130
131     static final int[] getDeclaredNamespaces(TinyTree tree, int nodeNr, int[] buffer) {
132         int ns = tree.beta[nodeNr]; // by convention
133
if (ns>0 ) {
134             int count = 0;
135             while (ns < tree.numberOfNamespaces &&
136                     tree.namespaceParent[ns] == nodeNr ) {
137                 count++;
138                 ns++;
139             }
140             if (count == 0) {
141                 return NodeInfo.EMPTY_NAMESPACE_LIST;
142             } else if (count <= buffer.length) {
143                 System.arraycopy(tree.namespaceCode, tree.beta[nodeNr], buffer, 0, count);
144                 if (count < buffer.length) {
145                     buffer[count] = -1;
146                 }
147                 return buffer;
148             } else {
149                 int[] array = new int[count];
150                 System.arraycopy(tree.namespaceCode, tree.beta[nodeNr], array, 0, count);
151                 return array;
152             }
153         } else {
154             return NodeInfo.EMPTY_NAMESPACE_LIST;
155         }
156     }
157
158     /**
159     * Get all the inscope namespaces for an element node. This method is better than the generic method
160      * provided by {@link net.sf.saxon.om.NamespaceIterator} because it doesn't require the element node
161      * (or its ancestors) to be instantiated as objects.
162      * @param tree the TinyTree containing the element node whose in-scope namespaces are required
163      * @param nodeNr the node number of the element node within the TinyTree. The caller is responsible
164      * for ensuring that this is indeed an element node
165      * @param buffer a buffer to hold the result, assuming it is large enough
166      * @return an integer array of namespace codes representing the inscope namespaces of the given element.
167      * The returned array will either be fully used, or it will contain a -1 entry marking the effective end
168      * of the list of namespace codes. Note that only distinct declared namespaces are included in the result;
169      * it does not contain any entries for namespace undeclarations or for overridden declarations.
170      */

171
172     static final int[] getInScopeNamespaces(TinyTree tree, int nodeNr, int[] buffer) {
173
174         if (buffer == null || buffer.length == 0) {
175             buffer = new int[10];
176         }
177         buffer[0] = NamespaceConstant.XML_NAMESPACE_CODE;
178         int used = 1;
179
180         if (tree.usesNamespaces) {
181             do {
182                 // gather the namespaces declared for this node
183
int ns = tree.beta[nodeNr]; // by convention
184
if (ns>0 ) {
185                     while (ns < tree.numberOfNamespaces &&
186                             tree.namespaceParent[ns] == nodeNr ) {
187                         int nscode = tree.namespaceCode[ns];
188
189                         // See if the prefix has already been declared; if so, this declaration is ignored
190
short prefixCode = (short)(nscode >> 16);
191                         boolean duplicate = false;
192                         for (int i=0; i<used; i++) {
193                             if ((buffer[i] >> 16) == prefixCode) {
194                                 duplicate = true;
195                                 break;
196                             }
197                         }
198                         if (!duplicate) {
199                             if (used >= buffer.length) {
200                                 int[] b2 = new int[used*2];
201                                 System.arraycopy(buffer, 0, b2, 0, used);
202                                 buffer = b2;
203                             }
204                             buffer[used++] = nscode;
205                         }
206                         ns++;
207                     }
208                 }
209
210                 // move on to the parent of this node
211
nodeNr = getParentNodeNr(tree, nodeNr);
212             } while (nodeNr != -1);
213
214             // The list of namespaces we have built up includes undeclarations as well as declarations.
215
// We now remove the undeclarations (which have a URI code of zero)
216

217             int j = 0;
218             for (int i=0; i<used; i++) {
219                 int nscode = buffer[i];
220                 if ((nscode & 0xffff) != 0) {
221                     buffer[j++] = nscode;
222                 }
223             }
224             used = j;
225         }
226
227         // If there are unused entries at the end of the array, add a -1 to mark the end
228
if (used < buffer.length) {
229             buffer[used] = -1;
230         }
231
232         return buffer;
233     }
234
235
236     /**
237     * Get the value of a given attribute of this node
238     * @param fingerprint The fingerprint of the attribute name
239     * @return the attribute value if it exists or null if not
240     */

241
242     public String JavaDoc getAttributeValue(int fingerprint) {
243         int a = tree.alpha[nodeNr];
244         if (a<0) return null;
245         while (a < tree.numberOfAttributes && tree.attParent[a] == nodeNr) {
246             if ((tree.attCode[a] & 0xfffff) == fingerprint ) {
247                 return tree.attValue[a].toString();
248             }
249             a++;
250         }
251         return null;
252     }
253
254     /**
255     * Copy this node to a given receiver
256     * @param whichNamespaces indicates which namespaces should be copied: all, none,
257     * or local (i.e., those not declared on a parent element)
258     */

259
260     public void copy(Receiver receiver, int whichNamespaces, boolean copyAnnotations, int locationId) throws XPathException {
261
262         // Based on an algorithm supplied by Ruud Diterwich
263

264         // Performance measurements show that this achieves no speed-up over the OLD version
265
// (in 7.4). So might as well switch back.
266

267         // control vars
268
short level = -1;
269         boolean closePending = false;
270         short startLevel = tree.depth[nodeNr];
271         boolean first = true;
272         int next = nodeNr;
273
274         // document.diagnosticDump();
275

276         do {
277
278             // determine node depth
279
short nodeLevel = tree.depth[next];
280
281             // extra close required?
282
if (closePending) {
283                 level++;
284             }
285
286             // close former elements
287
for (; level > nodeLevel; level--) {
288                 receiver.endElement();
289             }
290
291             // new node level
292
level = nodeLevel;
293
294             // output depends on node type
295
switch (tree.nodeKind[next]) {
296                 case Type.ELEMENT : {
297
298                     // start element
299
receiver.startElement(tree.nameCode[next],
300                                             (copyAnnotations ? tree.getTypeAnnotation(next): StandardNames.XDT_UNTYPED),
301                             locationId, 0);
302                                             //(first ? ReceiverOptions.DISINHERIT_NAMESPACES : 0));
303

304                     // there is an element to close
305
closePending = true;
306
307                     // output namespaces
308
if (whichNamespaces != NO_NAMESPACES && tree.usesNamespaces) {
309                         if (first) {
310                             sendNamespaceDeclarations(receiver, whichNamespaces==ALL_NAMESPACES);
311                         } else {
312                             int ns = tree.beta[next]; // by convention
313
if (ns>0 ) {
314                                 while (ns < tree.numberOfNamespaces &&
315                                         tree.namespaceParent[ns] == next ) {
316                                     int nscode = tree.namespaceCode[ns];
317                                     receiver.namespace(nscode, 0);
318                                     ns++;
319                                 }
320                             }
321                         }
322                     }
323                     first = false;
324
325                     // output attributes
326

327                     int att = tree.alpha[next];
328                     if (att >= 0) {
329                         while (att < tree.numberOfAttributes && tree.attParent[att] == next ) {
330                             int attCode = tree.attCode[att];
331                             int attType = (copyAnnotations ? tree.getAttributeAnnotation(att) : -1);
332                             receiver.attribute(attCode, attType, tree.attValue[att], locationId, 0);
333                             att++;
334                         }
335                     }
336
337                     // start content
338
receiver.startContent();
339                     break;
340                 }
341                 case Type.TEXT : {
342
343                     // don't close text nodes
344
closePending = false;
345
346                     // output characters
347
int start = tree.alpha[next];
348                     int len = tree.beta[next];
349                     receiver.characters(new CharSlice(tree.charBuffer, start, len), locationId, 0);
350                     break;
351                 }
352                 case Type.COMMENT : {
353
354                     // don't close text nodes
355
closePending = false;
356
357                     // output copy of comment
358
int start = tree.alpha[next];
359                     int len = tree.beta[next];
360                     if (len>0) {
361                         receiver.comment(tree.commentBuffer.subSequence(start, start+len), locationId, 0);
362                     } else {
363                         receiver.comment("", 0, 0);
364                     }
365                     break;
366                 }
367                 case Type.PROCESSING_INSTRUCTION : {
368
369                     // don't close text nodes
370
closePending = false;
371
372                     // output copy of PI
373
NodeInfo pi = tree.getNode(next);
374                     receiver.processingInstruction(pi.getLocalPart(), pi.getStringValue(), locationId, 0);
375                     break;
376                 }
377
378                 case Type.PARENT_POINTER : {
379                     closePending = false;
380                 }
381             }
382
383             next++;
384
385         } while (next < tree.numberOfNodes && tree.depth[next] > startLevel);
386
387         // close all remaining elements
388
if (closePending) {
389             level++;
390         }
391         for (; level > startLevel; level--) {
392             receiver.endElement();
393         }
394     }
395
396 // public void copyOLD(Receiver out, int whichNamespaces, boolean copyAnnotations) throws XPathException {
397
//
398
// int nc = getNameCode();
399
// int typeCode = (copyAnnotations ? getTypeAnnotation() : 0);
400
// out.startElement(nc, typeCode, 0, 0);
401
//
402
// // output the namespaces
403
//
404
// if (whichNamespaces != NO_NAMESPACES) {
405
// outputNamespaceNodes(out, whichNamespaces==ALL_NAMESPACES);
406
// }
407
//
408
// // output the attributes
409
//
410
// int a = document.alpha[nodeNr];
411
// if (a >= 0) {
412
// while (a < document.numberOfAttributes && document.attParent[a] == nodeNr) {
413
// document.getAttributeNode(a).copy(out, NO_NAMESPACES, copyAnnotations, locationId);
414
// a++;
415
// }
416
// }
417
//
418
// // output the children
419
//
420
// AxisIterator children =
421
// iterateAxis(Axis.CHILD, AnyNodeTest.getInstance());
422
//
423
// int childNamespaces = (whichNamespaces==NO_NAMESPACES ? NO_NAMESPACES : LOCAL_NAMESPACES);
424
// while (true) {
425
// NodeInfo next = (NodeInfo)children.next();
426
// if (next==null) break;
427
// next.copy(out, childNamespaces, copyAnnotations, locationId);
428
// }
429
// out.endElement();
430
// }
431

432
433
434     /**
435      * Get the namespace URI corresponding to a given prefix. Return null
436      * if the prefix is not in scope.
437      *
438      * @param prefix the namespace prefix. May be the zero-length string, indicating
439      * that there is no prefix. This indicates either the default namespace or the
440      * null namespace, depending on the value of useDefault.
441      * @param useDefault true if the default namespace is to be used when the
442      * prefix is "". If false, the method returns "" when the prefix is "".
443      * @return the uri for the namespace, or null if the prefix is not in scope.
444      * The "null namespace" is represented by the pseudo-URI "".
445      */

446
447     public String JavaDoc getURIForPrefix(String JavaDoc prefix, boolean useDefault) {
448         if (!useDefault && "".equals(prefix)) {
449             return "";
450         }
451         int prefixCode = getNamePool().getCodeForPrefix(prefix);
452         if (prefixCode == -1) {
453             return null;
454         }
455         int ns = tree.beta[nodeNr]; // by convention
456
if (ns>0 ) {
457             while (ns < tree.numberOfNamespaces &&
458                     tree.namespaceParent[ns] == nodeNr ) {
459                 int nscode = tree.namespaceCode[ns];
460                 if ((nscode >> 16) == prefixCode) {
461                     int uriCode = nscode & 0xffff;
462                     if (uriCode == 0) {
463                         // this is a namespace undeclaration, so the prefix is not in scope
464
if (prefixCode == 0) {
465                             // the namespace xmlns="" is always in scope
466
return "";
467                         } else {
468                             return null;
469                         }
470                     } else {
471                         return getNamePool().getURIFromURICode((short)uriCode);
472                     }
473                 }
474                 ns++;
475             }
476         }
477
478         // now search the namespaces defined on the ancestor nodes.
479

480         NodeInfo parent = getParent();
481         if (parent instanceof NamespaceResolver) {
482             return ((NamespaceResolver)parent).getURIForPrefix(prefix, useDefault);
483         }
484         return null;
485     }
486
487 }
488
489 //
490
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
491
// you may not use this file except in compliance with the License. You may obtain a copy of the
492
// License at http://www.mozilla.org/MPL/
493
//
494
// Software distributed under the License is distributed on an "AS IS" basis,
495
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
496
// See the License for the specific language governing rights and limitations under the License.
497
//
498
// The Original Code is: all this file.
499
//
500
// The Initial Developer of the Original Code is Michael H. Kay.
501
//
502
// The new copy() routine (in version 7.4.1) is contributed by Ruud Diterwich
503
//
504
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
505
//
506
// Contributor(s): none.
507
//
508
Popular Tags