
net.sourceforge.htmlunit.xpath.axes.UnionPathIterator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of htmlunit-xpath Show documentation
Show all versions of htmlunit-xpath Show documentation
The XPath engine used by HtmlUnit.
The newest version!
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sourceforge.htmlunit.xpath.axes;
import net.sourceforge.htmlunit.xpath.Expression;
import net.sourceforge.htmlunit.xpath.XPathVisitor;
import net.sourceforge.htmlunit.xpath.compiler.Compiler;
import net.sourceforge.htmlunit.xpath.compiler.OpCodes;
import net.sourceforge.htmlunit.xpath.compiler.OpMap;
import net.sourceforge.htmlunit.xpath.xml.dtm.Axis;
import net.sourceforge.htmlunit.xpath.xml.dtm.DTM;
import net.sourceforge.htmlunit.xpath.xml.dtm.DTMIterator;
/**
* This class extends NodeSetDTM, which implements DTMIterator, and fetches nodes one at a time in
* document order based on a XPath UnionExpr.
* As each node is iterated via nextNode(), the node is also stored in the NodeVector, so that
* previousNode() can easily be done.
*/
public class UnionPathIterator extends LocPathIterator
implements Cloneable, DTMIterator, PathComponent {
/** {@inheritDoc} */
@Override
public void setRoot(int context, Object environment) {
super.setRoot(context, environment);
try {
if (null != m_exprs) {
int n = m_exprs.length;
DTMIterator[] newIters = new DTMIterator[n];
for (int i = 0; i < n; i++) {
DTMIterator iter = m_exprs[i].asIterator(m_execContext, context);
newIters[i] = iter;
iter.nextNode();
}
m_iterators = newIters;
}
} catch (Exception e) {
throw new net.sourceforge.htmlunit.xpath.xml.utils.WrappedRuntimeException(e);
}
}
/** {@inheritDoc} */
@Override
public void detach() {
if (m_allowDetach && null != m_iterators) {
for (DTMIterator m_iterator : m_iterators) {
m_iterator.detach();
}
m_iterators = null;
}
}
/**
* Create a UnionPathIterator object, including creation of location path iterators from the
* opcode list, and call back into the Compiler to create predicate expressions.
*
* @param compiler The Compiler which is creating this expression.
* @param opPos The position of this iterator in the opcode list from the compiler.
* @throws javax.xml.transform.TransformerException if any
*/
public UnionPathIterator(Compiler compiler, int opPos)
throws javax.xml.transform.TransformerException {
super();
opPos = OpMap.getFirstChildPos(opPos);
loadLocationPaths(compiler, opPos, 0);
}
/**
* This will return an iterator capable of handling the union of paths given.
*
* @param compiler The Compiler which is creating this expression.
* @param opPos The position of this iterator in the opcode list from the compiler.
* @return Object that is derived from LocPathIterator.
* @throws javax.xml.transform.TransformerException if any
*/
public static LocPathIterator createUnionIterator(Compiler compiler, int opPos)
throws javax.xml.transform.TransformerException {
// For the moment, I'm going to first create a full UnionPathIterator, and
// then see if I can reduce it to a UnionChildIterator. It would obviously
// be more effecient to just test for the conditions for a UnionChildIterator,
// and then create that directly.
UnionPathIterator upi = new UnionPathIterator(compiler, opPos);
int nPaths = upi.m_exprs.length;
boolean isAllChildIterators = true;
for (int i = 0; i < nPaths; i++) {
LocPathIterator lpi = upi.m_exprs[i];
if (lpi.getAxis() != Axis.CHILD) {
isAllChildIterators = false;
break;
} else {
// check for positional predicates or position function, which won't work.
if (HasPositionalPredChecker.check(lpi)) {
isAllChildIterators = false;
break;
}
}
}
if (isAllChildIterators) {
UnionChildIterator uci = new UnionChildIterator();
for (int i = 0; i < nPaths; i++) {
PredicatedNodeTest lpi = upi.m_exprs[i];
// I could strip the lpi down to a pure PredicatedNodeTest, but
// I don't think it's worth it. Note that the test can be used
// as a static object... so it doesn't have to be cloned.
uci.addNodeTest(lpi);
}
return uci;
}
return upi;
}
/** {@inheritDoc} */
@Override
public int getAnalysisBits() {
int bits = 0;
if (m_exprs != null) {
for (LocPathIterator m_expr : m_exprs) {
int bit = m_expr.getAnalysisBits();
bits |= bit;
}
}
return bits;
}
/** {@inheritDoc} */
@Override
public Object clone() throws CloneNotSupportedException {
UnionPathIterator clone = (UnionPathIterator) super.clone();
if (m_iterators != null) {
int n = m_iterators.length;
clone.m_iterators = new DTMIterator[n];
for (int i = 0; i < n; i++) {
clone.m_iterators[i] = (DTMIterator) m_iterators[i].clone();
}
}
return clone;
}
/**
* Create a new location path iterator.
*
* @param compiler The Compiler which is creating this expression.
* @param opPos The position of this iterator in the
* @return New location path iterator.
* @throws javax.xml.transform.TransformerException if any
*/
protected LocPathIterator createDTMIterator(Compiler compiler, int opPos)
throws javax.xml.transform.TransformerException {
return (LocPathIterator)
WalkerFactory.newDTMIterator(compiler, opPos, compiler.getLocationPathDepth() <= 0);
}
/**
* Initialize the location path iterators. Recursive.
*
* @param compiler The Compiler which is creating this expression.
* @param opPos The position of this iterator in the opcode list from the compiler.
* @param count The insert position of the iterator.
* @throws javax.xml.transform.TransformerException if any
*/
protected void loadLocationPaths(Compiler compiler, int opPos, int count)
throws javax.xml.transform.TransformerException {
// TODO: Handle unwrapped FilterExpr
int steptype = compiler.getOp(opPos);
if (steptype == OpCodes.OP_LOCATIONPATH) {
loadLocationPaths(compiler, compiler.getNextOpPos(opPos), count + 1);
m_exprs[count] = createDTMIterator(compiler, opPos);
m_exprs[count].exprSetParent(this);
} else {
// Have to check for unwrapped functions, which the LocPathIterator
// doesn't handle.
switch (steptype) {
case OpCodes.OP_VARIABLE:
case OpCodes.OP_FUNCTION:
case OpCodes.OP_GROUP:
loadLocationPaths(compiler, compiler.getNextOpPos(opPos), count + 1);
WalkingIterator iter = new WalkingIterator(compiler.getNamespaceContext());
iter.exprSetParent(this);
if (compiler.getLocationPathDepth() <= 0) iter.setIsTopLevel(true);
iter.m_firstWalker = new net.sourceforge.htmlunit.xpath.axes.FilterExprWalker(iter);
iter.m_firstWalker.init(compiler, opPos, steptype);
m_exprs[count] = iter;
break;
default:
m_exprs = new LocPathIterator[count];
}
}
}
/** {@inheritDoc} */
@Override
public int nextNode() {
if (m_foundLast) return DTM.NULL;
// Loop through the iterators getting the current fetched
// node, and get the earliest occuring in document order
int earliestNode = DTM.NULL;
if (null != m_iterators) {
int n = m_iterators.length;
int iteratorUsed = -1;
for (int i = 0; i < n; i++) {
int node = m_iterators[i].getCurrentNode();
if (DTM.NULL == node) continue;
else if (DTM.NULL == earliestNode) {
iteratorUsed = i;
earliestNode = node;
} else {
if (node == earliestNode) {
// Found a duplicate, so skip past it.
m_iterators[i].nextNode();
} else {
DTM dtm = getDTM(node);
if (dtm.isNodeAfter(node, earliestNode)) {
iteratorUsed = i;
earliestNode = node;
}
}
}
}
if (DTM.NULL != earliestNode) {
m_iterators[iteratorUsed].nextNode();
incrementCurrentPos();
} else m_foundLast = true;
}
m_lastFetched = earliestNode;
return earliestNode;
}
/**
* The location path iterators, one for each location path contained in the union
* expression.
*
* @serial
*/
protected LocPathIterator[] m_exprs;
/**
* The location path iterators, one for each location path contained in the union
* expression.
*
* @serial
*/
protected DTMIterator[] m_iterators;
/** {@inheritDoc} */
@Override
public int getAxis() {
// Could be smarter.
return -1;
}
/** {@inheritDoc} */
@Override
public void callVisitors(XPathVisitor visitor) {
if (visitor.visitUnionPath()) {
if (null != m_exprs) {
for (LocPathIterator m_expr : m_exprs) {
m_expr.callVisitors(visitor);
}
}
}
}
/** {@inheritDoc} */
@Override
public boolean deepEquals(Expression expr) {
if (!super.deepEquals(expr)) return false;
UnionPathIterator upi = (UnionPathIterator) expr;
if (null != m_exprs) {
int n = m_exprs.length;
if ((null == upi.m_exprs) || (upi.m_exprs.length != n)) return false;
for (int i = 0; i < n; i++) {
if (!m_exprs[i].deepEquals(upi.m_exprs[i])) return false;
}
} else if (null != upi.m_exprs) {
return false;
}
return true;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy