org.htmlunit.xpath.axes.LocPathIterator 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.
/*
* 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 org.htmlunit.xpath.axes;
import org.htmlunit.xpath.XPathContext;
import org.htmlunit.xpath.XPathVisitor;
import org.htmlunit.xpath.objects.XNodeSet;
import org.htmlunit.xpath.objects.XObject;
import org.htmlunit.xpath.res.XPATHErrorResources;
import org.htmlunit.xpath.res.XPATHMessages;
import org.htmlunit.xpath.xml.dtm.DTM;
import org.htmlunit.xpath.xml.dtm.DTMFilter;
import org.htmlunit.xpath.xml.dtm.DTMIterator;
import org.htmlunit.xpath.xml.dtm.DTMManager;
import org.htmlunit.xpath.xml.utils.PrefixResolver;
/**
* This class extends NodeSetDTM, which implements NodeIterator, and fetches nodes one at a time in
* document order based on a XPath.
*
* @see = 0) ? getProximityPosition() : m_pos;
final LocPathIterator clone;
try {
clone = (LocPathIterator) clone();
}
catch (final CloneNotSupportedException cnse) {
return -1;
}
// We want to clip off the last predicate, but only if we are a sub
// context node list, NOT if we are a context list. See pos68 test,
// also test against bug4638.
if (predCount > 0 && isPredicateTest) {
// Don't call setPredicateCount, because it clones and is slower.
clone.m_predCount = m_predicateIndex;
// The line above used to be:
// clone.m_predCount = predCount - 1;
// ...which looks like a dumb bug to me. -sb
}
while (DTM.NULL != clone.nextNode()) {
pos++;
}
if (isPredicateTest && m_predicateIndex < 1) {
m_length = pos;
}
return pos;
}
/** {@inheritDoc} */
@Override
public boolean isFresh() {
return m_pos == 0;
}
/** {@inheritDoc} */
@Override
public int previousNode() {
throw new RuntimeException(
XPATHMessages.createXPATHMessage(XPATHErrorResources.ER_NODESETDTM_CANNOT_ITERATE, null));
}
/** {@inheritDoc} */
@Override
public int getWhatToShow() {
// TODO: ??
return DTMFilter.SHOW_ALL & ~DTMFilter.SHOW_ENTITY_REFERENCE;
}
/** {@inheritDoc} */
@Override
public int getRoot() {
return m_context;
}
/** {@inheritDoc} */
@Override
public boolean getExpandEntityReferences() {
return true;
}
/** {@inheritDoc} */
@Override
public void detach() {
// sb: allow reusing of cached nodes when possible?
// m_cachedNodes = null;
m_execContext = null;
// m_prefixResolver = null; sb: Why would this ever want to be null?
m_cdtm = null;
m_length = -1;
m_pos = 0;
m_lastFetched = DTM.NULL;
m_context = DTM.NULL;
m_currentContextNode = DTM.NULL;
m_clones.freeInstance(this);
}
/** {@inheritDoc} */
@Override
public void reset() {
assertion(false, "This iterator can not reset!");
}
/** {@inheritDoc} */
@Override
public DTMIterator cloneWithReset() throws CloneNotSupportedException {
final LocPathIterator clone;
// clone = (LocPathIterator) clone();
clone = (LocPathIterator) m_clones.getInstanceOrThrow();
clone.m_execContext = m_execContext;
clone.m_cdtm = m_cdtm;
clone.m_context = m_context;
clone.m_currentContextNode = m_currentContextNode;
clone.m_stackFrame = m_stackFrame;
// clone.reset();
return clone;
}
/** {@inheritDoc} */
@Override
public abstract int nextNode();
/**
* Bottleneck the return of a next node, to make returns easier from nextNode().
*
* @param nextNode The next node found, may be null.
* @return The same node that was passed as an argument.
*/
protected int returnNextNode(final int nextNode) {
if (DTM.NULL != nextNode) {
m_pos++;
}
m_lastFetched = nextNode;
if (DTM.NULL == nextNode) {
m_foundLast = true;
}
return nextNode;
}
/** {@inheritDoc} */
@Override
public int getCurrentNode() {
return m_lastFetched;
}
/** {@inheritDoc} */
@Override
public void runTo(final int index) {
if (m_foundLast || ((index >= 0) && (index <= getCurrentPos()))) {
return;
}
if (-1 == index) {
while (DTM.NULL != nextNode()) {
;
}
}
else {
while (DTM.NULL != nextNode()) {
if (getCurrentPos() >= index) {
break;
}
}
}
}
/**
* The XPath execution context we are operating on.
*
* @return XPath execution context this iterator is operating on, or null if setRoot has not been
* called.
*/
public final XPathContext getXPathContext() {
return m_execContext;
}
/**
* Return the saved reference to the prefix resolver that was in effect when this iterator was
* created.
*
* @return The prefix resolver or this iterator, which may be null.
*/
public final PrefixResolver getPrefixResolver() {
if (null == m_prefixResolver) {
m_prefixResolver = (PrefixResolver) getExpressionOwner();
}
return m_prefixResolver;
}
/** {@inheritDoc} */
@Override
public void callVisitors(final XPathVisitor visitor) {
if (visitor.visitLocationPath()) {
visitor.visitStep();
callPredicateVisitors(visitor);
}
}
// ============= State Data =============
/**
* The pool for cloned iterators. Iterators need to be cloned because the hold running state, and
* thus the original iterator expression from the stylesheet pool can not be used.
*/
protected final transient IteratorPool m_clones = new IteratorPool(this);
/**
* The dtm of the context node. Careful about using this... it may not be the dtm of the current
* node.
*/
protected transient DTM m_cdtm;
/** The stack frame index for this iterator. */
transient int m_stackFrame = -1;
/**
* Value determined at compile time, indicates that this is an iterator at the top level of the
* expression, rather than inside a predicate.
*
* @serial
*/
private boolean m_isTopLevel = false;
/** The last node that was fetched, usually by nextNode. */
public transient int m_lastFetched = DTM.NULL;
/**
* The context node for this iterator, which doesn't change through the course of the iteration.
*/
protected transient int m_context = DTM.NULL;
/**
* The node context from where the expression is being executed from (i.e. for current() support).
* Different from m_context in that this is the context for the entire expression, rather than the
* context for the subexpression.
*/
protected transient int m_currentContextNode = DTM.NULL;
/** The current position of the context node. */
protected transient int m_pos = 0;
protected transient int m_length = -1;
/**
* Fast access to the current prefix resolver. It isn't really clear that this is needed.
*
* @serial
*/
private PrefixResolver m_prefixResolver;
/** The XPathContext reference, needed for execution of many operations. */
protected transient XPathContext m_execContext;
/** {@inheritDoc} */
@Override
public boolean isDocOrdered() {
return true;
}
/** {@inheritDoc} */
@Override
public int getAxis() {
return -1;
}
/** {@inheritDoc} */
@Override
public int getLastPos(final XPathContext xctxt) {
return getLength();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy