package client.net.sf.saxon.ce.tree.linked;
import client.net.sf.saxon.ce.event.Receiver;
import client.net.sf.saxon.ce.lib.NamespaceConstant;
import client.net.sf.saxon.ce.om.*;
import client.net.sf.saxon.ce.trans.XPathException;
import client.net.sf.saxon.ce.tree.util.FastStringBuffer;
import client.net.sf.saxon.ce.tree.util.NamespaceIterator;
import client.net.sf.saxon.ce.tree.util.Navigator;
import client.net.sf.saxon.ce.type.Type;
import java.util.Iterator;
/**
* ElementImpl implements an element with no attributes or namespace declarations.<P>
* This class is an implementation of NodeInfo.
* @author Michael H. Kay
*/
public class ElementImpl extends ParentNodeImpl implements NamespaceResolver {
private int nameCode;
private AttributeCollection attributeList; // this excludes namespace attributes
private NamespaceBinding[] namespaceList = null; // list of namespace codes
/**
* Construct an empty ElementImpl
*/
public ElementImpl() {}
/**
* Set the name code. Used when creating a dummy element in the Stripper
* @param nameCode the integer name code representing the element name
*/
public void setNameCode(int nameCode) {
this.nameCode = nameCode;
}
/**
* Set the attribute list
* @param atts the list of attributes of this element (not including namespace attributes)
*/
public void setAttributeList(AttributeCollection atts) {
this.attributeList = atts;
}
/**
* Set the namespace list
* @param namespaces an integer array of namespace codes
*/
public void setNamespaceList(NamespaceBinding[] namespaces) {
this.namespaceList = namespaces;
}
/**
* Initialise a new ElementImpl with an element name
* @param nameCode Integer representing the element name, with namespaces resolved
* @param atts The attribute list: always null
* @param parent The parent node
* @param sequenceNumber Integer identifying this element within the document
*/
public void initialise(int nameCode, AttributeCollection atts, NodeInfo parent,
int sequenceNumber) {
setNameCode(nameCode);
setRawParent((ParentNodeImpl)parent);
setRawSequenceNumber(sequenceNumber);
attributeList = atts;
}
/**
* Set location information for this node
* @param systemId the base URI
*/
public void setLocation(String systemId) {
DocumentImpl root = getRawParent().getPhysicalRoot();
root.setSystemId(getRawSequenceNumber(), systemId);
}
/**
* Set the system ID of this node. This method is provided so that a NodeInfo
* implements the javax.xml.transform.Source interface, allowing a node to be
* used directly as the Source of a transformation
*/
public void setSystemId(String uri) {
getPhysicalRoot().setSystemId(getRawSequenceNumber(), uri);
}
/**
* Get the root node
*/
public NodeInfo getRoot() {
ParentNodeImpl up = getRawParent();
if (up == null || (up instanceof DocumentImpl && ((DocumentImpl)up).isImaginary())) {
return this;
} else {
return up.getRoot();
}
}
/**
* Get the root node, if it is a document node.
*
* @return the DocumentInfo representing the containing document. If this
* node is part of a tree that does not have a document node as its
* root, returns null.
* @since 8.4
*/
public DocumentInfo getDocumentRoot() {
NodeInfo root = getRoot();
if (root instanceof DocumentInfo) {
return (DocumentInfo)root;
} else {
return null;
}
}
/**
* Get the system ID of the entity containing this element node.
*/
public final String getSystemId() {
DocumentImpl root = getPhysicalRoot();
return (root == null ? null : root.getSystemId(getRawSequenceNumber()));
}
/**
* Get the base URI of this element node. This will be the same as the System ID unless
* xml:base has been used.
*/
public String getBaseURI() {
return Navigator.getBaseURI(this);
}
/**
* Get the attribute list. Note that if the attribute list is empty, it should not be modified, as it
* will be shared by other elements. Instead, set a new attribute list.
* @return the list of attributes of this element (not including namespace attributes)
*/
public AttributeCollection gsetAttributeCollection() {
return this.attributeList;
}
/**
* Determine whether the node has the is-nilled property
*
* @return true if the node has the is-nilled property
*/
public boolean isNilled() {
return false;
}
/**
* Get the type annotation of this node, if any
* @return the type annotation, as the integer name code of the type name
*/
public int getTypeAnnotation() {
return StandardNames.XS_UNTYPED;
}
/**
* Set the line number of the element within its source document entity
* @param line the line number
* @param column the column number
*/
public void setLineAndColumn(int line, int column) {
DocumentImpl root = getPhysicalRoot();
if (root != null) {
root.setLineAndColumn(getRawSequenceNumber(), line, column);
}
}
/**
* Get the line number of the node within its source document entity
*/
public int getLineNumber() {
DocumentImpl root = getPhysicalRoot();
if (root == null) {
return -1;
} else {
return root.getLineNumber(getRawSequenceNumber());
}
}
/**
* Get the line number of the node within its source document entity
*/
public int getColumnNumber() {
DocumentImpl root = getPhysicalRoot();
if (root == null) {
return -1;
} else {
return root.getColumnNumber(getRawSequenceNumber());
}
}
/**
* Get the nameCode of the node. This is used to locate the name in the NamePool
*/
public int getNameCode() {
return nameCode;
}
/**
* Get a character string that uniquely identifies this node
* @param buffer to contain the generated ID
*/
public void generateId(FastStringBuffer buffer) {
int sequence = getRawSequenceNumber();
if (sequence >= 0) {
getPhysicalRoot().generateId(buffer);
buffer.append("e");
buffer.append(Integer.toString(sequence));
} else {
getRawParent().generateId(buffer);
buffer.append("f");
buffer.append(Integer.toString(getSiblingPosition()));
}
}
/**
* Return the kind of node.
* @return Type.ELEMENT
*/
public final int getNodeKind() {
return Type.ELEMENT;
}
/**
* Copy this node to a given outputter (supporting xsl:copy-of)
* @param out The outputter
* @param copyOptions
*/
public void copy(Receiver out, int copyOptions) throws XPathException {
out.startElement(getNameCode(), 0);
// output the namespaces
int childCopyOptions = copyOptions & ~CopyOptions.ALL_NAMESPACES;
if ((copyOptions & CopyOptions.LOCAL_NAMESPACES) != 0) {
NamespaceBinding[] localNamespaces = getDeclaredNamespaces(null);
for (int i=0; i<localNamespaces.length; i++) {
NamespaceBinding ns = localNamespaces[i];
if (ns == null) {
break;
}
out.namespace(ns, 0);
}
} else if ((copyOptions & CopyOptions.ALL_NAMESPACES) != 0) {
NamespaceIterator.sendNamespaces(this, out);
childCopyOptions |= CopyOptions.LOCAL_NAMESPACES;
}
// output the attributes
if (attributeList != null) {
for (int i=0; i<attributeList.getLength(); i++) {
int nc = attributeList.getNameCode(i);
if (nc != -1) {
// if attribute hasn't been deleted
out.attribute(nc, attributeList.getValue(i));
}
}
}
out.startContent();
// output the children
NodeImpl next = (NodeImpl)getFirstChild();
while (next!=null) {
next.copy(out, childCopyOptions);
next = (NodeImpl)next.getNextSibling();
}
out.endElement();
}
/**
* Set the namespace declarations for the element
* @param namespaces the list of namespace codes
* @param namespacesUsed the number of entries in the list that are used
*/
public void setNamespaceDeclarations(NamespaceBinding[] namespaces, int namespacesUsed) {
namespaceList = new NamespaceBinding[namespacesUsed];
System.arraycopy(namespaces, 0, namespaceList, 0, namespacesUsed);
}
/**
* Get an iterator over all the prefixes declared in this namespace context. This will include
* the default namespace (prefix="") and the XML namespace where appropriate
*/
public Iterator iteratePrefixes() {
return new Iterator() {
private NamePool pool = null;
private Iterator<NamespaceBinding> iter = NamespaceIterator.iterateNamespaces(ElementImpl.this);
public boolean hasNext() {
return (pool == null || iter.hasNext());
}
public Object next() {
if (pool == null) {
pool = getNamePool();
return "xml";
} else {
return iter.next().getPrefix();
}
}
public void remove() {
throw new UnsupportedOperationException("remove");
}
};
}
/**
* Get the URI bound to a given prefix in the in-scope namespaces of this element
* @param prefix the prefix
* @return the uri , or null if there is no in-scope binding for this prefix
*/
public String getURIForPrefix(String prefix, boolean useDefault) {
if (prefix.equals("xml")) {
return NamespaceConstant.XML;
}
if (prefix.isEmpty() && !useDefault) {
return NamespaceConstant.NULL;
}
if (namespaceList!=null) {
for (int i=0; i<namespaceList.length; i++) {
if ((namespaceList[i].getPrefix().equals(prefix))) {
String uri = namespaceList[i].getURI();
return (uri.isEmpty() && !prefix.isEmpty() ? null : uri);
}
}
}
NodeInfo next = getRawParent();
if (next.getNodeKind()==Type.DOCUMENT) {
// prefixCode==0 represents the empty namespace prefix ""
return (prefix.isEmpty() ? NamespaceConstant.NULL : null);
} else {
return ((ElementImpl)next).getURIForPrefix(prefix, useDefault);
}
}
/**
* Search the NamespaceList for a given URI, returning the corresponding prefix.
* @param uri The URI to be matched.
* @return The prefix corresponding to this URI. If not found, return null. If there is
* more than one prefix matching the URI, the first one found is returned. If the URI matches
* the default namespace, return an empty string.
*/
public String getPrefixForURI(String uri) {
if (uri.equals(NamespaceConstant.XML)) {
return "xml";
}
for (Iterator<String> iter = iteratePrefixes(); iter.hasNext();) {
String prefix = iter.next();
if (uri.equals(getURIForPrefix(prefix, true))) {
return uri;
}
}
return null;
}
/**
* Get all namespace undeclarations and undeclarations defined on this element.
*
* @param buffer If this is non-null, and the result array fits in this buffer, then the result
* may overwrite the contents of this array, to avoid the cost of allocating a new array on the heap.
* @return An array of integers representing the namespace declarations and undeclarations present on
* this element. For a node other than an element, return null. Otherwise, the returned array is a
* sequence of namespace codes, whose meaning may be interpreted by reference to the name pool. The
* top half word of each namespace code represents the prefix, the bottom half represents the URI.
* If the bottom half is zero, then this is a namespace undeclaration rather than a declaration.
* The XML namespace is never included in the list. If the supplied array is larger than required,
* then the first unused entry will be set to -1.
* <p/>
* <p>For a node other than an element, the method returns null.</p>
*/
public NamespaceBinding[] getDeclaredNamespaces(NamespaceBinding[] buffer) {
return (namespaceList == null ? NamespaceBinding.EMPTY_ARRAY : namespaceList);
}
/**
* Get the attribute list for this element.
* @return The attribute list. This will not include any
* namespace attributes. The attribute names will be in expanded form, with prefixes
* replaced by URIs
*/
public AttributeCollection getAttributeList() {
return (attributeList == null ? AttributeCollection.EMPTY_ATTRIBUTE_COLLECTION : attributeList);
}
/**
* Get the namespace list for this element.
* @return The raw namespace list, as an array of name codes
*/
public NamespaceBinding[] getNamespaceList() {
return namespaceList;
}
/**
* Get the value of a given attribute of this node
* @param fingerprint The fingerprint of the attribute name
* @return the attribute value if it exists or null if not
*/
public String getAttributeValue(int fingerprint) {
return (attributeList == null ? null : attributeList.getValueByFingerprint(fingerprint));
}
/**
* Get the value of a given attribute of this node
* @param uri the namespace URI of the attribute name, or "" if the attribute is not in a namepsace
* @param localName the local part of the attribute name
* @return the attribute value if it exists or null if not
*/
public String getAttributeValue(String uri, String localName) {
return (attributeList == null ? null : attributeList.getValue(uri, localName));
}
/**
* Determine whether this node has the is-id property
* @return true if the node is an ID
*/
public boolean isId() {
int tc = getTypeAnnotation();
return tc < 1024 ? tc == StandardNames.XS_ID : getConfiguration().getTypeHierarchy().isIdCode(tc);
}
}
// 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.