1 /*
2 * Copyright (C) 2002 Carsten Krebs (Team-Konzept GmbH & Co.KG)
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18 package com.teamkonzept.dom4jb.saxon;
19
20 import javax.xml.transform.TransformerException;
21
22 import com.icl.saxon.om.Axis;
23 import com.icl.saxon.om.AxisEnumeration;
24 import com.icl.saxon.om.DocumentInfo;
25 import com.icl.saxon.om.EmptyEnumeration;
26 import com.icl.saxon.om.NodeInfo;
27 import com.icl.saxon.om.SingletonEnumeration;
28 import com.icl.saxon.output.Outputter;
29 import com.icl.saxon.pattern.NodeTest;
30 import com.teamkonzept.dom4jb.schema.TextDescriptor;
31
32 public class Text
33 extends com.teamkonzept.dom4jb.dom.Text
34 implements NodeInfo, AxisNode {
35
36 private static final int LOW_20_MASK = 0xfffff;
37 private DescendantAxis axis;
38 private int position;
39
40 public Text(final Document document,
41 final TextDescriptor descriptor,
42 final Object bean) {
43 super(document, descriptor, bean);
44 this.axis = null;
45 this.position = -1;
46 }
47
48 public synchronized void attachAxis(final int position,
49 final DescendantAxis axis) {
50 this.axis = axis;
51 this.position = position;
52 }
53
54 public DescendantAxis getAxis() {
55 return axis;
56 }
57
58 public int getPosition() {
59 return position;
60 }
61
62 /***
63 * Get a character string that uniquely identifies this node.<br />
64 * Note: a.isSameNode(b) if and only if generateId(a)==generateId(b)
65 * @return a string that uniquely identifies this node, within this
66 * document. The calling code prepends information to make the result
67 * unique across all documents.
68 */
69 public String generateId() {
70 final StringBuffer sb = new StringBuffer(getParent().generateId());
71 sb.append("text");
72 sb.append(this.getChildIndex());
73 return sb.toString();
74 }
75
76 /***
77 * Copy this node to a given outputter (deep copy)
78 */
79 public void copy(final Outputter out) throws TransformerException {
80 out.writeContent(getStringValue());
81 }
82
83 /***
84 * Output all namespace nodes associated with this element. Does nothing if
85 * the node is not an element.
86 * @param out The relevant outputter
87 * @param includeAncestors True if namespaces declared on ancestor elements
88 * must be output; false if it is known that these are already on the
89 * result tree
90 */
91 public void outputNamespaceNodes(final Outputter out,
92 final boolean includeAncestors)
93 throws TransformerException {
94 }
95
96 /***
97 * Get the display name of this node. For elements and attributes this
98 * is [prefix:]localname. For unnamed nodes, it is an empty string.
99 * @return The display name of this node.
100 * For a node with no name, return an empty string.
101 */
102 public String getDisplayName() {
103 return getNodeName();
104 }
105
106 /***
107 * Return the string value of the node. The interpretation of this depends
108 * on the type of node. For an element it is the accumulated character
109 * content of the element, including descendant elements.
110 * @return the string value of the node
111 */
112 public String getStringValue() {
113 return getNodeValue();
114 }
115
116 /***
117 * Find the value of a given attribute of this node. <BR>
118 * This method is defined on all nodes to meet XSL requirements, but for
119 * nodes other than elements it will always return null.
120 * @param uri the namespace uri of an attribute ("" if no namespace)
121 * @param localName the local name of the attribute
122 * @return the value of the attribute, if it exists, otherwise null
123 */
124 public String getAttributeValue(final String uri, final String localName) {
125 return "";
126 }
127
128 /***
129 * Get the value of a given attribute of this node
130 * @param fingerprint The fingerprint of the attribute name
131 * @return the attribute value if it exists or null if not
132 */
133 public String getAttributeValue(final int fingerprint) {
134 return null;
135 }
136
137 public void expandStringValue(final StringBuffer sb) {
138 sb.append(getNodeValue());
139 }
140
141 public Namespace[] getNamespaces() {
142 return null;
143 }
144 // ------- GENERAL stuff -------
145
146 /***
147 * Get the System ID for the node.
148 * @return the System Identifier of the entity in the source document
149 * containing the node, or null if not known. Note this is not the same as
150 * the base URI: the base URI can be modified by xml:base, but the
151 * system ID cannot.
152 */
153 public String getSystemId() {
154 return ((Document) document).getSystemId();
155 }
156
157 public void setSystemId(final String uri) {
158 ((Document) document).setSystemId(uri);
159 }
160
161 /***
162 * Get the Base URI for the node, that is, the URI used for resolving a
163 * relative URI contained in the node. This will be the same as the
164 * System ID unless xml:base has been used.
165 */
166 public String getBaseURI() {
167 return getSystemId();
168 }
169
170 /***
171 * Get line number
172 * @return the line number of the node in its original source document;
173 * or -1 if not available
174 */
175 public int getLineNumber() {
176 return -1;
177 }
178
179 /***
180 * Get name code. The name code is a coded form of the node name: two nodes
181 * with the same name code have the same namespace URI, the same local name,
182 * and the same prefix. By masking the name code with &0xfffff, you get a
183 * fingerprint: two nodes with the same fingerprint have the same local name
184 * and namespace URI.
185 * @see com.icl.saxon.om.NamePool#allocate allocate
186 */
187 public int getNameCode() {
188 return -1;
189 }
190
191 /***
192 * Get fingerprint. The fingerprint is a coded form of the expanded name
193 * of the node: two nodes
194 * with the same name code have the same namespace URI and the same
195 * local name. A fingerprint of -1 should be returned for a node with
196 * no name.
197 */
198 public int getFingerprint() {
199 return getNameCode() & LOW_20_MASK;
200 }
201
202 /***
203 * Get the URI part of the name of this node. This is the URI corresponding
204 * to the prefix, or the URI of the default namespace if appropriate.
205 * @return The URI of the namespace of this node. For an unnamed node,
206 * return null. For a node with an empty prefix, return an empty string.
207 */
208 public String getURI() {
209 return null;
210 }
211
212 /***
213 * Get the NodeInfo object representing the parent of this node
214 */
215 public NodeInfo getParent() {
216 return (NodeInfo) getParentNode();
217 }
218
219 /***
220 * Get the prefix part of the name of this node. This is the name before
221 * the ":" if any.
222 * @return the prefix part of the name. For an unnamed node, return an
223 * empty string.
224 */
225 public String getPrefix() {
226 return "";
227 }
228
229 /***
230 * Get the prefix part of the name of this node. This is the name before
231 * the ":" if any.
232 * @return the prefix part of the name. For an unnamed node, return an
233 * empty string.
234 */
235 public String getLocalName() {
236 return "";
237 }
238
239 /***
240 * Get the root (document) node
241 * @return the DocumentInfo representing the containing document
242 */
243 public DocumentInfo getDocumentRoot() {
244 return (DocumentInfo) document;
245 }
246
247 /***
248 * Copy the string-value of this node to a given outputter
249 */
250 public void copyStringValue(final Outputter out)
251 throws TransformerException {
252 out.writeContent(getStringValue());
253 }
254
255 /***
256 * Return an enumeration over the nodes reached by the given axis from
257 * this node
258 * @param nodeType the type(s) of node to be included,
259 * e.g. NodeInfo.ELEMENT, NodeInfo.TEXT.
260 * The value NodeInfo.NODE means include any type of node.
261 * @param nodeTest A pattern to be matched by the returned nodes
262 * @return a NodeEnumeration that scans the nodes reached by the axis
263 * in turn.
264 */
265 public AxisEnumeration getEnumeration(
266 final byte axisNumber,
267 final NodeTest nodeTest) {
268 switch (axisNumber) {
269 case Axis.ANCESTOR :
270 return new FilterEnumeration(
271 new AncestorEnumeration(this, false),
272 nodeTest);
273
274 case Axis.ANCESTOR_OR_SELF :
275 return new FilterEnumeration(
276 new AncestorEnumeration(this, true),
277 nodeTest);
278
279 case Axis.ATTRIBUTE :
280 case Axis.CHILD :
281 case Axis.DESCENDANT :
282 return EmptyEnumeration.getInstance();
283
284 case Axis.DESCENDANT_OR_SELF :
285 if (nodeTest.matches(this))
286 return new SingletonEnumeration(this);
287 return EmptyEnumeration.getInstance();
288
289 case Axis.FOLLOWING :
290 return new FilterEnumeration(
291 new FollowingEnumeration(this),
292 nodeTest);
293
294 case Axis.FOLLOWING_SIBLING :
295 return new FilterEnumeration(
296 new SiblingEnumeration(this, true),
297 nodeTest);
298
299 case Axis.NAMESPACE :
300 return EmptyEnumeration.getInstance();
301
302 case Axis.PARENT :
303 if (nodeTest.matches((NodeInfo) parent))
304 return new SingletonEnumeration((NodeInfo) parent);
305 return EmptyEnumeration.getInstance();
306
307 case Axis.PRECEDING :
308 return new FilterEnumeration(
309 new PrecedingEnumeration(this, false),
310 nodeTest);
311
312 case Axis.PRECEDING_SIBLING :
313 return new FilterEnumeration(
314 new SiblingEnumeration(this, false),
315 nodeTest);
316
317 case Axis.SELF :
318 if (nodeTest.matches(this))
319 return new SingletonEnumeration(this);
320 return EmptyEnumeration.getInstance();
321
322 case Axis.PRECEDING_OR_ANCESTOR :
323 return new FilterEnumeration(
324 new PrecedingEnumeration(this, true),
325 nodeTest);
326
327 default :
328 throw new IllegalArgumentException(
329 "Unknown axis number " + axisNumber);
330 }
331 }
332
333 /***
334 * Determine the relative position of this node and another node,
335 * in document order. The other node will always be in the same document.
336 * @param other The other node, whose position is to be compared with
337 * this node
338 * @return -1 if this node precedes the other node, +1 if it follows
339 * the other node, or 0 if they are the same node. (In this case,
340 * isSameNode() will always return true, and the two nodes will produce
341 * the same result for generateId())
342 */
343 public int compareOrder(final NodeInfo other) {
344 // are they the same node?
345 if (this == other || this.isSameNode(other)) {
346 return 0;
347 }
348
349 // are they siblings (common case)
350 if (this.getParent().isSameNode(other.getParent())) {
351 return this.getChildIndex()
352 - ((com.teamkonzept.dom4jb.dom.Node) other).getChildIndex();
353 }
354
355 // are they evaluated on the same descendant axis
356 DescendantAxis axis;
357 int axisIdx = 0;
358 synchronized (this) {
359 axis = this.getAxis();
360 if (axis != null) {
361 axisIdx = this.getPosition();
362 }
363 }
364 AxisNode node = (AxisNode) other;
365 if (axis != null) {
366 synchronized (node) {
367 final DescendantAxis otherAxis = node.getAxis();
368 if (otherAxis == axis) {
369 return axisIdx - node.getPosition();
370 }
371 }
372 }
373
374 // find the depths of both nodes in the tree
375 int depth1 = 0;
376 int depth2 = 0;
377 NodeInfo p1 = this;
378 NodeInfo p2 = other;
379 while (p1 != null) {
380 depth1++;
381 p1 = p1.getParent();
382 }
383 while (p2 != null) {
384 depth2++;
385 p2 = p2.getParent();
386 }
387
388 // move up one branch of the tree so we have two nodes on the same level
389 p1 = this;
390 while (depth1 > depth2) {
391 p1 = p1.getParent();
392 depth1--;
393 }
394
395 p2 = other;
396 while (depth2 > depth1) {
397 p2 = p2.getParent();
398 depth2--;
399 }
400
401 // now move up both branches in sync until we find a common parent
402 while (true) {
403 NodeInfo par1 = p1.getParent();
404 NodeInfo par2 = p2.getParent();
405 if (par1 == null || par2 == null) {
406 throw new NullPointerException(
407 "DOM tree compare" + " - internal error");
408 }
409 if (par1.isSameNode(par2)) {
410 return ((com.teamkonzept.dom4jb.dom.Node) p1).getChildIndex()
411 - ((com.teamkonzept.dom4jb.dom.Node) p2).getChildIndex();
412 }
413 p1 = par1;
414 p2 = par2;
415 }
416 }
417
418 /***
419 * Determine whether this is the same node as another node. <br />
420 * Note: a.isSameNode(b) if and only if generateId(a)==generateId(b)
421 * @return true if this Node object and the supplied Node object
422 * represent the same node in the tree.
423 */
424 public boolean isSameNode(final NodeInfo other) {
425 if (this == other) {
426 return true;
427 }
428 if (other == null
429 || this.getNodeType() != other.getNodeType()
430 || !(other instanceof com.teamkonzept.dom4jb.dom.Node)
431 || getChildIndex()
432 != ((com.teamkonzept.dom4jb.dom.Node) other).getChildIndex()) {
433 return false;
434 }
435 return this.equals(other);
436 }
437 }
This page was automatically generated by Maven