net.sf.saxon.tree.ElementWithAttributes Maven / Gradle / Ivy
package net.sf.saxon.tree;
import net.sf.saxon.event.LocationCopier;
import net.sf.saxon.event.Receiver;
import net.sf.saxon.om.*;
import net.sf.saxon.sort.IntArraySet;
import net.sf.saxon.sort.IntIterator;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.type.Type;
import java.util.Iterator;
/**
* A node in the XML parse tree representing an XML element.
* This class is an implementation of NodeInfo
* @author Michael H. Kay
* @version 8 August 2000: separated from ElementImpl
*/
// The name of the element and its attributes are now namespace-resolved by the
// parser. However, this class retains the ability to do namespace resolution for other
// names, for example variable and template names in a stylesheet.
public class ElementWithAttributes extends ElementImpl implements NamespaceResolver {
protected AttributeCollection attributeList; // this excludes namespace attributes
protected int[] namespaceList = null; // list of namespace codes
// note that this namespace list includes only the namespaces actually defined on
// this element, not those inherited from outer elements.
/**
* Initialise a new ElementWithAttributes with an element name and attribute list
* @param nameCode The element name, with namespaces resolved
* @param atts The attribute list, after namespace processing
* @param parent The parent node
*/
public void initialise(int nameCode, AttributeCollectionImpl atts, NodeInfo parent,
String baseURI, int lineNumber, int sequenceNumber) {
this.nameCode = nameCode;
attributeList = atts;
this.parent = (ParentNodeImpl)parent;
sequence = sequenceNumber;
root = (DocumentImpl)parent.getDocumentRoot();
root.setLineNumber(sequenceNumber, lineNumber);
root.setSystemId(sequenceNumber, baseURI);
}
/**
* 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(int[] namespaces, int namespacesUsed) {
namespaceList = new int[namespacesUsed];
System.arraycopy(namespaces, 0, namespaceList, 0, namespacesUsed);
}
/**
* Get the namespace URI corresponding to a given prefix. Return null
* if the prefix is not in scope.
*
* @param prefix the namespace prefix. May be the zero-length string, indicating
* that there is no prefix. This indicates either the default namespace or the
* null namespace, depending on the value of useDefault.
* @param useDefault true if the default namespace is to be used when the
* prefix is "". If false, the method returns "" when the prefix is "".
* @return the uri for the namespace, or null if the prefix is not in scope.
* The "null namespace" is represented by the pseudo-URI "".
*/
public String getURIForPrefix(String prefix, boolean useDefault) {
if (prefix.equals("xml")) {
return NamespaceConstant.XML;
}
if (prefix.length() == 0 && !useDefault) {
return "";
}
NamePool pool = getNamePool();
int prefixCode = pool.getCodeForPrefix(prefix);
if (prefixCode==-1) {
return null;
}
try {
short uriCode = getURICodeForPrefixCode(prefixCode);
return pool.getURIFromURICode(uriCode);
} catch (NamespaceException e) {
return null;
}
}
/**
* 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 IntIterator iter = NamespaceCodeIterator.iterateNamespaces(ElementWithAttributes.this);
public boolean hasNext() {
return (pool == null || iter.hasNext());
}
public Object next() {
if (pool == null) {
pool = getNamePool();
return "xml";
} else {
return pool.getPrefixFromNamespaceCode(iter.next());
}
}
public void remove() {
throw new UnsupportedOperationException("remove");
}
};
}
/**
* Search the NamespaceList for a given prefix, returning the corresponding URI.
* @param prefix The prefix to be matched. To find the default namespace, supply ""
* @return The URI code corresponding to this namespace. If it is an unnamed default namespace,
* return Namespace.NULL_CODE.
* @throws NamespaceException if the prefix has not been declared on this NamespaceList.
*/
public short getURICodeForPrefix(String prefix) throws NamespaceException {
if (prefix.equals("xml")) return NamespaceConstant.XML_CODE;
NamePool pool = getNamePool();
int prefixCode = pool.getCodeForPrefix(prefix);
if (prefixCode==-1) {
throw new NamespaceException(prefix);
}
return getURICodeForPrefixCode(prefixCode);
}
private short getURICodeForPrefixCode(int prefixCode) throws NamespaceException {
if (namespaceList!=null) {
for (int i=0; i>16) == prefixCode) {
return (short)(namespaceList[i] & 0xffff);
}
}
}
NodeInfo next = parent;
while (true) {
if (next.getNodeKind()==Type.DOCUMENT) {
// prefixCode==0 represents the empty namespace prefix ""
if (prefixCode==0) return NamespaceConstant.NULL_CODE;
throw new NamespaceException(getNamePool().getPrefixFromNamespaceCode(prefixCode<<16));
} else if (next instanceof ElementWithAttributes) {
return ((ElementWithAttributes)next).getURICodeForPrefixCode(prefixCode);
} else {
next = next.getParent();
}
}
}
/**
* 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";
NamePool pool = getNamePool();
int uriCode = pool.getCodeForURI(uri);
if (uriCode<0) return null;
return getPrefixForURICode(uriCode);
}
private String getPrefixForURICode(int code) {
if (namespaceList!=null) {
for (int i=0; i
* For a node other than an element, the method returns null.
*/
public int[] getDeclaredNamespaces(int[] buffer) {
return (namespaceList == null ? IntArraySet.EMPTY_INT_ARRAY : namespaceList);
}
/**
* Get the list of in-scope namespaces for this element as an array of
* namespace codes. (Used by LiteralResultElement)
* @return the list of namespaces
*/
public int[] getInScopeNamespaceCodes() {
return NamespaceIterator.getInScopeNamespaceCodes(this);
}
/**
* 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;
}
/**
* 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.getValueByFingerprint(fingerprint);
}
/**
* Copy this node to a given outputter (supporting xsl:copy-of)
* @param out The outputter
* @param whichNamespaces indicates which namespaces should be output: all, none, or local
* namespaces only (those not declared on the parent element)
*/
public void copy(Receiver out, int whichNamespaces, boolean copyAnnotations, int locationId) throws XPathException {
int typeCode = (copyAnnotations ? getTypeAnnotation() : -1);
if (locationId == 0 && out instanceof LocationCopier) {
out.setSystemId(getBaseURI());
((LocationCopier)out).setLineNumber(getLineNumber());
}
out.startElement(getNameCode(), typeCode, locationId, 0);
// output the namespaces
switch (whichNamespaces) {
case NodeInfo.NO_NAMESPACES:
break;
case NodeInfo.LOCAL_NAMESPACES:
int[] localNamespaces = getDeclaredNamespaces(null);
for (int i=0; i