jxpathcontext.java

来自「JXPath」· Java 代码 · 共 863 行 · 第 1/2 页

JAVA
863
字号
/*
 * 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;

import java.text.DecimalFormatSymbols;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

/**
 * JXPathContext  provides APIs for the traversal of graphs of JavaBeans using
 * the XPath syntax. Using JXPathContext, you can read and write properties of
 * JavaBeans, arrays, collections and maps. JXPathContext uses JavaBeans
 * introspection to enumerate and access JavaBeans properties.
 * <p>
 * JXPathContext  allows alternative implementations. This is why instead of
 * allocating JXPathContext directly, you should call a static
 * <code>newContext</code> method.  This method will utilize the
 * JXPathContextFactory API to locate a suitable implementation of JXPath.
 * Bundled with JXPath comes a default implementation called Reference
 * Implementation.
 * </p>
 *
 * <h2>JXPath Interprets XPath Syntax on Java Object Graphs</h2>
 *
 * JXPath uses an intuitive interpretation of the xpath syntax in the context
 * of Java object graphs. Here are some examples:
 *
 * <h3>Example 1: JavaBean Property Access</h3>
 *
 * JXPath can be used to access properties of a JavaBean.
 *
 * <pre><blockquote>
 * public class Employee {
 *    public String getFirstName(){
 *       ...
 *    }
 * }
 *
 * Employee emp = new Employee();
 * ...
 *
 * JXPathContext context = JXPathContext.newContext(emp);
 * String fName = (String)context.getValue("firstName");
 * </blockquote></pre>
 *
 * In  this example, we are using JXPath to access a property of the
 * <code>emp</code> bean. In this simple case the invocation of JXPath is
 * equivalent to invocation of getFirstName() on the bean.
 *
 * <h3>Example 2: Nested Bean Property Access</h3>
 * JXPath can traverse object graphs:
 *
 * <pre><blockquote>
 * public class Employee {
 *    public Address getHomeAddress(){
 *       ...
 *    }
 * }
 * public class Address {
 *    public String getStreetNumber(){
 *       ...
 *    }
 * }
 *
 * Employee emp = new Employee();
 * ...
 *
 * JXPathContext context = JXPathContext.newContext(emp);
 * String sNumber = (String)context.getValue("homeAddress/streetNumber");
 * </blockquote></pre>
 *
 * In this case XPath is used to access a property of a nested bean.
 * <p>
 * A property identified by the xpath does not have to be a "leaf" property.
 * For instance, we can extract the whole Address object in above example:
 *
 * <pre><blockquote>
 *    Address addr = (Address)context.getValue("homeAddress");
 * </blockquote></pre>
 * </p>
 *
 * <h3>Example 3: Collection Subscripts</h3>
 * JXPath can extract elements from arrays and collections.
 *
 * <pre><blockquote>
 * public class Integers {
 *    public int[] getNumbers(){
 *       ...
 *    }
 * }
 *
 * Integers ints = new Integers();
 * ...
 *
 * JXPathContext context = JXPathContext.newContext(ints);
 * Integer thirdInt = (Integer)context.getValue("numbers[3]");
 * </blockquote></pre>
 * A  collection can be an arbitrary array or an instance of java.util.
 * Collection.
 * <p>
 * Note: in XPath the first element of a collection has index 1, not 0.<br>
 *
 * <h3>Example 4: Map Element Access</h3>
 *
 * JXPath supports maps. To get a value use its key.
 *
 * <pre><blockquote>
 * public class Employee {
 *    public Map getAddresses(){
 *       return addressMap;
 *    }
 *
 *    public void addAddress(String key, Address address){
 *       addressMap.put(key, address);
 *    }
 *    ...
 * }
 *
 * Employee emp = new Employee();
 * emp.addAddress("home", new Address(...));
 * emp.addAddress("office", new Address(...));
 * ...
 *
 * JXPathContext context = JXPathContext.newContext(emp);
 * String homeZipCode = (String)context.getValue("addresses/home/zipCode");
 * </blockquote></pre>
 *
 * Often you will need to use the alternative syntax for accessing Map
 * elements:
 *
 * <pre><blockquote>
 * String homeZipCode = 
 *     (String) context.getValue("addresses[@name='home']/zipCode");
 * </blockquote></pre>
 *
 * In this case, the key can be an expression, e.g. a variable.<br>
 *
 * Note: At this point JXPath only supports Maps that use strings for keys.<br>
 * Note: JXPath supports the extended notion of Map: any object with
 *       dynamic properties can be handled by JXPath provided that its
 *       class is registered with the {@link JXPathIntrospector}.
 *
 * <h3>Example 5: Retrieving Multiple Results</h3>
 *
 * JXPath can retrieve multiple objects from a graph. Note that the method
 * called in this case is not <code>getValue</code>, but <code>iterate</code>.
 *
 * <pre><blockquote>
 * public class Author {
 *    public Book[] getBooks(){
 *       ...
 *    }
 * }
 *
 * Author auth = new Author();
 * ...
 *
 * JXPathContext context = JXPathContext.newContext(auth);
 * Iterator threeBooks = context.iterate("books[position() &lt; 4]");
 * </blockquote></pre>
 *
 * This returns a list of at most three books from the array of all books
 * written by the author.
 *
 * <h3>Example 6: Setting Properties</h3>
 * JXPath can be used to modify property values.
 *
 * <pre><blockquote>
 * public class Employee {
 *    public Address getAddress() {
 *       ...
 *    }
 *
 *    public void setAddress(Address address) {
 *       ...
 *    }
 * }
 *
 * Employee emp = new Employee();
 * Address addr = new Address();
 * ...
 *
 * JXPathContext context = JXPathContext.newContext(emp);
 * context.setValue("address", addr);
 * context.setValue("address/zipCode", "90190");
 *
 * </blockquote></pre>
 *
 * <h3>Example 7: Creating objects</h3>
 * JXPath  can be used to create new objects. First, create a subclass of {@link
 * AbstractFactory AbstractFactory} and install it on the JXPathContext. Then
 * call {@link JXPathContext#createPath createPathAndSetValue()} instead of
 * "setValue". JXPathContext will invoke your AbstractFactory when it discovers
 * that an intermediate node of the path is <b>null</b>.  It will not override
 * existing nodes.
 *
 * <pre><blockquote>
 * public class AddressFactory extends AbstractFactory {
 *    public boolean createObject(JXPathContext context, 
 *               Pointer pointer, Object parent, String name, int index){
 *     if ((parent instanceof Employee) &amp;&amp; name.equals("address"){
 *       ((Employee)parent).setAddress(new Address());
 *       return true;
 *     }
 *     return false;
 *   }
 * }
 *
 * JXPathContext context = JXPathContext.newContext(emp);
 * context.setFactory(new AddressFactory());
 * context.createPathAndSetValue("address/zipCode", "90190");
 * </blockquote></pre>
 *
 * <h3>Example 8: Using Variables</h3>
 * JXPath supports the notion of variables. The XPath syntax for accessing
 * variables is <i>"$varName"</i>.
 *
 * <pre><blockquote>
 * public class Author {
 *    public Book[] getBooks(){
 *       ...
 *    }
 * }
 *
 * Author auth = new Author();
 * ...
 *
 * JXPathContext context = JXPathContext.newContext(auth);
 * context.getVariables().declareVariable("index", new Integer(2));
 *
 * Book secondBook = (Book)context.getValue("books[$index]");
 * </blockquote></pre>
 *
 * You can also set variables using JXPath:
 *
 * <pre><blockquote>
 * context.setValue("$index", new Integer(3));
 * </blockquote></pre>
 *
 * Note: you can only <i>change</i> the value of an existing variable this
 * way, you cannot <i>define</i> a new variable.
 *
 * <p>
 * When a variable contains a JavaBean or a collection, you can
 * traverse the bean or collection as well:
 * <pre><blockquote>
 * ...
 * context.getVariables().declareVariable("book", myBook);
 * String title = (String)context.getValue("$book/title);
 *
 * Book array[] = new Book[]{...};
 *
 * context.getVariables().declareVariable("books", array);
 *
 * String title = (String)context.getValue("$books[2]/title);
 * </blockquote></pre>
 *
 * <h3>Example 9: Using Nested Contexts</h3>
 * If  you need to use the same set of variable while interpreting XPaths with
 * different beans, it makes sense to put the variables in a separate context
 * and specify that context as a parent context every time you allocate a new
 * JXPathContext for a JavaBean.
 *
 * <pre><blockquote>
 * JXPathContext varContext = JXPathContext.newContext(null);
 * varContext.getVariables().declareVariable("title", "Java");
 *
 * JXPathContext context = JXPathContext.newContext(varContext, auth);
 *
 * Iterator javaBooks = context.iterate("books[title = $title]");
 * </blockquote></pre>
 *
 * <h3>Using Custom Variable Pools</h3>
 * By default, JXPathContext creates a HashMap of variables. However,
 * you can substitute a custom implementation of the Variables
 * interface to make JXPath work with an alternative source of variables.
 * For example, you can define implementations of Variables that
 * cover a servlet context, HTTP request or any similar structure.
 *
 * <h3>Example 10: Using Standard Extension Functions</h3>
 * Using the standard extension functions, you can call methods on objects,
 * static methods on classes and create objects using any constructor.
 * The class names should be fully qualified.
 * <p>
 * Here's how you can create new objects:
 * <pre><blockquote>
 * Book book = 
 *    (Book) context.getValue(
 *         "org.apache.commons.jxpath.example.Book.new ('John Updike')");
 * </blockquote></pre>
 *
 * Here's how you can call static methods:
 * <pre><blockquote>
 *   Book book = 
 *    (Book) context.getValue( 
 *       "org. apache.commons.jxpath.example.Book.getBestBook('John Updike')");
 * </blockquote></pre>
 *
 * Here's how you can call regular methods:
 * <pre><blockquote>
 * String firstName = (String)context.getValue("getAuthorsFirstName($book)");
 * </blockquote></pre>
 * As you can see, the target of the method is specified as the first parameter
 * of the function.
 *
 * <h3>Example 11: Using Custom Extension Functions</h3>
 * Collections of custom extension functions can be implemented
 * as {@link Functions Functions} objects or as Java classes, whose methods
 * become extenstion functions.
 * <p>
 * Let's say the following class implements various formatting operations:
 * <pre><blockquote>
 * public class Formats {
 *    public static String date(Date d, String pattern){
 *        return new SimpleDateFormat(pattern).format(d);
 *    }
 *    ...
 * }
 * </blockquote></pre>
 *
 * We can register this class with a JXPathContext:
 *
 * <pre><blockquote>
 * context.setFunctions(new ClassFunctions(Formats.class, "format"));
 * ...
 *
 * context.getVariables().declareVariable("today", new Date());
 * String today = (String)context.getValue("format:date($today, 'MM/dd/yyyy')");
 *
 * </blockquote></pre>
 * You can also register whole packages of Java classes using PackageFunctions.
 * <p>
 * Also, see {@link FunctionLibrary FunctionLibrary}, which is a class
 * that allows you to register multiple sets of extension functions with
 * the same JXPathContext.
 *
 * <h2>Configuring JXPath</h2>
 *
 * JXPath uses JavaBeans introspection to discover properties of JavaBeans.
 * You can provide alternative property lists by supplying
 * custom JXPathBeanInfo classes (see {@link JXPathBeanInfo JXPathBeanInfo}).
 *
 * <h2>Notes</h2>
 * <ul>
 * <li> JXPath does not support DOM attributes for non-DOM objects. Even though
 * XPaths like "para[@type='warning']" are legitimate, they will always produce
 * empty results. The only attribute supported for JavaBeans is "name".  The
 * XPath "foo/bar" is equivalent to "foo[@name='bar']".
 * </ul>
 *
 * See  <a href="http://www.w3schools.com/xpath">XPath Tutorial by
 * W3Schools</a><br>. Also see <a href="http://www.w3.org/TR/xpath">XML Path
 * Language (XPath) Version 1.0</a><br><br> 
 * 
 * You will also find more information and examples in
 * <a href="http://jakarta.apache.org/commons/jxpath/users-guide.html">
 * JXPath User's Guide</a>
 *
 *
 * @author Dmitri Plotnikov
 * @version $Revision: 1.25 $ $Date: 2004/06/29 21:15:46 $
 */
public abstract class JXPathContext {
    protected JXPathContext parentContext;
    protected Object contextBean;
    protected Variables vars;
    protected Functions functions;
    protected AbstractFactory factory;
    private Locale locale;
    private boolean lenientSet = false;
    private boolean lenient = false;
    protected IdentityManager idManager;
    protected KeyManager keyManager;
    protected HashMap decimalFormats;

    private static JXPathContextFactory contextFactory;
    private static JXPathContext compilationContext;
    
    private static final PackageFunctions GENERIC_FUNCTIONS =
        new PackageFunctions("", null);

    /**
     * Creates a new JXPathContext with the specified object as the root node.
     */
    public static JXPathContext newContext(Object contextBean) {
        return getContextFactory().newContext(null, contextBean);
    }

    /**
     * Creates a new JXPathContext with the specified bean as the root node and
     * the specified parent context. Variables defined in a parent context can
     * be referenced in XPaths passed to the child context.
     */
    public static JXPathContext newContext(
        JXPathContext parentContext,
        Object contextBean) 
    {
        return getContextFactory().newContext(parentContext, contextBean);
    }

    /**
     * Acquires a context factory and caches it. 
     */
    private static JXPathContextFactory getContextFactory () {
        if (contextFactory == null) {
            contextFactory = JXPathContextFactory.newInstance();            
        }
        return contextFactory;
    }
    
    /**
     * This  constructor should remain protected - it is to be overridden by
     * subclasses, but never explicitly invoked by clients.
     */
    protected JXPathContext(JXPathContext parentContext, Object contextBean) {
        this.parentContext = parentContext;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?