simplepathinterpreter.java
来自「JXPath」· Java 代码 · 共 842 行 · 第 1/3 页
JAVA
842 行
/*
* Copyright 1999-2004 The Apache Software Foundation
*
* Licensed 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.apache.commons.jxpath.ri.axes;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.commons.jxpath.JXPathException;
import org.apache.commons.jxpath.ri.Compiler;
import org.apache.commons.jxpath.ri.EvalContext;
import org.apache.commons.jxpath.ri.InfoSetUtil;
import org.apache.commons.jxpath.ri.QName;
import org.apache.commons.jxpath.ri.compiler.Expression;
import org.apache.commons.jxpath.ri.compiler.NameAttributeTest;
import org.apache.commons.jxpath.ri.compiler.NodeNameTest;
import org.apache.commons.jxpath.ri.compiler.NodeTest;
import org.apache.commons.jxpath.ri.compiler.Step;
import org.apache.commons.jxpath.ri.model.NodeIterator;
import org.apache.commons.jxpath.ri.model.NodePointer;
import org.apache.commons.jxpath.ri.model.beans.LangAttributePointer;
import org.apache.commons.jxpath.ri.model.beans.NullElementPointer;
import org.apache.commons.jxpath.ri.model.beans.NullPropertyPointer;
import org.apache.commons.jxpath.ri.model.beans.PropertyOwnerPointer;
import org.apache.commons.jxpath.ri.model.beans.PropertyPointer;
/**
* An evaluation mechanism for simple XPaths, which
* is much faster than the usual process. It is only used for
* xpaths which have no context-dependent parts, consist entirely of
* <code>child::name</code> and <code>self::node()</code> steps with
* predicates that either integer or have the form <code>[@name = ...]</code>.
*
* @author Dmitri Plotnikov
* @version $Revision: 1.10 $ $Date: 2002/04/24 04:05:40 $
*/
public class SimplePathInterpreter {
// Because of the complexity caused by the variety of situations
// that need to be addressed by this class, we attempt to break up
// the class into individual methods addressing those situations
// individually. The names of the methods are supposed to
// give brief descriptions of those situations.
private static final QName QNAME_NAME = new QName(null, "name");
private static final int PERFECT_MATCH = 1000;
// Uncomment this variable and the PATH = ... lines in
// the two following methods in order to be able to print the
// currently evaluated path for debugging of this class
// private static String PATH; // Debugging
/**
* Interpret a simple path that starts with the given root and
* follows the given steps. All steps must have the axis "child::"
* and a name test. They can also optionally have predicates
* of type [@name=expression] or simply [expression] interpreted
* as an index.
*/
public static NodePointer interpretSimpleLocationPath(
EvalContext context, NodePointer root, Step steps[])
{
// PATH = createNullPointer(context, root, steps, 0).toString(); // Dbg
NodePointer pointer = doStep(context, root, steps, 0);
// return valuePointer(pointer);
return pointer;
}
/**
* Interpret the steps of a simple expression path that
* starts with the given root, which is the result of evaluation
* of the root expression of the expression path, applies the
* given predicates to it and then follows the given steps.
* All steps must have the axis "child::" or "attribute::"
* and a name test. They can also optionally have predicates
* of type [@name=...] or simply [...] interpreted as an index.
*/
public static NodePointer interpretSimpleExpressionPath(
EvalContext context, NodePointer root,
Expression predicates[], Step[] steps)
{
// PATH = createNullPointerForPredicates(context, root,
// steps, -1, predicates, 0).toString(); // Debugging
NodePointer pointer =
doPredicate(context, root, steps, -1, predicates, 0);
// return valuePointer(pointer);
return pointer;
}
/**
* Recursive evaluation of a path. The general plan is:
* Look at the current step,
* find nodes that match it,
* iterate over those nodes and
* for each of them call doStep again for subsequent steps.
*/
private static NodePointer doStep(
EvalContext context, NodePointer parent,
Step steps[], int currentStep)
{
if (parent == null) {
return null;
}
if (currentStep == steps.length) {
// We have reached the end of the list of steps
return parent;
}
// Open all containers
parent = valuePointer(parent);
Step step = steps[currentStep];
Expression predicates[] = step.getPredicates();
// Divide and conquer: the process is broken out into
// four major use cases.
// 1. Current step has no predicates and
// the root is a property owner (e.g. bean or map)
// 2. Current step has predicates and
// the root is a property owner (e.g. bean or map)
// 3. Current step has no predicates and
// the root is an InfoSet standard node (e.g. DOM Node)
// 4. Current step has predicates and
// the root is an InfoSet standard node (e.g. DOM Node)
if (parent instanceof PropertyOwnerPointer) {
if (predicates == null || predicates.length == 0) {
return doStepNoPredicatesPropertyOwner(
context,
(PropertyOwnerPointer) parent,
steps,
currentStep);
}
else {
return doStepPredicatesPropertyOwner(
context,
(PropertyOwnerPointer) parent,
steps,
currentStep);
}
}
else {
if (predicates == null || predicates.length == 0) {
return doStepNoPredicatesStandard(
context,
parent,
steps,
currentStep);
}
else {
return doStepPredicatesStandard(
context,
parent,
steps,
currentStep);
}
}
}
/**
* We have a step that starts with a property owner (bean, map, etc) and has
* no predicates. The name test of the step may map to a scalar property
* or to a collection. If it is a collection, we should apply the tail of
* the path to each element until we find a match. If we don't find
* a perfect match, we should return the "best quality" pointer, which
* has the longest chain of steps mapping to existing nodes and the shortes
* tail of Null* pointers.
*/
private static NodePointer doStepNoPredicatesPropertyOwner(
EvalContext context, PropertyOwnerPointer parentPointer,
Step[] steps, int currentStep)
{
Step step = steps[currentStep];
NodePointer childPointer =
createChildPointerForStep(parentPointer, step);
if (!childPointer.isActual()) {
// The property does not exist - create a null pointer.
return createNullPointer(
context,
parentPointer,
steps,
currentStep);
}
else if (currentStep == steps.length - 1) {
// If this is the last step - we are done, we found it
return childPointer;
}
else if (childPointer.isCollection()) {
// Iterate over all values and
// execute remaining steps for each node,
// looking for the best quality match
int bestQuality = 0;
childPointer = (NodePointer) childPointer.clone();
NodePointer bestMatch = null;
int count = childPointer.getLength();
for (int i = 0; i < count; i++) {
childPointer.setIndex(i);
NodePointer pointer =
doStep(context, childPointer, steps, currentStep + 1);
int quality = computeQuality(pointer);
if (quality == PERFECT_MATCH) {
return pointer;
}
else if (quality > bestQuality) {
bestQuality = quality;
bestMatch = (NodePointer) pointer.clone();
}
}
if (bestMatch != null) {
return bestMatch;
}
// This step did not find anything - return a null pointer
return createNullPointer(context, childPointer, steps, currentStep);
}
else {
// Evaluate subsequent steps
return doStep(context, childPointer, steps, currentStep + 1);
}
}
/**
* A path that starts with a standard InfoSet node (e.g. DOM Node) and
* has no predicates. Get a child iterator and apply the tail of
* the path to each element until we find a match. If we don't find
* a perfect match, we should return the "best quality" pointer, which
* has the longest chain of steps mapping to existing nodes and the shortes
* tail of Null* pointers.
*/
private static NodePointer doStepNoPredicatesStandard(
EvalContext context, NodePointer parentPointer,
Step[] steps, int currentStep)
{
Step step = steps[currentStep];
if (step.getAxis() == Compiler.AXIS_SELF) {
return doStep(context, parentPointer, steps, currentStep + 1);
}
int bestQuality = 0;
NodePointer bestMatch = null;
NodeIterator it = getNodeIterator(context, parentPointer, step);
if (it != null) {
for (int i = 1; it.setPosition(i); i++) {
NodePointer childPointer = it.getNodePointer();
if (steps.length == currentStep + 1) {
// If this is the last step - we are done, we found it
return childPointer;
}
NodePointer pointer = doStep(
context, childPointer, steps, currentStep + 1);
int quality = computeQuality(pointer);
if (quality == PERFECT_MATCH) {
return pointer;
}
else if (quality > bestQuality) {
bestQuality = quality;
bestMatch = (NodePointer) pointer.clone();
}
}
}
if (bestMatch != null) {
return bestMatch;
}
return createNullPointer(
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?