View Javadoc
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