package org.cdlib.xtf.lazyTree;
// IMPORTANT NOTE: When comparing, this file is most similar to Saxon's
// net.sf.saxon.tinytree.TinyElementImpl.java
//
import net.sf.saxon.event.LocationCopier;
import net.sf.saxon.event.Receiver;
import net.sf.saxon.om.Axis;
import net.sf.saxon.om.AxisIterator;
import net.sf.saxon.om.Navigator;
import net.sf.saxon.om.NodeInfo;
import net.sf.saxon.om.StandardNames;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.type.Type;
import org.cdlib.xtf.util.PackedByteBuf;
import java.io.IOException;
/**
* A node in the XML parse tree representing an XML element.<P>
* This class is an implementation of NodeInfo. The object is a wrapper around
* one entry in the arrays maintained by the LazyTree. Note that the same node
* might be represented by different LazyElementImpl objects at different times.
* @author Michael H. Kay
*/
public class ElementImpl extends ParentNodeImpl
{
int nameSpace;
int[] attrNames;
String[] attrValues;
public void init(int attrOffset, int nameSpace)
throws IOException
{
this.nameSpace = nameSpace;
if (attrOffset >= 0)
{
// Read in the attributes.
document.attrFile.seek(attrOffset);
document.attrFile.read(document.attrBytes);
PackedByteBuf buf = document.attrBuf;
buf.setBytes(document.attrBytes);
int nAttrs = buf.readInt();
attrNames = new int[nAttrs];
attrValues = new String[nAttrs];
for (int i = 0; i < nAttrs; i++) {
int nameNum = buf.readInt();
attrNames[i] = document.nameNumToCode[nameNum];
attrValues[i] = buf.readString();
} // for i
} // if
} // init()
/**
* Return the type of node.
* @return Type.ELEMENT
*/
public final int getNodeKind() {
return Type.ELEMENT;
}
/**
* 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 type annotation of this node, if any
* Returns Type.UNTYPED_ANY if there is no type annotation
*/
public int getTypeAnnotation() {
return document.getTypeAnnotation(nodeNum);
}
/**
* Output all namespace nodes associated with this element.
* @param out The relevant outputter
* @param includeAncestors True if namespaces associated with ancestor
*/
public void sendNamespaceDeclarations(Receiver out, boolean includeAncestors)
throws XPathException
{
if (!document.usesNamespaces) {
return;
}
int ns = nameSpace;
if (ns > 0)
{
while (ns < document.numberOfNamespaces &&
document.namespaceParent[ns] == nodeNum)
{
int nscode = document.namespaceCode[ns];
out.namespace(nscode, 0);
ns++;
}
}
// now add the namespaces defined on the ancestor nodes. We rely on the receiver
// to eliminate multiple declarations of the same prefix
if (includeAncestors && document.isUsingNamespaces())
{
NodeInfo parent = getParent();
if (parent != null) {
parent.sendNamespaceDeclarations(out, true);
}
// terminates when the parent is a root node
}
}
/**
* 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 int[] getDeclaredNamespaces(int[] buffer) {
return getDeclaredNamespaces(document, nodeNum, nameSpace, buffer);
}
/**
* Static method to get all namespace undeclarations and undeclarations defined on a given element,
* without instantiating the node object.
* @param doc The lazy document containing the given element node
* @param nodeNr The node number of the given element node within the tinyTree
* @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>
*/
static int[] getDeclaredNamespaces(LazyDocument doc, int nodeNr,
int nameSpace, int[] buffer)
{
int ns = nameSpace;
if (ns > 0)
{
int count = 0;
while (ns < doc.numberOfNamespaces && doc.namespaceParent[ns] == nodeNr) {
count++;
ns++;
}
if (count == 0)
{
return NodeInfo.EMPTY_NAMESPACE_LIST;
}
else if (count <= buffer.length) {
System.arraycopy(doc.namespaceCode, nameSpace, buffer, 0, count);
if (count < buffer.length) {
buffer[count] = -1;
}
return buffer;
}
else {
int[] array = new int[count];
System.arraycopy(doc.namespaceCode, nameSpace, array, 0, count);
return array;
}
}
else {
return NodeInfo.EMPTY_NAMESPACE_LIST;
}
}
/**
* 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)
{
if (attrNames == null)
return null;
for (int i = 0; i < attrNames.length; i++) {
if ((attrNames[i] & 0xfffff) == fingerprint)
return attrValues[i];
} // for i
return null;
}
/**
* Copy this node to a given receiver
* @param whichNamespaces indicates which namespaces should be copied: all, none,
* or local (i.e., those not declared on a parent element)
*/
public void copy(Receiver out, int whichNamespaces, boolean copyAnnotations,
int locationId)
throws XPathException
{
int typeCode = (copyAnnotations ? getTypeAnnotation() : StandardNames.XS_UNTYPED);
if (locationId == 0 && out instanceof LocationCopier) {
out.setSystemId(getSystemId());
((LocationCopier)out).setLineNumber(getLineNumber());
}
out.startElement(nameCode, typeCode, locationId, 0);
// output the namespaces
if (whichNamespaces != NO_NAMESPACES)
sendNamespaceDeclarations(out, whichNamespaces == ALL_NAMESPACES);
// output the attributes
if (attrNames != null)
{
for (int i = 0; i < attrNames.length; i++) {
new AttributeImpl(this, i).copy(out,
NO_NAMESPACES,
copyAnnotations,
locationId);
} // for i
} // if
// indicate start of content
out.startContent();
// output the children
AxisIterator children = iterateAxis(Axis.CHILD);
int childNamespaces = (whichNamespaces == NO_NAMESPACES ? NO_NAMESPACES
: LOCAL_NAMESPACES);
while (true) {
NodeInfo next = (NodeInfo)children.next();
if (next == null)
break;
next.copy(out, childNamespaces, copyAnnotations, locationId);
}
out.endElement();
}
}
//
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
// you may not use this file except in compliance with the License. You may obtain a copy of the
// License at http://www.mozilla.org/MPL/
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
// See the License for the specific language governing rights and limitations under the License.
//
// The Original Code is: most of this file.
//
// The Initial Developer of the Original Code is
// Michael Kay of International Computers Limited (michael.h.kay@ntlworld.com).
//
// Portions created by Martin Haye are Copyright (C) Regents of the University
// of California. All Rights Reserved.
//
// Contributor(s): Martin Haye.
//