nodepointer.java
来自「JXPath」· Java 代码 · 共 765 行 · 第 1/2 页
JAVA
765 行
/*
* 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.model;
import java.util.Locale;
import org.apache.commons.jxpath.JXPathContext;
import org.apache.commons.jxpath.JXPathException;
import org.apache.commons.jxpath.Pointer;
import org.apache.commons.jxpath.ri.Compiler;
import org.apache.commons.jxpath.ri.JXPathContextReferenceImpl;
import org.apache.commons.jxpath.ri.NamespaceResolver;
import org.apache.commons.jxpath.ri.QName;
import org.apache.commons.jxpath.ri.compiler.NodeNameTest;
import org.apache.commons.jxpath.ri.compiler.NodeTest;
import org.apache.commons.jxpath.ri.compiler.NodeTypeTest;
import org.apache.commons.jxpath.ri.model.beans.NullPointer;
/**
* Common superclass for Pointers of all kinds. A NodePointer maps to
* a deterministic XPath that represents the location of a node in an
* object graph. This XPath uses only simple axes: child, namespace and
* attribute and only simple, context-independent predicates.
*
* @author Dmitri Plotnikov
* @version $Revision: 1.25 $ $Date: 2004/04/01 02:55:32 $
*/
public abstract class NodePointer implements Pointer {
public static final int WHOLE_COLLECTION = Integer.MIN_VALUE;
protected int index = WHOLE_COLLECTION;
public static final String UNKNOWN_NAMESPACE = "<<unknown namespace>>";
private boolean attribute = false;
private transient Object rootNode;
private NamespaceResolver namespaceResolver;
/**
* Allocates an entirely new NodePointer by iterating through all installed
* NodePointerFactories until it finds one that can create a pointer.
*/
public static NodePointer newNodePointer(
QName name,
Object bean,
Locale locale)
{
NodePointer pointer = null;
if (bean == null) {
pointer = new NullPointer(name, locale);
return pointer;
}
NodePointerFactory[] factories =
JXPathContextReferenceImpl.getNodePointerFactories();
for (int i = 0; i < factories.length; i++) {
pointer = factories[i].createNodePointer(name, bean, locale);
if (pointer != null) {
return pointer;
}
}
throw new JXPathException(
"Could not allocate a NodePointer for object of "
+ bean.getClass());
}
/**
* Allocates an new child NodePointer by iterating through all installed
* NodePointerFactories until it finds one that can create a pointer.
*/
public static NodePointer newChildNodePointer(
NodePointer parent,
QName name,
Object bean)
{
NodePointerFactory[] factories =
JXPathContextReferenceImpl.getNodePointerFactories();
for (int i = 0; i < factories.length; i++) {
NodePointer pointer =
factories[i].createNodePointer(parent, name, bean);
if (pointer != null) {
return pointer;
}
}
throw new JXPathException(
"Could not allocate a NodePointer for object of "
+ bean.getClass());
}
protected NodePointer parent;
protected Locale locale;
// private NamespaceManager namespaceManager;
protected NodePointer(NodePointer parent) {
this.parent = parent;
}
protected NodePointer(NodePointer parent, Locale locale) {
this.parent = parent;
this.locale = locale;
}
public NamespaceResolver getNamespaceResolver() {
if (namespaceResolver == null && parent != null) {
namespaceResolver = parent.getNamespaceResolver();
}
return namespaceResolver;
}
public void setNamespaceResolver(NamespaceResolver namespaceResolver) {
this.namespaceResolver = namespaceResolver;
}
public NodePointer getParent() {
NodePointer pointer = parent;
while (pointer != null && pointer.isContainer()) {
pointer = pointer.getImmediateParentPointer();
}
return pointer;
}
public NodePointer getImmediateParentPointer() {
return parent;
}
/**
* Set to true if the pointer represents the "attribute::" axis.
*/
public void setAttribute(boolean attribute) {
this.attribute = attribute;
}
/**
* Returns true if the pointer represents the "attribute::" axis.
*/
public boolean isAttribute() {
return attribute;
}
/**
* Returns true if this Pointer has no parent.
*/
public boolean isRoot() {
return parent == null;
}
/**
* If true, this node does not have children
*/
public abstract boolean isLeaf();
/**
* @deprecated Please use !isContainer()
*/
public boolean isNode() {
return !isContainer();
}
/**
* If true, this node is axiliary and can only be used as an intermediate in
* the chain of pointers.
*/
public boolean isContainer() {
return false;
}
/**
* If the pointer represents a collection, the index identifies
* an element of that collection. The default value of <code>index</code>
* is <code>WHOLE_COLLECTION</code>, which just means that the pointer
* is not indexed at all.
* Note: the index on NodePointer starts with 0, not 1.
*/
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
/**
* Returns <code>true</code> if the value of the pointer is an array or
* a Collection.
*/
public abstract boolean isCollection();
/**
* If the pointer represents a collection (or collection element),
* returns the length of the collection.
* Otherwise returns 1 (even if the value is null).
*/
public abstract int getLength();
/**
* By default, returns <code>getNode()</code>, can be overridden to
* return a "canonical" value, like for instance a DOM element should
* return its string value.
*/
public Object getValue() {
NodePointer valuePointer = getValuePointer();
if (valuePointer != this) {
return valuePointer.getValue();
}
// Default behavior is to return the same as getNode()
return getNode();
}
/**
* If this pointer manages a transparent container, like a variable,
* this method returns the pointer to the contents.
* Only an auxiliary (non-node) pointer can (and should) return a
* value pointer other than itself.
* Note that you probably don't want to override
* <code>getValuePointer()</code> directly. Override the
* <code>getImmediateValuePointer()</code> method instead. The
* <code>getValuePointer()</code> method is calls
* <code>getImmediateValuePointer()</code> and, if the result is not
* <code>this</code>, invokes <code>getValuePointer()</code> recursively.
* The idea here is to open all nested containers. Let's say we have a
* container within a container within a container. The
* <code>getValuePointer()</code> method should then open all those
* containers and return the pointer to the ultimate contents. It does so
* with the above recursion.
*/
public NodePointer getValuePointer() {
NodePointer ivp = getImmediateValuePointer();
if (ivp != this) {
return ivp.getValuePointer();
}
return this;
}
/**
* @see #getValuePointer()
*
* @return NodePointer is either <code>this</code> or a pointer
* for the immediately contained value.
*/
public NodePointer getImmediateValuePointer() {
return this;
}
/**
* An actual pointer points to an existing part of an object graph, even
* if it is null. A non-actual pointer represents a part that does not exist
* at all.
* For instance consider the pointer "/address/street".
* If both <em>address</em> and <em>street</em> are not null,
* the pointer is actual.
* If <em>address</em> is not null, but <em>street</em> is null,
* the pointer is still actual.
* If <em>address</em> is null, the pointer is not actual.
* (In JavaBeans) if <em>address</em> is not a property of the root bean,
* a Pointer for this path cannot be obtained at all - actual or otherwise.
*/
public boolean isActual() {
if (index == WHOLE_COLLECTION) {
return true;
}
else {
return index >= 0 && index < getLength();
}
}
/**
* Returns the name of this node. Can be null.
*/
public abstract QName getName();
/**
* Returns the value represented by the pointer before indexing.
* So, if the node represents an element of a collection, this
* method returns the collection itself.
*/
public abstract Object getBaseValue();
/**
* Returns the object the pointer points to; does not convert it
* to a "canonical" type.
*
* @deprecated 1.1 Please use getNode()
*/
public Object getNodeValue() {
return getNode();
}
/**
* Returns the object the pointer points to; does not convert it
* to a "canonical" type. Opens containers, properties etc and returns
* the ultimate contents.
*/
public Object getNode() {
return getValuePointer().getImmediateNode();
}
public Object getRootNode() {
if (rootNode == null) {
if (parent != null) {
rootNode = parent.getRootNode();
}
else {
rootNode = getImmediateNode();
}
}
return rootNode;
}
/**
* Returns the object the pointer points to; does not convert it
* to a "canonical" type.
*/
public abstract Object getImmediateNode();
/**
* Converts the value to the required type and changes the corresponding
* object to that value.
*/
public abstract void setValue(Object value);
/**
* Compares two child NodePointers and returns a positive number,
* zero or a positive number according to the order of the pointers.
*/
public abstract int compareChildNodePointers(
NodePointer pointer1, NodePointer pointer2);
/**
* Checks if this Pointer matches the supplied NodeTest.
*/
public boolean testNode(NodeTest test) {
if (test == null) {
return true;
}
else if (test instanceof NodeNameTest) {
if (isContainer()) {
return false;
}
NodeNameTest nodeNameTest = (NodeNameTest) test;
QName testName = nodeNameTest.getNodeName();
QName nodeName = getName();
if (nodeName == null) {
return false;
}
String testPrefix = testName.getPrefix();
String nodePrefix = nodeName.getPrefix();
if (!equalStrings(testPrefix, nodePrefix)) {
String testNS = getNamespaceURI(testPrefix);
String nodeNS = getNamespaceURI(nodePrefix);
if (!equalStrings(testNS, nodeNS)) {
return false;
}
}
if (nodeNameTest.isWildcard()) {
return true;
}
return testName.getName().equals(nodeName.getName());
}
else if (test instanceof NodeTypeTest) {
if (((NodeTypeTest) test).getNodeType()
== Compiler.NODE_TYPE_NODE) {
return isNode();
}
}
return false;
}
private static boolean equalStrings(String s1, String s2) {
if (s1 == null && s2 != null) {
return false;
}
if (s1 != null && !s1.equals(s2)) {
return false;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?