001: package net.sf.saxon.om;
002:
003: import net.sf.saxon.Configuration;
004: import net.sf.saxon.Err;
005: import net.sf.saxon.event.Receiver;
006: import net.sf.saxon.pattern.NodeTest;
007: import net.sf.saxon.trans.XPathException;
008: import net.sf.saxon.type.SchemaType;
009: import net.sf.saxon.type.Type;
010: import net.sf.saxon.value.UntypedAtomicValue;
011: import net.sf.saxon.value.Value;
012:
013: /**
014: * A node (implementing the NodeInfo interface) representing an attribute, text node,
015: * comment, processing instruction, or namespace that has no parent (and of course no children).
016: * Exceptionally it is also used (during whitespace stripping) to represent a standalone element.
017: * @author Michael H. Kay
018: */
019:
020: public final class Orphan implements NodeInfo, FingerprintedNode {
021:
022: private short kind;
023: private int nameCode = -1;
024: private CharSequence stringValue;
025: private int typeAnnotation = -1;
026: private Configuration config;
027: private String systemId;
028:
029: public Orphan(Configuration config) {
030: this .config = config;
031: }
032:
033: public void setNodeKind(short kind) {
034: this .kind = kind;
035: }
036:
037: public void setNameCode(int nameCode) {
038: this .nameCode = nameCode;
039: }
040:
041: public void setStringValue(CharSequence stringValue) {
042: this .stringValue = stringValue;
043: }
044:
045: public void setTypeAnnotation(int typeAnnotation) {
046: this .typeAnnotation = typeAnnotation;
047: }
048:
049: public void setSystemId(String systemId) {
050: this .systemId = systemId;
051: }
052:
053: /**
054: * Return the type of node.
055: * @return one of the values Node.ELEMENT, Node.TEXT, Node.ATTRIBUTE, etc.
056: */
057:
058: public int getNodeKind() {
059: return kind;
060: }
061:
062: /**
063: * Get the typed value of the item
064: */
065:
066: public SequenceIterator getTypedValue() throws XPathException {
067: if (typeAnnotation == -1) {
068: return SingletonIterator
069: .makeIterator(new UntypedAtomicValue(stringValue));
070: } else {
071: SchemaType stype = config.getSchemaType(typeAnnotation);
072: if (stype == null) {
073: String typeName = config.getNamePool().getDisplayName(
074: typeAnnotation);
075: throw new IllegalStateException(
076: "Unknown type annotation " + Err.wrap(typeName)
077: + " in standalone node");
078: } else {
079: return stype.getTypedValue(this );
080: }
081: }
082: }
083:
084: /**
085: * Get the typed value. The result of this method will always be consistent with the method
086: * {@link Item#getTypedValue()}. However, this method is often more convenient and may be
087: * more efficient, especially in the common case where the value is expected to be a singleton.
088: *
089: * @return the typed value. If requireSingleton is set to true, the result will always be an
090: * AtomicValue. In other cases it may be a Value representing a sequence whose items are atomic
091: * values.
092: * @since 8.5
093: */
094:
095: public Value atomize() throws XPathException {
096: if (typeAnnotation == -1) {
097: return new UntypedAtomicValue(stringValue);
098: } else {
099: SchemaType stype = config.getSchemaType(typeAnnotation);
100: if (stype == null) {
101: String typeName = config.getNamePool().getDisplayName(
102: typeAnnotation);
103: throw new IllegalStateException(
104: "Unknown type annotation " + Err.wrap(typeName)
105: + " in standalone node");
106: } else {
107: return stype.atomize(this );
108: }
109: }
110: }
111:
112: /**
113: * Get the configuration
114: */
115:
116: public Configuration getConfiguration() {
117: return config;
118: }
119:
120: /**
121: * Get the name pool
122: */
123:
124: public NamePool getNamePool() {
125: return config.getNamePool();
126: }
127:
128: /**
129: * Get the type annotation
130: */
131:
132: public int getTypeAnnotation() {
133: return typeAnnotation;
134: }
135:
136: /**
137: * Determine whether this is the same node as another node. <br />
138: * Note: a.isSameNode(b) if and only if generateId(a)==generateId(b)
139: * @return true if this Node object and the supplied Node object represent the
140: * same node in the tree.
141: */
142:
143: public boolean isSameNodeInfo(NodeInfo other) {
144: return this == other;
145: }
146:
147: /**
148: * Get the System ID for the node.
149: * @return the System Identifier of the entity in the source document containing the node,
150: * or null if not known. Note this is not the same as the base URI: the base URI can be
151: * modified by xml:base, but the system ID cannot.
152: */
153:
154: public String getSystemId() {
155: return systemId;
156: }
157:
158: /**
159: * Get the Base URI for the node, that is, the URI used for resolving a relative URI contained
160: * in the node. This will be the same as the System ID unless xml:base has been used.
161: */
162:
163: public String getBaseURI() {
164: if (kind == Type.PROCESSING_INSTRUCTION) {
165: return systemId;
166: } else {
167: return null;
168: }
169: }
170:
171: /**
172: * Get line number
173: * @return the line number of the node in its original source document; or -1 if not available
174: */
175:
176: public int getLineNumber() {
177: return -1;
178: }
179:
180: /**
181: * Determine the relative position of this node and another node, in document order.
182: * The other node will always be in the same document.
183: * @param other The other node, whose position is to be compared with this node
184: * @return -1 if this node precedes the other node, +1 if it follows the other
185: * node, or 0 if they are the same node. (In this case, isSameNode() will always
186: * return true, and the two nodes will produce the same result for generateId())
187: */
188:
189: public int compareOrder(NodeInfo other) {
190:
191: // are they the same node?
192: if (this .isSameNodeInfo(other)) {
193: return 0;
194: }
195: return (this .hashCode() < other.hashCode() ? -1 : +1);
196: }
197:
198: /**
199: * Return the string value of the node.
200: * @return the string value of the node
201: */
202:
203: public String getStringValue() {
204: return stringValue.toString();
205: }
206:
207: /**
208: * Get the value of the item as a CharSequence. This is in some cases more efficient than
209: * the version of the method that returns a String.
210: */
211:
212: public CharSequence getStringValueCS() {
213: return stringValue;
214: }
215:
216: /**
217: * Get name code. The name code is a coded form of the node name: two nodes
218: * with the same name code have the same namespace URI, the same local name,
219: * and the same prefix. By masking the name code with &0xfffff, you get a
220: * fingerprint: two nodes with the same fingerprint have the same local name
221: * and namespace URI.
222: * @see net.sf.saxon.om.NamePool#allocate allocate
223: */
224:
225: public int getNameCode() {
226: return nameCode;
227: }
228:
229: /**
230: * Get fingerprint. The fingerprint is a coded form of the expanded name
231: * of the node: two nodes
232: * with the same name code have the same namespace URI and the same local name.
233: * A fingerprint of -1 should be returned for a node with no name.
234: */
235:
236: public int getFingerprint() {
237: if (nameCode == -1) {
238: return -1;
239: } else {
240: return getNameCode() & 0xfffff;
241: }
242: }
243:
244: /**
245: * Get the local part of the name of this node. This is the name after the ":" if any.
246: * @return the local part of the name. For an unnamed node, returns "".
247: */
248:
249: public String getLocalPart() {
250: if (nameCode == -1) {
251: return "";
252: } else {
253: return config.getNamePool().getLocalName(nameCode);
254: }
255: }
256:
257: /**
258: * Get the URI part of the name of this node. This is the URI corresponding to the
259: * prefix, or the URI of the default namespace if appropriate.
260: * @return The URI of the namespace of this node. For an unnamed node, return null.
261: * For a node with an empty prefix, return an empty string.
262: */
263:
264: public String getURI() {
265: if (nameCode == -1) {
266: return "";
267: } else {
268: return config.getNamePool().getURI(nameCode);
269: }
270: }
271:
272: /**
273: * Get the prefix of the name of the node. This is defined only for elements and attributes.
274: * If the node has no prefix, or for other kinds of node, return a zero-length string.
275: *
276: * @return The prefix of the name of the node.
277: */
278:
279: public String getPrefix() {
280: if (nameCode == -1) {
281: return "";
282: } else {
283: return config.getNamePool().getPrefix(nameCode);
284: }
285: }
286:
287: /**
288: * Get the display name of this node. For elements and attributes this is [prefix:]localname.
289: * For unnamed nodes, it is an empty string.
290: * @return The display name of this node.
291: * For a node with no name, return an empty string.
292: */
293:
294: public String getDisplayName() {
295: if (nameCode == -1) {
296: return "";
297: } else {
298: return config.getNamePool().getDisplayName(nameCode);
299: }
300: }
301:
302: /**
303: * Get the NodeInfo object representing the parent of this node
304: * @return null - an Orphan has no parent.
305: */
306:
307: public NodeInfo getParent() {
308: return null;
309: }
310:
311: /**
312: * Return an iteration over the nodes reached by the given axis from this node
313: * @param axisNumber the axis to be searched, e.g. Axis.CHILD or Axis.ANCESTOR
314: * @return a SequenceIterator that scans the nodes reached by the axis in turn.
315: */
316:
317: public AxisIterator iterateAxis(byte axisNumber) {
318: switch (axisNumber) {
319: case Axis.ANCESTOR_OR_SELF:
320: case Axis.DESCENDANT_OR_SELF:
321: case Axis.SELF:
322: return SingletonIterator.makeIterator(this );
323: case Axis.ANCESTOR:
324: case Axis.ATTRIBUTE:
325: case Axis.CHILD:
326: case Axis.DESCENDANT:
327: case Axis.FOLLOWING:
328: case Axis.FOLLOWING_SIBLING:
329: case Axis.NAMESPACE:
330: case Axis.PARENT:
331: case Axis.PRECEDING:
332: case Axis.PRECEDING_SIBLING:
333: case Axis.PRECEDING_OR_ANCESTOR:
334: return EmptyIterator.getInstance();
335: default:
336: throw new IllegalArgumentException("Unknown axis number "
337: + axisNumber);
338: }
339: }
340:
341: /**
342: * Return an iteration over the nodes reached by the given axis from this node
343: * @param axisNumber the axis to be searched, e.g. Axis.CHILD or Axis.ANCESTOR
344: * @param nodeTest A pattern to be matched by the returned nodes
345: * @return a SequenceIterator that scans the nodes reached by the axis in turn.
346: */
347:
348: public AxisIterator iterateAxis(byte axisNumber, NodeTest nodeTest) {
349: switch (axisNumber) {
350: case Axis.ANCESTOR_OR_SELF:
351: case Axis.DESCENDANT_OR_SELF:
352: case Axis.SELF:
353: if (nodeTest.matches(this )) {
354: return SingletonIterator.makeIterator(this );
355: } else {
356: return EmptyIterator.getInstance();
357: }
358: case Axis.ANCESTOR:
359: case Axis.ATTRIBUTE:
360: case Axis.CHILD:
361: case Axis.DESCENDANT:
362: case Axis.FOLLOWING:
363: case Axis.FOLLOWING_SIBLING:
364: case Axis.NAMESPACE:
365: case Axis.PARENT:
366: case Axis.PRECEDING:
367: case Axis.PRECEDING_SIBLING:
368: case Axis.PRECEDING_OR_ANCESTOR:
369: return EmptyIterator.getInstance();
370: default:
371: throw new IllegalArgumentException("Unknown axis number "
372: + axisNumber);
373: }
374: }
375:
376: /**
377: * Get the value of a given attribute of this node
378: * @param fingerprint The fingerprint of the attribute name
379: * @return the attribute value if it exists or null if not
380: */
381:
382: public String getAttributeValue(int fingerprint) {
383: return null;
384: }
385:
386: /**
387: * Get the root node of this tree (not necessarily a document node).
388: * Always returns this node in the case of an Orphan node.
389: */
390:
391: public NodeInfo getRoot() {
392: return this ;
393: }
394:
395: /**
396: * Get the root (document) node
397: * @return the DocumentInfo representing the containing document, or null if the
398: * node is not part of a document. Always null for an Orphan node.
399: */
400:
401: public DocumentInfo getDocumentRoot() {
402: return null;
403: }
404:
405: /**
406: * Determine whether the node has any children.
407: * @return false - an orphan node never has any children
408: */
409:
410: public boolean hasChildNodes() {
411: return false;
412: }
413:
414: /**
415: * Get a character string that uniquely identifies this node.
416: * Note: a.isSameNode(b) if and only if generateId(a)==generateId(b)
417: * @return a string that uniquely identifies this node, within this
418: * document. The calling code prepends information to make the result
419: * unique across all documents.
420: */
421:
422: public String generateId() {
423: return "Q" + hashCode();
424: }
425:
426: /**
427: * Get the document number of the document containing this node. For a free-standing
428: * orphan node, just return the hashcode.
429: */
430:
431: public int getDocumentNumber() {
432: return hashCode() & 0xffffff;
433: // lose the top bits because we need to subtract these values for comparison
434: }
435:
436: /**
437: * Copy this node to a given outputter (deep copy)
438: */
439:
440: public void copy(Receiver out, int whichNamespaces,
441: boolean copyAnnotations, int locationId)
442: throws XPathException {
443: Navigator.copy(this , out, config.getNamePool(),
444: whichNamespaces, copyAnnotations, locationId);
445: }
446:
447: /**
448: * Output all namespace nodes associated with this element. Does nothing if
449: * the node is not an element.
450: * @param out The relevant outputter
451: * @param includeAncestors True if namespaces declared on ancestor elements must
452: */
453:
454: public void sendNamespaceDeclarations(Receiver out,
455: boolean includeAncestors) {
456: }
457:
458: /**
459: * Get all namespace undeclarations and undeclarations defined on this element.
460: *
461: * @param buffer If this is non-null, and the result array fits in this buffer, then the result
462: * may overwrite the contents of this array, to avoid the cost of allocating a new array on the heap.
463: * @return An array of integers representing the namespace declarations and undeclarations present on
464: * this element. For a node other than an element, return null. Otherwise, the returned array is a
465: * sequence of namespace codes, whose meaning may be interpreted by reference to the name pool. The
466: * top half word of each namespace code represents the prefix, the bottom half represents the URI.
467: * If the bottom half is zero, then this is a namespace undeclaration rather than a declaration.
468: * The XML namespace is never included in the list. If the supplied array is larger than required,
469: * then the first unused entry will be set to -1.
470: * <p/>
471: * <p>For a node other than an element, the method returns null.</p>
472: */
473:
474: public int[] getDeclaredNamespaces(int[] buffer) {
475: return null;
476: }
477:
478: }
479:
480: //
481: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
482: // you may not use this file except in compliance with the License. You may obtain a copy of the
483: // License at http://www.mozilla.org/MPL/
484: //
485: // Software distributed under the License is distributed on an "AS IS" basis,
486: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
487: // See the License for the specific language governing rights and limitations under the License.
488: //
489: // The Original Code is: all this file.
490: //
491: // The Initial Developer of the Original Code is
492: // Michael H. Kay.
493: //
494: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
495: //
496: // Contributor(s): none.
497: //
|