net.sf.saxon.option.axiom.AxiomParentNodeWrapper Maven / Gradle / Ivy
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2015 Saxonica Limited.
// 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.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
package net.sf.saxon.option.axiom;
import net.sf.saxon.om.AtomicSequence;
import net.sf.saxon.om.NodeInfo;
import net.sf.saxon.pattern.NodeTest;
import net.sf.saxon.tree.iter.AxisIterator;
import net.sf.saxon.tree.iter.AxisIteratorImpl;
import net.sf.saxon.tree.util.FastStringBuffer;
import net.sf.saxon.tree.util.Navigator;
import net.sf.saxon.tree.wrapper.AbstractNodeWrapper;
import net.sf.saxon.tree.wrapper.SiblingCountingNode;
import net.sf.saxon.value.UntypedAtomicValue;
import org.apache.axiom.om.OMContainer;
import org.apache.axiom.om.OMDocument;
import org.apache.axiom.om.OMNode;
import org.apache.axiom.om.OMText;
import java.util.Iterator;
/**
* A node in the XDM tree; specifically, a node that wraps an Axiom document node or element node.
*
* @author Michael H. Kay
*/
public abstract class AxiomParentNodeWrapper extends AbstractNodeWrapper
implements SiblingCountingNode {
protected OMContainer node;
protected AxiomParentNodeWrapper(OMContainer node) {
this.node = node;
}
/**
* Get the underlying Axiom node, to implement the VirtualNode interface
*/
public Object getUnderlyingNode() {
return node;
}
/**
* Get the typed value.
*
* @return the typed value. If requireSingleton is set to true, the result
* will always be an AtomicValue. In other cases it may be a Value
* representing a sequence whose items are atomic values.
*/
public AtomicSequence atomize() {
return new UntypedAtomicValue(getStringValueCS());
}
/**
* Get the value of the item as a CharSequence. This is in some cases more efficient than
* the version of the method that returns a String.
*/
public CharSequence getStringValueCS() {
FastStringBuffer buff = new FastStringBuffer(FastStringBuffer.C256);
for (Iterator iter = node.getDescendants(false); iter.hasNext(); ) {
OMNode next = (OMNode) iter.next();
if (next instanceof OMText) {
buff.append(((OMText) next).getText());
}
}
return buff.condense();
}
/**
* Determine whether the node has any children.
* Note: the result is equivalent to
* getEnumeration(Axis.CHILD, AnyNodeTest.getInstance()).hasNext()
*/
public boolean hasChildNodes() {
return node.getFirstOMChild() != null;
}
/**
* Get a character string that uniquely identifies this node. Note:
* a.isSameNode(b) if and only if generateId(a)==generateId(b)
*
* @param buffer a buffer to contain a string that uniquely identifies this node, across all documents
*/
public void generateId(FastStringBuffer buffer) {
Navigator.appendSequentialKey(this, buffer, true);
}
@Override
protected final AxisIterator iterateChildren(NodeTest nodeTest) {
return new ChildWrappingIterator(this, nodeTest);
}
@Override
protected AxisIterator iterateDescendants(NodeTest nodeTest, boolean includeSelf) {
// Note: for unknown reasons, this method is really slow. See XMark test q7.
return new DescendantWrappingIterator(this, nodeTest, includeSelf);
}
/**
* Abstract iterator that takes an iterator over nodes in the Axiom tree and
* wraps it with an implementation of Saxon's AxisIterator that wraps each
* successive node as it is found.
*/
private abstract class AxiomWrappingIterator extends AxisIteratorImpl {
Iterator base;
NodeTest nodeTest;
public AxiomWrappingIterator(Iterator base, NodeTest nodeTest) {
this.base = base;
this.nodeTest = nodeTest;
}
public NodeInfo next() {
while (true) {
if (base.hasNext()) {
Object node = base.next();
NodeInfo wrapper = wrap(node);
if (nodeTest.matchesNode(wrapper)) {
return wrapper;
}
} else {
return null;
}
}
}
protected abstract NodeInfo wrap(Object node);
}
/**
* Iterator over the descendants of a supplied node (optionally including the node itself)
*/
protected class DescendantWrappingIterator extends AxiomWrappingIterator {
AxiomParentNodeWrapper parentWrapper;
AxiomDocument docWrapper;
boolean includeSelf;
public DescendantWrappingIterator(AxiomParentNodeWrapper parentWrapper, NodeTest nodeTest, boolean includeSelf) {
super(node.getDescendants(includeSelf), nodeTest);
this.parentWrapper = parentWrapper;
docWrapper = (AxiomDocument)parentWrapper.getTreeInfo();
this.includeSelf = includeSelf;
}
public AxisIterator getAnother() {
return new DescendantWrappingIterator(parentWrapper, nodeTest, includeSelf);
}
protected NodeInfo wrap(Object node) {
if (node instanceof OMDocument) {
return docWrapper.getRootNode();
} else {
return AxiomDocument.makeWrapper((OMNode) node, docWrapper, null, -1);
}
}
}
/**
* Iterator over the children of a supplied node
*/
protected class ChildWrappingIterator extends AxiomWrappingIterator {
AxiomParentNodeWrapper commonParent;
AxiomDocument docWrapper;
int index = 0;
public ChildWrappingIterator(AxiomParentNodeWrapper commonParent, NodeTest nodeTest) {
super(node.getChildren(), nodeTest);
this.commonParent = commonParent;
this.nodeTest = nodeTest;
this.docWrapper = (AxiomDocument)commonParent.getTreeInfo();
}
public AxisIterator getAnother() {
return new ChildWrappingIterator(commonParent, nodeTest);
}
protected NodeInfo wrap(Object node) {
return AxiomDocument.makeWrapper((OMNode) node, docWrapper, commonParent, index++);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy