package client.net.sf.saxon.ce.tree.linked; import client.net.sf.saxon.ce.event.Receiver; import client.net.sf.saxon.ce.om.NodeInfo; import client.net.sf.saxon.ce.om.StandardNames; import client.net.sf.saxon.ce.trans.XPathException; import client.net.sf.saxon.ce.tree.util.FastStringBuffer; import client.net.sf.saxon.ce.type.Type; /** * A node in the "linked" tree representing an attribute. Note that this is * generated only "on demand", when the attribute is selected by a path expression.<P> * * <p>It is possible for multiple AttributeImpl objects to represent the same attribute node. * The identity of an attribute node is determined by the identity of the element, and the index * position of the attribute within the element. Index positions are not reused when an attribute * is deleted, and are retained when an attribute is renamed.</p> * * <p>This object no longer caches information such as the name code and string value, because * these would become invalid when the element node is modified.</p> * * @author Michael H. Kay */ final class AttributeImpl extends NodeImpl { /** * Construct an Attribute node for the n'th attribute of a given element * @param element The element containing the relevant attribute * @param index The index position of the attribute starting at zero */ public AttributeImpl(ElementImpl element, int index) { setRawParent(element); setSiblingPosition(index); } /** * Get the name code, which enables the name to be located in the name pool */ public int getNameCode() { if (getRawParent() == null || getSiblingPosition() == -1) { // implies this node is deleted return -1; } return ((ElementImpl)getRawParent()).getAttributeList().getNameCode(getSiblingPosition()); } /** * Get the type annotation of this node, if any */ public int getTypeAnnotation() { return StandardNames.XS_UNTYPED_ATOMIC; } /** * Determine whether this is the same node as another node * @return true if this Node object and the supplied Node object represent the * same node in the tree. */ public boolean isSameNodeInfo(NodeInfo other) { if (!(other instanceof AttributeImpl)) { return false; } if (this==other) { return true; } AttributeImpl otherAtt = (AttributeImpl)other; return getRawParent().isSameNodeInfo(otherAtt.getRawParent()) && getSiblingPosition() == otherAtt.getSiblingPosition(); } /** * The hashCode() method obeys the contract for hashCode(): that is, if two objects are equal * (represent the same node) then they must have the same hashCode() * @since 8.7 Previously, the effect of the equals() and hashCode() methods was not defined. Callers * should therefore be aware that third party implementations of the NodeInfo interface may * not implement the correct semantics. */ public int hashCode() { return getRawParent().hashCode() ^ (getSiblingPosition()<<16); } /** * Get the node sequence number (in document order). Sequence numbers are monotonic but not * consecutive. In the current implementation, parent nodes (elements and roots) have a zero * least-significant word, while namespaces, attributes, text nodes, comments, and PIs have * the top word the same as their owner and the bottom half reflecting their relative position. */ protected int[] getSequenceNumber() { return new int[]{getRawParent().getRawSequenceNumber(), 0x8000 + getSiblingPosition()}; // note the 0x8000 is to leave room for namespace nodes } /** * Return the type of node. * @return Node.ATTRIBUTE */ public final int getNodeKind() { return Type.ATTRIBUTE; } /** * Return the character value of the node. * @return the attribute value */ public String getStringValue() { return ((ElementImpl)getRawParent()).getAttributeList().getValue(getSiblingPosition()); } /** * Get next sibling - not defined for attributes */ public NodeInfo getNextSibling() { return null; } /** * Get previous sibling - not defined for attributes */ public NodeInfo getPreviousSibling() { return null; } /** * Get the previous node in document order (skipping attributes) */ public NodeImpl getPreviousInDocument() { return (NodeImpl)getParent(); } /** * Get the next node in document order (skipping attributes) */ public NodeImpl getNextInDocument(NodeImpl anchor) { if (anchor==this) return null; return ((NodeImpl)getParent()).getNextInDocument(anchor); } /** * Get sequential key. Returns key of owning element with the attribute index as a suffix * @param buffer a buffer to which the generated ID will be written */ public void generateId(FastStringBuffer buffer) { getParent().generateId(buffer); buffer.append('a'); buffer.append(Integer.toString(getSiblingPosition())); } /** * Copy this node to a given outputter */ public void copy(Receiver out, int copyOptions) throws XPathException { int nameCode = getNameCode(); out.attribute(nameCode, getStringValue()); } } // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. // If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. // This Source Code Form is “Incompatible With Secondary Licenses”, as defined by the Mozilla Public License, v. 2.0.