All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.htmlunit.xpath.axes.DescendantIterator Maven / Gradle / Ivy

There is a newer version: 4.7.0
Show 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 org.htmlunit.xpath.axes;

import org.htmlunit.xpath.Expression;
import org.htmlunit.xpath.XPathContext;
import org.htmlunit.xpath.compiler.Compiler;
import org.htmlunit.xpath.compiler.OpCodes;
import org.htmlunit.xpath.compiler.OpMap;
import org.htmlunit.xpath.patterns.NodeTest;
import org.htmlunit.xpath.xml.dtm.Axis;
import org.htmlunit.xpath.xml.dtm.DTM;
import org.htmlunit.xpath.xml.dtm.DTMAxisTraverser;
import org.htmlunit.xpath.xml.dtm.DTMFilter;
import org.htmlunit.xpath.xml.dtm.DTMIterator;

/**
 * This class implements an optimized iterator for descendant, descendant-or-self, or "//foo"
 * patterns.
 *
 * @see org.htmlunit.xpath.axes.LocPathIterator
 */
public class DescendantIterator extends LocPathIterator {

  /**
   * Create a DescendantIterator object.
   *
   * @param compiler A reference to the Compiler that contains the op map.
   * @param opPos The position within the op map, which contains the location path expression for
   *     this itterator.
   * @throws javax.xml.transform.TransformerException if any
   */
  DescendantIterator(final Compiler compiler, final int opPos, final int analysis)
      throws javax.xml.transform.TransformerException {

    super(analysis);

    int firstStepPos = OpMap.getFirstChildPos(opPos);
    final int stepType = compiler.getOp(firstStepPos);

    boolean orSelf = OpCodes.FROM_DESCENDANTS_OR_SELF == stepType;
    boolean fromRoot = false;
    if (OpCodes.FROM_SELF == stepType) {
      orSelf = true;
      // firstStepPos += 8;
    }
    else if (OpCodes.FROM_ROOT == stepType) {
      fromRoot = true;
      // Ugly code... will go away when AST work is done.
      final int nextStepPos = compiler.getNextStepPos(firstStepPos);
      if (compiler.getOp(nextStepPos) == OpCodes.FROM_DESCENDANTS_OR_SELF) {
          orSelf = true;
      }
      // firstStepPos += 8;
    }

    // Find the position of the last step.
    int nextStepPos = firstStepPos;
    while (true) {
      nextStepPos = compiler.getNextStepPos(nextStepPos);
      if (nextStepPos > 0) {
        final int stepOp = compiler.getOp(nextStepPos);
        if (OpCodes.ENDOP != stepOp) {
            firstStepPos = nextStepPos;
        }
        else {
            break;
        }
      }
      else {
          break;
      }
    }

    // Fix for http://nagoya.apache.org/bugzilla/show_bug.cgi?id=1336
    if ((analysis & WalkerFactory.BIT_CHILD) != 0) {
        orSelf = false;
    }

    if (fromRoot) {
      if (orSelf) {
          m_axis = Axis.DESCENDANTSORSELFFROMROOT;
      }
      else {
          m_axis = Axis.DESCENDANTSFROMROOT;
      }
    }
    else if (orSelf) {
        m_axis = Axis.DESCENDANTORSELF;
    }
    else {
        m_axis = Axis.DESCENDANT;
    }

    final int whatToShow = compiler.getWhatToShow(firstStepPos);

    if ((0
            == (whatToShow
                & (DTMFilter.SHOW_ATTRIBUTE
                    | DTMFilter.SHOW_ELEMENT
                    | DTMFilter.SHOW_PROCESSING_INSTRUCTION)))
        || (whatToShow == DTMFilter.SHOW_ALL)) {
        initNodeTest(whatToShow);
    }
    else {
      initNodeTest(
          whatToShow, compiler.getStepNS(firstStepPos), compiler.getStepLocalName(firstStepPos));
    }
    initPredicateInfo(compiler, firstStepPos);
  }

  /** {@inheritDoc} */
  @Override
  public DTMIterator cloneWithReset() throws CloneNotSupportedException {

    final DescendantIterator clone = (DescendantIterator) super.cloneWithReset();
    clone.m_traverser = m_traverser;

    clone.resetProximityPositions();

    return clone;
  }

  /** {@inheritDoc} */
  @Override
  public int nextNode() {
    if (m_foundLast) {
        return DTM.NULL;
    }

    if (DTM.NULL == m_lastFetched) {
      resetProximityPositions();
    }

    int next;

    try {
      do {
        if (0 == m_extendedTypeID) {
          next =
              m_lastFetched =
                  (DTM.NULL == m_lastFetched)
                      ? m_traverser.first(m_context)
                      : m_traverser.next(m_context, m_lastFetched);
        }
        else {
          next =
              m_lastFetched =
                  (DTM.NULL == m_lastFetched)
                      ? m_traverser.first(m_context, m_extendedTypeID)
                      : m_traverser.next(m_context, m_lastFetched, m_extendedTypeID);
        }

        if (DTM.NULL != next) {
          if (DTMIterator.FILTER_ACCEPT == acceptNode(next)) {
              break;
          }
          continue;
        }

        break;
      }
      while (next != DTM.NULL);

      if (DTM.NULL != next) {
        m_pos++;
        return next;
      }

      m_foundLast = true;
      return DTM.NULL;
    }
    finally {
    }
  }

  /** {@inheritDoc} */
  @Override
  public void setRoot(final int context, final Object environment) {
    super.setRoot(context, environment);
    m_traverser = m_cdtm.getAxisTraverser(m_axis);

    final String localName = getLocalName();
    final String namespace = getNamespace();
    final int what = m_whatToShow;
    if (DTMFilter.SHOW_ALL == what
        || NodeTest.WILD.equals(localName)
        || NodeTest.WILD.equals(namespace)) {
      m_extendedTypeID = 0;
    }
    else {
      final int type = getNodeTypeTest(what);
      m_extendedTypeID = m_cdtm.getExpandedTypeID(namespace, localName, type);
    }
  }

  /** {@inheritDoc} */
  @Override
  public int asNode(final XPathContext xctxt) throws javax.xml.transform.TransformerException {
    if (getPredicateCount() > 0) {
        return super.asNode(xctxt);
    }

    final int current = xctxt.getCurrentNode();

    final DTM dtm = xctxt.getDTM(current);
    final DTMAxisTraverser traverser = dtm.getAxisTraverser(m_axis);

    final String localName = getLocalName();
    final String namespace = getNamespace();
    final int what = m_whatToShow;
    if (DTMFilter.SHOW_ALL == what || localName == NodeTest.WILD || namespace == NodeTest.WILD) {
      return traverser.first(current);
    }
    final int type = getNodeTypeTest(what);
    final int extendedType = dtm.getExpandedTypeID(namespace, localName, type);
    return traverser.first(current, extendedType);
  }

  /** {@inheritDoc} */
  @Override
  public void detach() {
    m_traverser = null;
    m_extendedTypeID = 0;

    // Always call the superclass detach last!
    super.detach();
  }

  /** {@inheritDoc} */
  @Override
  public int getAxis() {
    return m_axis;
  }

  /** The traverser to use to navigate over the descendants. */
  protected transient DTMAxisTraverser m_traverser;

  /** The axis that we are traversing. */
  protected int m_axis;

  /** The extended type ID, not set until setRoot. */
  protected int m_extendedTypeID;

  /** {@inheritDoc} */
  @Override
  public boolean deepEquals(final Expression expr) {
    if (!super.deepEquals(expr)) {
        return false;
    }

    return m_axis == ((DescendantIterator) expr).m_axis;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy