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