| /* |
| * 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.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; |
| |
| import org.apache.commons.jxpath.util.KeyManagerUtils; |
| |
| /** |
| * 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 |
| * {@link 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() < 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) && 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://commons.apache.org/jxpath/users-guide.html"> |
| * JXPath User's Guide</a> |
| * |
| * |
| * @author Dmitri Plotnikov |
| * @version $Revision$ $Date$ |
| */ |
| public abstract class JXPathContext { |
| private static JXPathContextFactory contextFactory; |
| private static JXPathContext compilationContext; |
| |
| private static final PackageFunctions GENERIC_FUNCTIONS = |
| new PackageFunctions("", null); |
| |
| /** parent context */ |
| protected JXPathContext parentContext; |
| /** context bean */ |
| protected Object contextBean; |
| /** variables */ |
| protected Variables vars; |
| /** functions */ |
| protected Functions functions; |
| /** AbstractFactory */ |
| protected AbstractFactory factory; |
| /** IdentityManager */ |
| protected IdentityManager idManager; |
| /** KeyManager */ |
| protected KeyManager keyManager; |
| /** decimal format map */ |
| protected HashMap decimalFormats; |
| |
| private Locale locale; |
| private boolean lenientSet = false; |
| private boolean lenient = false; |
| |
| /** |
| * Creates a new JXPathContext with the specified object as the root node. |
| * @param contextBean Object |
| * @return JXPathContext |
| */ |
| 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. |
| * @param parentContext parent context |
| * @param contextBean Object |
| * @return JXPathContext |
| */ |
| public static JXPathContext newContext( |
| JXPathContext parentContext, |
| Object contextBean) { |
| return getContextFactory().newContext(parentContext, contextBean); |
| } |
| |
| /** |
| * Acquires a context factory and caches it. |
| * @return JXPathContextFactory |
| */ |
| 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. |
| * @param parentContext parent context |
| * @param contextBean Object |
| */ |
| protected JXPathContext(JXPathContext parentContext, Object contextBean) { |
| this.parentContext = parentContext; |
| this.contextBean = contextBean; |
| } |
| |
| /** |
| * Returns the parent context of this context or null. |
| * @return JXPathContext |
| */ |
| public JXPathContext getParentContext() { |
| return parentContext; |
| } |
| |
| /** |
| * Returns the JavaBean associated with this context. |
| * @return Object |
| */ |
| public Object getContextBean() { |
| return contextBean; |
| } |
| |
| /** |
| * Returns a Pointer for the context bean. |
| * @return Pointer |
| */ |
| public abstract Pointer getContextPointer(); |
| |
| /** |
| * Returns a JXPathContext that is relative to the current JXPathContext. |
| * The supplied pointer becomes the context pointer of the new context. |
| * The relative context inherits variables, extension functions, locale etc |
| * from the parent context. |
| * @param pointer Pointer |
| * @return JXPathContext |
| */ |
| public abstract JXPathContext getRelativeContext(Pointer pointer); |
| |
| /** |
| * Installs a custom implementation of the Variables interface. |
| * @param vars Variables |
| */ |
| public void setVariables(Variables vars) { |
| this.vars = vars; |
| } |
| |
| /** |
| * Returns the variable pool associated with the context. If no such |
| * pool was specified with the {@link #setVariables} method, |
| * returns the default implementation of Variables, |
| * {@link BasicVariables BasicVariables}. |
| * @return Variables |
| */ |
| public Variables getVariables() { |
| if (vars == null) { |
| vars = new BasicVariables(); |
| } |
| return vars; |
| } |
| |
| /** |
| * Install a library of extension functions. |
| * @param functions Functions |
| * @see FunctionLibrary |
| */ |
| public void setFunctions(Functions functions) { |
| this.functions = functions; |
| } |
| |
| /** |
| * Returns the set of functions installed on the context. |
| * @return Functions |
| */ |
| public Functions getFunctions() { |
| if (functions != null) { |
| return functions; |
| } |
| if (parentContext == null) { |
| return GENERIC_FUNCTIONS; |
| } |
| return null; |
| } |
| |
| /** |
| * Install an abstract factory that should be used by the |
| * <code>createPath()</code> and <code>createPathAndSetValue()</code> |
| * methods. |
| * @param factory AbstractFactory |
| */ |
| public void setFactory(AbstractFactory factory) { |
| this.factory = factory; |
| } |
| |
| /** |
| * Returns the AbstractFactory installed on this context. |
| * If none has been installed and this context has a parent context, |
| * returns the parent's factory. Otherwise returns null. |
| * @return AbstractFactory |
| */ |
| public AbstractFactory getFactory() { |
| if (factory == null && parentContext != null) { |
| return parentContext.getFactory(); |
| } |
| return factory; |
| } |
| |
| /** |
| * Set the locale for this context. The value of the "lang" |
| * attribute as well as the the lang() function will be |
| * affected by the locale. By default, JXPath uses |
| * <code>Locale.getDefault()</code> |
| * @param locale Locale |
| */ |
| public synchronized void setLocale(Locale locale) { |
| this.locale = locale; |
| } |
| |
| /** |
| * Returns the locale set with setLocale. If none was set and |
| * the context has a parent, returns the parent's locale. |
| * Otherwise, returns Locale.getDefault(). |
| * @return Locale |
| */ |
| public synchronized Locale getLocale() { |
| if (locale == null) { |
| if (parentContext != null) { |
| return parentContext.getLocale(); |
| } |
| locale = Locale.getDefault(); |
| } |
| return locale; |
| } |
| |
| /** |
| * Sets {@link DecimalFormatSymbols} for a given name. The DecimalFormatSymbols |
| * can be referenced as the third, optional argument in the invocation of |
| * <code>format-number (number,format,decimal-format-name)</code> function. |
| * By default, JXPath uses the symbols for the current locale. |
| * |
| * @param name the format name or null for default format. |
| * @param symbols DecimalFormatSymbols |
| */ |
| public synchronized void setDecimalFormatSymbols(String name, |
| DecimalFormatSymbols symbols) { |
| if (decimalFormats == null) { |
| decimalFormats = new HashMap(); |
| } |
| decimalFormats.put(name, symbols); |
| } |
| |
| /** |
| * Get the named DecimalFormatSymbols. |
| * @param name key |
| * @return DecimalFormatSymbols |
| * @see #setDecimalFormatSymbols(String, DecimalFormatSymbols) |
| */ |
| public synchronized DecimalFormatSymbols getDecimalFormatSymbols(String name) { |
| if (decimalFormats == null) { |
| return parentContext == null ? null : parentContext.getDecimalFormatSymbols(name); |
| } |
| return (DecimalFormatSymbols) decimalFormats.get(name); |
| } |
| |
| /** |
| * If the context is in the lenient mode, then getValue() returns null |
| * for inexistent paths. Otherwise, a path that does not map to |
| * an existing property will throw an exception. Note that if the |
| * property exists, but its value is null, the exception is <i>not</i> |
| * thrown. |
| * <p> |
| * By default, lenient = false |
| * @param lenient flag |
| */ |
| public synchronized void setLenient(boolean lenient) { |
| this.lenient = lenient; |
| lenientSet = true; |
| } |
| |
| /** |
| * Learn whether this JXPathContext is lenient. |
| * @return boolean |
| * @see #setLenient(boolean) |
| */ |
| public synchronized boolean isLenient() { |
| if (!lenientSet && parentContext != null) { |
| return parentContext.isLenient(); |
| } |
| return lenient; |
| } |
| |
| /** |
| * Compiles the supplied XPath and returns an internal representation |
| * of the path that can then be evaluated. Use CompiledExpressions |
| * when you need to evaluate the same expression multiple times |
| * and there is a convenient place to cache CompiledExpression |
| * between invocations. |
| * @param xpath to compile |
| * @return CompiledExpression |
| */ |
| public static CompiledExpression compile(String xpath) { |
| if (compilationContext == null) { |
| compilationContext = JXPathContext.newContext(null); |
| } |
| return compilationContext.compilePath(xpath); |
| } |
| |
| /** |
| * Overridden by each concrete implementation of JXPathContext |
| * to perform compilation. Is called by <code>compile()</code>. |
| * @param xpath to compile |
| * @return CompiledExpression |
| */ |
| protected abstract CompiledExpression compilePath(String xpath); |
| |
| /** |
| * Finds the first object that matches the specified XPath. It is equivalent |
| * to <code>getPointer(xpath).getNode()</code>. Note that this method |
| * produces the same result as <code>getValue()</code> on object models |
| * like JavaBeans, but a different result for DOM/JDOM etc., because it |
| * returns the Node itself, rather than its textual contents. |
| * |
| * @param xpath the xpath to be evaluated |
| * @return the found object |
| */ |
| public Object selectSingleNode(String xpath) { |
| Pointer pointer = getPointer(xpath); |
| return pointer == null ? null : pointer.getNode(); |
| } |
| |
| /** |
| * Finds all nodes that match the specified XPath. |
| * |
| * @param xpath the xpath to be evaluated |
| * @return a list of found objects |
| */ |
| public List selectNodes(String xpath) { |
| ArrayList list = new ArrayList(); |
| Iterator iterator = iteratePointers(xpath); |
| while (iterator.hasNext()) { |
| Pointer pointer = (Pointer) iterator.next(); |
| list.add(pointer.getNode()); |
| } |
| return list; |
| } |
| |
| /** |
| * Evaluates the xpath and returns the resulting object. Primitive |
| * types are wrapped into objects. |
| * @param xpath to evaluate |
| * @return Object found |
| */ |
| public abstract Object getValue(String xpath); |
| |
| /** |
| * Evaluates the xpath, converts the result to the specified class and |
| * returns the resulting object. |
| * @param xpath to evaluate |
| * @param requiredType required type |
| * @return Object found |
| */ |
| public abstract Object getValue(String xpath, Class requiredType); |
| |
| /** |
| * Modifies the value of the property described by the supplied xpath. |
| * Will throw an exception if one of the following conditions occurs: |
| * <ul> |
| * <li>The xpath does not in fact describe an existing property |
| * <li>The property is not writable (no public, non-static set method) |
| * </ul> |
| * @param xpath indicating position |
| * @param value to set |
| */ |
| public abstract void setValue(String xpath, Object value); |
| |
| /** |
| * Creates missing elements of the path by invoking an {@link AbstractFactory}, |
| * which should first be installed on the context by calling {@link #setFactory}. |
| * <p> |
| * Will throw an exception if the AbstractFactory fails to create |
| * an instance for a path element. |
| * @param xpath indicating destination to create |
| * @return pointer to new location |
| */ |
| public abstract Pointer createPath(String xpath); |
| |
| /** |
| * The same as setValue, except it creates intermediate elements of |
| * the path by invoking an {@link AbstractFactory}, which should first be |
| * installed on the context by calling {@link #setFactory}. |
| * <p> |
| * Will throw an exception if one of the following conditions occurs: |
| * <ul> |
| * <li>Elements of the xpath aleady exist, but the path does not in |
| * fact describe an existing property |
| * <li>The AbstractFactory fails to create an instance for an intermediate |
| * element. |
| * <li>The property is not writable (no public, non-static set method) |
| * </ul> |
| * @param xpath indicating position to create |
| * @param value to set |
| * @return pointer to new location |
| */ |
| public abstract Pointer createPathAndSetValue(String xpath, Object value); |
| |
| /** |
| * Removes the element of the object graph described by the xpath. |
| * @param xpath indicating position to remove |
| */ |
| public abstract void removePath(String xpath); |
| |
| /** |
| * Removes all elements of the object graph described by the xpath. |
| * @param xpath indicating positions to remove |
| */ |
| public abstract void removeAll(String xpath); |
| |
| /** |
| * Traverses the xpath and returns an Iterator of all results found |
| * for the path. If the xpath matches no properties |
| * in the graph, the Iterator will be empty, but not null. |
| * @param xpath to iterate |
| * @return Iterator<Object> |
| */ |
| public abstract Iterator iterate(String xpath); |
| |
| /** |
| * Traverses the xpath and returns a Pointer. |
| * A Pointer provides easy access to a property. |
| * If the xpath matches no properties |
| * in the graph, the pointer will be null. |
| * @param xpath desired |
| * @return Pointer |
| */ |
| public abstract Pointer getPointer(String xpath); |
| |
| /** |
| * Traverses the xpath and returns an Iterator of Pointers. |
| * A Pointer provides easy access to a property. |
| * If the xpath matches no properties |
| * in the graph, the Iterator be empty, but not null. |
| * @param xpath to iterate |
| * @return Iterator<Pointer> |
| */ |
| public abstract Iterator iteratePointers(String xpath); |
| |
| /** |
| * Install an identity manager that will be used by the context |
| * to look up a node by its ID. |
| * @param idManager IdentityManager to set |
| */ |
| public void setIdentityManager(IdentityManager idManager) { |
| this.idManager = idManager; |
| } |
| |
| /** |
| * Returns this context's identity manager. If none has been installed, |
| * returns the identity manager of the parent context. |
| * @return IdentityManager |
| */ |
| public IdentityManager getIdentityManager() { |
| if (idManager == null && parentContext != null) { |
| return parentContext.getIdentityManager(); |
| } |
| return idManager; |
| } |
| |
| /** |
| * Locates a Node by its ID. |
| * |
| * @param id is the ID of the sought node. |
| * @return Pointer |
| */ |
| public Pointer getPointerByID(String id) { |
| IdentityManager manager = getIdentityManager(); |
| if (manager != null) { |
| return manager.getPointerByID(this, id); |
| } |
| throw new JXPathException( |
| "Cannot find an element by ID - " |
| + "no IdentityManager has been specified"); |
| } |
| |
| /** |
| * Install a key manager that will be used by the context |
| * to look up a node by a key value. |
| * @param keyManager KeyManager |
| */ |
| public void setKeyManager(KeyManager keyManager) { |
| this.keyManager = keyManager; |
| } |
| |
| /** |
| * Returns this context's key manager. If none has been installed, |
| * returns the key manager of the parent context. |
| * @return KeyManager |
| */ |
| public KeyManager getKeyManager() { |
| if (keyManager == null && parentContext != null) { |
| return parentContext.getKeyManager(); |
| } |
| return keyManager; |
| } |
| |
| /** |
| * Locates a Node by a key value. |
| * @param key string |
| * @param value string |
| * @return Pointer found |
| */ |
| public Pointer getPointerByKey(String key, String value) { |
| KeyManager manager = getKeyManager(); |
| if (manager != null) { |
| return manager.getPointerByKey(this, key, value); |
| } |
| throw new JXPathException( |
| "Cannot find an element by key - " |
| + "no KeyManager has been specified"); |
| } |
| |
| /** |
| * Locates a NodeSet by key/value. |
| * @param key string |
| * @param value object |
| * @return NodeSet found |
| */ |
| public NodeSet getNodeSetByKey(String key, Object value) { |
| KeyManager manager = getKeyManager(); |
| if (manager != null) { |
| return KeyManagerUtils.getExtendedKeyManager(manager) |
| .getNodeSetByKey(this, key, value); |
| } |
| throw new JXPathException("Cannot find an element by key - " |
| + "no KeyManager has been specified"); |
| } |
| |
| /** |
| * Registers a namespace prefix. |
| * |
| * @param prefix A namespace prefix |
| * @param namespaceURI A URI for that prefix |
| */ |
| public void registerNamespace(String prefix, String namespaceURI) { |
| throw new UnsupportedOperationException( |
| "Namespace registration is not implemented by " + getClass()); |
| } |
| |
| /** |
| * Given a prefix, returns a registered namespace URI. If the requested |
| * prefix was not defined explicitly using the registerNamespace method, |
| * JXPathContext will then check the context node to see if the prefix is |
| * defined there. See |
| * {@link #setNamespaceContextPointer(Pointer) setNamespaceContextPointer}. |
| * |
| * @param prefix The namespace prefix to look up |
| * @return namespace URI or null if the prefix is undefined. |
| */ |
| public String getNamespaceURI(String prefix) { |
| throw new UnsupportedOperationException( |
| "Namespace registration is not implemented by " + getClass()); |
| } |
| |
| /** |
| * Get the prefix associated with the specifed namespace URI. |
| * @param namespaceURI the ns URI to check. |
| * @return String prefix |
| * @since JXPath 1.3 |
| */ |
| public String getPrefix(String namespaceURI) { |
| throw new UnsupportedOperationException( |
| "Namespace registration is not implemented by " + getClass()); |
| } |
| |
| /** |
| * Namespace prefixes can be defined implicitly by specifying a pointer to a |
| * context where the namespaces are defined. By default, |
| * NamespaceContextPointer is the same as the Context Pointer, see |
| * {@link #getContextPointer() getContextPointer()} |
| * |
| * @param namespaceContextPointer The pointer to the context where prefixes used in |
| * XPath expressions should be resolved. |
| */ |
| public void setNamespaceContextPointer(Pointer namespaceContextPointer) { |
| throw new UnsupportedOperationException( |
| "Namespace registration is not implemented by " + getClass()); |
| } |
| |
| /** |
| * Returns the namespace context pointer set with |
| * {@link #setNamespaceContextPointer(Pointer) setNamespaceContextPointer()} |
| * or, if none has been specified, the context pointer otherwise. |
| * |
| * @return The namespace context pointer. |
| */ |
| public Pointer getNamespaceContextPointer() { |
| throw new UnsupportedOperationException( |
| "Namespace registration is not implemented by " + getClass()); |
| } |
| |
| } |