Navigation.java

/**
 * **********************************************************************
 *
 * <p>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
 *
 * <p>http://www.apache.org/licenses/LICENSE-2.0
 *
 * <p>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.
 *
 * <p>**********************************************************************
 */
package org.odftoolkit.odfdom.incubator.search;

import org.w3c.dom.Node;

/**
 * Abstract class Navigation used to navigate the document and find the matched element by the user
 * defined conditions
 */
public abstract class Navigation {

  /**
   * Return true if document still has more matched Selection when traversing the document(In other
   * words return true if getNextMatchElement() would return an element instance rather than return
   * null)
   *
   * @return true if document still has more matched Selection, and vice versa
   */
  public abstract boolean hasNext();
  // abstract public void gotoPrevious();

  /**
   * get the current Selection result
   *
   * @return the current Selection result
   */
  public abstract Selection getCurrentItem();

  /**
   * check if the element match the user defined condition
   *
   * @param element navigate this element
   * @return true if the element match the user defined condition; false if not match
   */
  public abstract boolean match(Node element);

  /**
   * get the next matched element in a whole dom tree
   *
   * @param startpoint navigate from the startpoint
   * @return the next matched element
   */
  protected Node getNextMatchElement(Node startpoint) {
    Node matchedNode = null;
    matchedNode = traverseTree(startpoint);

    Node currentpoint = startpoint;
    while ((matchedNode == null) && (currentpoint != null)) {
      Node sibling = currentpoint.getNextSibling();
      if ((sibling != null)
          && (sibling.getNodeType() == Node.TEXT_NODE || sibling.getNodeType() == Node.ELEMENT_NODE)
          && (match(sibling))) {
        matchedNode = sibling;
      }
      while ((sibling != null) && (matchedNode == null)) {
        if ((sibling.getNodeType() == Node.TEXT_NODE
            || sibling.getNodeType() == Node.ELEMENT_NODE)) {
          matchedNode = traverseTree(sibling);
        }
        sibling = sibling.getNextSibling();
        if (sibling != null && match(sibling)) {
          matchedNode = sibling;
        }
      }
      currentpoint = currentpoint.getParentNode();
    }

    return matchedNode;
  }

  /**
   * get the next matched element in a sub tree
   *
   * @param startpoint navigate from the startpoint
   * @param root the root of the sub tree
   * @return the next matched element
   */
  protected Node getNextMatchElementInTree(Node startpoint, Node root) {
    Node matchedNode = null;
    matchedNode = traverseTree(startpoint);

    Node currentpoint = startpoint;
    while ((matchedNode == null) && (currentpoint != root)) {
      Node sibling = currentpoint.getNextSibling();
      if ((sibling != null)
          && (sibling.getNodeType() == Node.TEXT_NODE || sibling.getNodeType() == Node.ELEMENT_NODE)
          && (match(sibling))) {
        matchedNode = sibling;
      }
      while ((sibling != null) && (matchedNode == null)) {
        if ((sibling.getNodeType() == Node.TEXT_NODE
            || sibling.getNodeType() == Node.ELEMENT_NODE)) {
          matchedNode = traverseTree(sibling);
        }
        sibling = sibling.getNextSibling();
        if (sibling != null && match(sibling)) {
          matchedNode = sibling;
        }
      }
      currentpoint = currentpoint.getParentNode();
    }

    return matchedNode;
  }

  private Node traverseTree(Node root) {
    Node matchedNode = null;
    if (root == null) {
      return null;
    }
    // if (match(root)) return root;

    Node node = root.getFirstChild();
    while (node != null) {
      if ((node.getNodeType() == Node.TEXT_NODE || node.getNodeType() == Node.ELEMENT_NODE)) {
        if (match(node) == true) {
          matchedNode = node;
          break;
        } else {
          matchedNode = traverseTree(node);
          if (matchedNode != null) {
            break;
          }
        }
      }
      node = node.getNextSibling();
    }
    return matchedNode;
  }
}