| <?xml version="1.0" encoding="UTF-8"?> |
| <!-- |
| 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. |
| --> |
| <document> |
| <properties> |
| <title> |
| JXPath User's Guide |
| </title> |
| <author email="dmitri@apache.org"> |
| Dmitri Plotnikov |
| </author> |
| </properties> |
| |
| <body> |
| <section name="What's JXPath"> |
| <p> |
| JXPath provides APIs for traversal of graphs of JavaBeans, |
| DOM and other types of objects using the XPath syntax. |
| </p> |
| <p> |
| If you are not familiar with the XPath syntax, start with |
| <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> - |
| that's the official standard. |
| </p> |
| <p> |
| XPath is the official expression language of XSLT. In XSLT, you |
| mostly use XPath to access various elements of XML documents. |
| You can do that with JXPath as well. In addition, you can read |
| and write properties of JavaBeans, get and set elements of |
| arrays, collections, maps, transparent containers, various |
| context objects in Servlets etc. In other words, JXPath applies |
| the concepts of XPath to alternate object models. |
| </p> |
| <p> |
| You can also have JXPath create new objects if needed. |
| </p> |
| <p> |
| The central class in the JXPath architecture is |
| <a href="apidocs/org/apache/commons/jxpath/JXPathContext.html"><code>JXPathContext</code></a>. |
| Most of the APIs discussed in this document have to do with the |
| JXPathContext class. |
| </p> |
| <ul> |
| <li><a href="#Object Graph Traversal">Object Graph Traversal</a> |
| <ul> |
| <li><a href="#JavaBean Property Access">JavaBean Property Access</a> |
| </li> |
| <li><a href="#Lenient Mode">Lenient Mode</a> |
| </li> |
| <li><a href="#Nested Bean Property Access">Nested Bean Property Access</a> |
| </li> |
| <li><a href="#Collection Subscripts">Collection Subscripts</a> |
| </li> |
| <li><a href="#Retrieving Multiple Results">Retrieving Multiple Results</a> |
| </li> |
| <li><a href="#Map Element Access">Map Element Access</a> |
| </li> |
| <li><a href="#DOM/JDOM Document Access">DOM/JDOM Document Access</a> |
| </li> |
| <li><a href="#Registering Namespaces">Registering Namespaces</a> |
| </li> |
| <li><a href="#Containers">Containers</a> |
| </li> |
| <li><a href="#Functions id() and key()">Functions id() and key()</a> |
| </li> |
| </ul> |
| </li> |
| <li><a href="#XPath Axes And Object Graphs">XPath Axes And Object Graphs</a> |
| <ul> |
| <li><a href="#Parent/child Relationship">Parent/child Relationship</a> |
| </li> |
| <li><a href="#Document Order">Document Order</a> |
| </li> |
| <li><a href="#Attributes">Attributes</a> |
| </li> |
| </ul> |
| </li> |
| <li><a href="#Exceptions During XPath Evaluation">Exceptions During XPath Evaluation</a> |
| </li> |
| <li><a href="#Modifying Object Graphs">Modifying Object Graphs</a> |
| <ul> |
| <li><a href="#Setting Properties">Setting Properties</a> |
| </li> |
| <li><a href="#Creating Objects">Creating Objects</a> |
| </li> |
| </ul> |
| </li> |
| <li><a href="#Variables">Variables</a> |
| <ul> |
| <li><a href="#Custom Variable Pools">Custom Variable Pools</a> |
| </li> |
| </ul> |
| </li> |
| <li><a href="#Servlet Contexts">Servlet Contexts</a> |
| <ul> |
| <li><a href="#JSP Page Context">JSP Page Context</a> |
| </li> |
| <li><a href="#Servlet Request Context">Servlet Request Context</a> |
| </li> |
| <li><a href="#HttpSession Context">HttpSession Context</a> |
| </li> |
| <li><a href="#ServletContext Context">ServletContext Context</a> |
| </li> |
| </ul> |
| </li> |
| <li><a href="#Pointers">Pointers</a> |
| </li> |
| <li><a href="#Relative Contexts">Relative Contexts</a> |
| </li> |
| <li><a href="#Extension Functions">Extension Functions</a> |
| <ul> |
| <li><a href="#Standard Extension Functions">Standard Extension Functions</a> |
| </li> |
| <li><a href="#Custom Extension Functions">Custom Extension Functions</a> |
| </li> |
| <li><a href="#Expression Context">Expression Context</a> |
| </li> |
| <li><a href="#Collections as Arguments">Collections as Arguments</a> |
| </li> |
| <li><a href="#Collection as the Return Value">Collection as the Return Value</a> |
| </li> |
| </ul> |
| </li> |
| <li><a href="#Type Conversions">Type Conversions</a> |
| </li> |
| <li><a href="#Internationalization">Internationalization</a> |
| </li> |
| <li><a href="#Nested Contexts">Nested Contexts</a> |
| </li> |
| <li><a href="#Compiled Expressions">Compiled Expressions</a> |
| </li> |
| <li><a href="#Customizing JXPath">Customizing JXPath</a> |
| <ul> |
| <li><a href="#Custom JXPathBeanInfo">Custom JXPathBeanInfo</a> |
| </li> |
| <li><a href="#Custom DynamicPropertyHandler">Custom DynamicPropertyHandler</a> |
| </li> |
| <li><a href="#Custom Pointers and Iterators">Custom Pointers and Iterators</a> |
| </li> |
| <li><a href="#Alternative JXPath Implementation">Alternative JXPath Implementation</a> |
| </li> |
| </ul> |
| </li> |
| <li><a href="#Miscellaneous">Miscellaneous</a> |
| </li> |
| </ul> |
| </section> |
| |
| |
| <section name="Object Graph Traversal"> |
| <p> |
| JXPath uses JavaBeans introspection to enumerate and access |
| JavaBeans properties. |
| </p> |
| <p> |
| The interpretation of the XPath syntax in the context of Java |
| object graphs is quite intuitive: the <code>"child"</code> |
| axis of XPath is mapped to JavaBean properties. In fact, |
| the <code>"attribute:"</code> axis is mapped exactly the same way, |
| so the <code>"child::"</code> and <code>"attribute:"</code> axes |
| can be used interchangeably with JavaBeans. |
| </p> |
| |
| |
| <subsection name="JavaBean Property Access"> |
| <p> |
| JXPath can be used to access properties of a JavaBean. |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| public class Employee { |
| public String getFirstName(){ |
| ... |
| } |
| } |
| |
| Employee emp = new Employee(); |
| ... |
| |
| JXPathContext context = JXPathContext.newContext(emp); |
| String fName = (String)context.getValue("firstName"); |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| <p> |
| 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 |
| <code>getFirstName()</code> on the bean. |
| </p> |
| <p> |
| Note that using the XPath <code>"@firstName"</code> instead of |
| <code>"firstName"</code> whould produce the same result, because the |
| <code>"child::"</code> and <code>"attribute::"</code> axes are equivalent. |
| </p> |
| </subsection> |
| |
| |
| <subsection name="Lenient Mode"> |
| <p> |
| The <code>context.getValue(xpath)</code> method throws |
| an exception if the supplied xpath does not map to an |
| existing property. This constraint can be relaxed by |
| calling <code>context.setLenient(true)</code>. In the |
| lenient mode the method merely returns null if the path |
| maps to nothing. |
| </p> |
| </subsection> |
| |
| |
| <subsection name="Nested Bean Property Access"> |
| <p> |
| JXPath can traverse object graphs: |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| 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"); |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| <p> |
| In this case XPath is used to access a property of a nested |
| bean. |
| </p> |
| <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: |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| Address addr = (Address)context.getValue("homeAddress"); |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| </subsection> |
| |
| |
| <subsection name="Collection Subscripts"> |
| <p> |
| JXPath can extract elements from arrays and collections. |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| public class Integers { |
| public int[] getNumbers(){ |
| ... |
| } |
| } |
| |
| Integers ints = new Integers(); |
| ... |
| |
| JXPathContext context = JXPathContext.newContext(ints); |
| Integer thirdInt = (Integer)context.getValue("numbers[3]"); |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| <p> |
| A collection can be an arbitrary array or an instance of |
| java.util.Collection. JXPath also supports indexed properties |
| according to the JavaBeans specification. |
| </p> |
| <p><b>Note:</b> in XPath the first element of a collection has |
| index 1, not 0. |
| <br/> |
| </p> |
| </subsection> |
| |
| |
| <subsection name="Retrieving Multiple Results"> |
| <p> |
| 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>. |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| public class Author { |
| public Book[] getBooks(){ |
| ... |
| } |
| } |
| |
| Author auth = new Author(); |
| ... |
| |
| JXPathContext context = JXPathContext.newContext(auth); |
| Iterator threeBooks = context.iterate("books[position() < 4]"); |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| <p> |
| This returns an iterator over at most three books from the array |
| of all books written by the author. |
| </p> |
| </subsection> |
| |
| |
| <subsection name="Map Element Access"> |
| <p> |
| JXPath supports maps. To get a value use its key as the name in |
| a <code>child::name</code> construct. |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| public class Employee { |
| private Map addressMap = new HashMap(); |
| { |
| addressMap.put("home", new Address(...)); |
| addressMap.put("office", new Address(...)); |
| } |
| |
| public Map getAddresses(){ |
| return addressMap; |
| } |
| ... |
| } |
| |
| Employee emp = new Employee(); |
| JXPathContext context = JXPathContext.newContext(emp); |
| String homeZipCode = |
| (String)context.getValue("addresses/home/zipCode"); |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| <p> |
| Often you will need to use the alternative syntax for |
| accessing Map elements: |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| String homeZipCode = (String)context. |
| getValue("addresses[@name='home']/zipCode"); |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| <p> |
| Unlike a child name in XPath, the value of the "name" |
| attribute does |
| <em> |
| not |
| </em> |
| have to be a properly formed identifier. Also, |
| in this case the key can be an expression, e.g. a variable. |
| </p> |
| <p> |
| The attribute "name" can be used not only with Maps, but |
| with JavaBeans as well. The value of this attribute |
| represents the name of a property. |
| </p> |
| <p><b>Note:</b> At this point JXPath only supports Maps that use |
| strings for keys. |
| </p> |
| <p><b>Note:</b> JXPath supports the extended notion of Map: any |
| object similar to Map, i.e. having some kind of API for accessing |
| values by key, can be handled by JXPath |
| provided that its class is registered with the |
| <a href="apidocs/org/apache/commons/jxpath/JXPathIntrospector.html"><code>JXPathIntrospector</code></a>. |
| The term JXPath uses for such objects is "objects with Dynamic Properties". |
| </p> |
| </subsection> |
| |
| <subsection name="DynaBean Access"> |
| <p> |
| JXPath supports <a href="http://commons.apache.org/beanutils/api/org/apache/commons/beanutils/DynaBean.html">DynaBeans</a> |
| as well. DynaBeans are treated exactly the same way as JavaBeans. |
| </p> |
| </subsection> |
| |
| <subsection name="DOM/JDOM Document Access"> |
| <p> |
| JXPath supports access to DOM and JDOM Nodes. The DOM/JDOM node can be |
| the context node of JXPathContext or it can be a value of a |
| property, element of a collection, value of a variable etc. |
| Let's say we have a path <code>"$foo/bar/baz"</code>. |
| It will find the desired node if, for instance, the value of the variable |
| "foo" is a JavaBean, whose property "bar" contains a DOM/JDOM |
| Node, which has a child element named "baz". |
| </p> |
| <p> |
| The intepretation of XPath over DOM/JDOM structures is |
| implemented in accordance with the XPath specification. |
| </p> |
| </subsection> |
| |
| <subsection name="Getting a Value vs. Selecting a Node"> |
| <p> |
| JXPathContext has two similar sets of APIs: |
| <code>getValue(xpath)/iterate(xpath)</code> and |
| <code>selectSingleNode(xpath)/selectNodes(xpath)</code>. |
| With JavaBeans and similar Java object |
| models, these sets of APIs are effectively equivalent. However, with DOM/JDOM |
| there is a difference: <code>selectSingleNode(xpath)</code> and |
| <code>selectNodes(xpath)</code> return Nodes, while |
| <code>getValue()</code> and <code>iterate(xpath)</code> return textual contents |
| of those nodes. |
| </p> |
| <p> |
| Consider the following XML document: |
| </p> |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <?xml version="1.0" ?> |
| <address> |
| <street>Orchard Road</street> |
| </address> |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| <p> |
| With the same XPath, <code>getValue("/address/street")</code>, will |
| return the string <code>"Orchard Road"</code>, |
| while <code>selectSingleNode("/address/street")</code> - |
| an object of type <code>Element</code> (DOM or JDOM, depending on the |
| type of parser used). The returned <code>Element</code> is, of course, |
| <code><street>Orchard Road</street></code>. |
| </p> |
| </subsection> |
| |
| <subsection name="Registering Namespaces"> |
| <p> |
| When using namespaces, it is important to remember that XPath matches |
| qualified names (QNames) based on the namespace URI, not on the prefix. |
| Therefore the XPath |
| <code>"//foo:bar"</code> may not find a node named "foo:bar" if the prefix |
| <code>"foo"</code> in the context of the node and in the execution context |
| of the XPath are mapped to different URIs. Conversely, <code>"//foo:bar"</code> |
| will find the node named <code>"biz:bar"</code>, if <code>"foo"</code> in the |
| execution context and <code>"biz"</code> in the node context are mapped |
| to the same URI. |
| </p> |
| <p> |
| In order to use a namespace prefix with JXPath, that prefix should be |
| known to JXPathContext. JXPathContext knows about namespace prefixes |
| declared on the document element of the context node (the one passed |
| to <code>JXPathContext.newContext(node)</code>), as well as the ones |
| explicitly registered using the <a href="apidocs/org/apache/commons/jxpath/JXPathContext.html#registerNamespace(java.lang.String, java.lang.String)"> |
| <code>JXPathContext.registerNamespace(prefix, namespaceURI)</code></a> method. |
| </p> |
| </subsection> |
| |
| <subsection name="Containers"> |
| <p> |
| A <a href="apidocs/org/apache/commons/jxpath/Container.html">Container</a> |
| is an object implementing an indirection mechanism |
| transparent to JXPath. |
| </p> |
| <p> |
| For example, if property <code>"foo"</code> of the |
| context node has a Container as its value, the XPath "foo" |
| will produce the contents of that Container, not the |
| container itself. |
| </p> |
| <p> |
| An example of a useful container is |
| <a href="apidocs/org/apache/commons/jxpath/XMLDocumentContainer.html">XMLDocumentContainer</a>. |
| When you create an XMLDocumentContainer, you give it a |
| pointer to an XML file (a <code>URL</code> or a |
| <code>javax.xml.transform.Source</code>). It will read |
| and parse the XML file only when it is accessed. You can |
| create XMLDocumentContainers for various XML documents that |
| may or may not be accessed by XPaths. If they are, they |
| will be automatically read, parsed and traversed. If they |
| are not- they won't be read at all. Of course, once XMLDocumentContainer |
| has read its XML file, it will cache the parse results for |
| a future use. |
| </p> |
| <p> |
| Let's say we have the the following XML file, which is |
| stored as a Java resource. |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| <?xml version="1.0" ?> |
| <vendor> |
| <location id="store101"> |
| <address> |
| <street>Orchard Road</street> |
| </address> |
| </location> |
| |
| <location id="store102"> |
| <address> |
| <street>Tangerine Drive</street> |
| </address> |
| </location> |
| </vendor> |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| <p> |
| Here's the code that makes use of XMLDocumentContainer. |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| class Company { |
| private Container locations = null; |
| |
| public Container getLocations(){ |
| if (locations == null){ |
| URL url = getClass().getResource("Vendor.xml"); |
| locations = new XMLDocumentContainer(url); |
| } |
| return locations; |
| } |
| } |
| ... |
| context = JXPathContext.newContext(new Company()); |
| ... |
| String street = (String)context.getValue( |
| "locations/vendor/location[@id = 'store102']//street"); |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| <p> |
| Like was described before, this code will implicitly open |
| and parse the XML file and find a value in it according to |
| the XPath. |
| </p> |
| </subsection> |
| |
| <subsection name="Functions id() and key()"> |
| <p> |
| Functions <code>id()</code> and <code>key()</code> can be |
| used with JXPath, however most of the time that requires custom |
| coding. |
| </p> |
| <p> |
| The only situation where no custom coding is needed is when |
| you want to use the <code>id()</code> function and you have |
| a DOM Node as the context node of the JXPathContext. In |
| this case, JXPath will use the standard behavior of DOM. |
| </p> |
| <p> |
| In order to evaluate the <code>id()</code> function, JXPath |
| calls a delegate object that should be implemented and installed |
| on the JXPathContext. The object should implement the |
| <a href="apidocs/org/apache/commons/jxpath/IdentityManager.html">IdentityManager</a> |
| interface. |
| </p> |
| <p> |
| Similarly, the <code>key()</code> function relies on a custom |
| implementation of the |
| <a href="apidocs/org/apache/commons/jxpath/KeyManager.html">KeyManager</a> |
| interface. |
| </p> |
| </subsection> |
| </section> |
| |
| <section name="XPath Axes And Object Graphs"> |
| <p> |
| The interpretation of XPath over XML models like DOM and JDOM is governed by |
| the XPath standard. There is no official standard for the interpretation |
| of XPaths on other types of models: beans, maps etc. |
| This part describes how JXPath performs such interpretation. |
| </p> |
| |
| <subsection name="Parent/child Relationship"> |
| <p> |
| In DOM/JDOM the definition of a node's parent is clear: a Node always |
| points to its parent. XML is a strict tree, so there always exactly |
| one parent for every node except the root. |
| </p> |
| <p> |
| With other models the situation is more complex. An general object model |
| can not be described as a tree. In many cases it is a complicated |
| graph with many paths to the same node and even referential cycles |
| where node A is node B's child, but also node B is node A's child. |
| Even if the graph is a strict tree, a node of that tree may not have |
| a pointer to its parent. |
| </p> |
| <p> |
| Because of all these issues, JXPath abandons the static notion |
| of a parent/child relationship in favor of a dynamic one. |
| When an XPath is evaluated, the engine performs a series of searches |
| and computations in so called <i>evaluation contexts</i>. For example, |
| when the <code>"/foo/bar"</code> path is evaluated, JXPath first looks |
| for a node named "foo" in the root evaluation context. |
| If such a node is found, the interpreter forms a new context |
| for the discovered node and searches for a node named "bar" in |
| that context. |
| </p> |
| <p> |
| This chain of contexts is used in JXPath to define the parent-child |
| relationship. Parent is the base node of the previous evaluation |
| context in the chain. A more appropriate name for the "parent::" axis |
| would then be "step back". |
| </p> |
| <p> |
| Consider this example. The evaluated path is |
| <code>"foo//bar/../baz"</code>. In the process of evaluating of this |
| path, the engine will walk the graph forming chains of context like |
| <code>"/foo/a/b/c/bar"</code>. Once a node with the name "bar" is found, |
| the engine will "step back": in our case it will go back to the |
| <code>"/foo/a/b/c"</code> context and then look for the node with |
| the name "baz" in that context. |
| </p> |
| <p> |
| <b>Exercise:</b> think about how the path |
| <code>"//foo[../@name='bar']"</code> would be interpreted. |
| </p> |
| <p> |
| <b>Solution:</b> |
| <ol> |
| <li> |
| Descend from the root of the graph looking for a node |
| with the name "foo". |
| </li> |
| <li> |
| Let's say the engine has found such a node in the context of |
| a node called "biz". The "biz" node is the dynamic parent |
| of the node "foo". |
| </li> |
| <li> |
| Form a new context for the "foo" node. |
| </li> |
| <li> |
| To evaluate the predicate <code>"../@name='bar'"</code>, step back |
| to the previous context, which is the context of |
| the node "biz" to see if it has an attribute called "name". If so, |
| compare the value of that attribute to "bar". If it is equal, |
| include the current "foo" node in the result set. |
| </li> |
| </ol> |
| </p> |
| <p> |
| The dynamic interpretation of the parent/child relationship affects |
| most axes including "parent::", "ancestor::", |
| "preceding::", "following::" etc. |
| </p> |
| </subsection> |
| |
| <subsection name="Document Order"> |
| <p> |
| The XPath standard defines the term "document order" as the order |
| in which pieces of XML follow each other in the textual representation. |
| This definition is not applicable directly to non-XML models. |
| </p> |
| <p> |
| Results of many types of xpaths depend on the document order, so |
| we cannot leave it as "unpredictable" or "undefined" for such nodes |
| as JavaBeans or Maps. In order to have a predictable order, |
| JXPath sorts properties of beans and keys of maps alphabetically. |
| </p> |
| </subsection> |
| |
| <subsection name="Attributes"> |
| <p> |
| For JavaBeans and Maps the "attribute::" axis is interpreted |
| the same as the "child::" axis. |
| </p> |
| <p> |
| The only distinctions are "xml:lang", "xml:space", and "name". |
| </p> |
| <p> |
| Attribute <code>xml:lang</code> refers to the name of the locale |
| associated with the node. In XML the <code>xml:lang</code> attribute |
| can be specifed for an element explicitly. In non-XML models, |
| the locale is associated with the whole JXPathContext. Unless |
| explicitly set it is the application's default locale. |
| </p> |
| <p> |
| Since version 1.3, the <code>xml:space</code> attribute can be used |
| in an XML model to direct JXPath's interpretation of embedded |
| whitespace among XML content and nested text. In previous versions |
| this data was trimmed, and this has been preserved as the default |
| behavior for reasons of backward compatibility. Specifying |
| <code>xml:space="preserve"</code> will cause JXPath to preserve |
| whitespace. Keep in mind that it is possible to specify default |
| attribute values using DTD or XML schema, so that there exists a |
| straightforward and standards-based way to enable whitespace |
| preservation by default at the document or element level. |
| </p> |
| <p> |
| The <code>name</code> attribute is primarily used when |
| working with Maps. Often elements of a Map can be retrieved |
| using the "child::" axis. For example, if "foo" in <code>"foo/bar"</code> |
| refers to a Map then the path extracts from the map the value for the key |
| "bar". The syntax of XPath requires that a child name be a properly |
| formed identifier. Now, what if the key we are looking for is "?%$", |
| which is not an identifier. In this case we can use the "name" |
| attribute like this: <code>"foo[@name='?%$']"</code>. This path |
| is not interpreted as "find a 'foo' that has the name '?%$'". It is |
| interpreted as "find a 'foo' and get the value for the key '?%$'" |
| from it. This interpretation is used for maps and beans only. |
| In the case of XML, "name" is treated like any other attribute. |
| </p> |
| </subsection> |
| |
| </section> |
| |
| <section name="Exceptions During XPath Evaluation"> |
| <p> |
| Exceptions thrown by accessor methods are treated differently depending |
| on the evaluated xpath and the particular method used to do the |
| evaluation. |
| </p> |
| <p> |
| The basic idea is that if JXPath is <i>looking</i> for something by |
| iterating over all properties of a bean and during that iteration |
| an accessor method for one of these properties throws an exception, |
| JXPath ignores the exception and moves on to the next property. |
| This could happen if the method is <code>iterate()</code> or |
| if the path contains search axes like "descendant::", "ancestor::" etc. |
| </p> |
| <p> |
| In all other cases, an exception thrown by an accessor method is |
| wrapped into a JXPathException and re-thrown. |
| </p> |
| </section> |
| |
| <section name="Modifying Object Graphs"> |
| <p> |
| JXPath can also be used to modify parts of object graphs: |
| property values, values for keys in Maps. It can in some cases |
| create intermediate nodes in object graphs. |
| </p> |
| |
| |
| <subsection name="Setting Properties"> |
| <p> |
| JXPath can be used to modify property values. |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| 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"); |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| </subsection> |
| |
| |
| <subsection name="Creating Objects"> |
| <p> |
| JXPath can be used to create new objects. First, create a |
| subclass of |
| <a href="apidocs/org/apache/commons/jxpath/AbstractFactory.html"><code>AbstractFactory</code></a> |
| and install it on the JXPathContext. Then call |
| <code>jxPathContext.createPath(xpath)</code>. |
| 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. |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| 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.createPath("address"); |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| <p> |
| You can also combine creating a path with setting the value |
| of the leaf: the <code>createPathAndSetValue(path, value)</code> |
| method is used for that. |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| context.createPathAndSetValue("address/zipCode", "90190"); |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| <p> |
| Note that it only makes sense to use the automatic creation of |
| nodes with very simple paths. In fact, JXPath will not |
| attempt to create intermediate nodes for paths that don't |
| follow these three rules: |
| <ul> |
| <li> |
| The only axes used are "child::" and "attribute::", e.g. |
| <code>"foo/bar/@baz"</code> |
| </li> |
| <li> |
| The only two types of predicates used are |
| context-independent indexing and the |
| <code>"[@name = <i>expr</i>]"</code> |
| construct, e.g. <code>"map[@name='key1'][4/2]"</code>. |
| </li> |
| <li> |
| If a variable is used, it is the root of the path, |
| e.g. <code>"$object/child"</code>. |
| </li> |
| </ul> |
| </p> |
| </subsection> |
| </section> |
| |
| |
| <section name="Variables"> |
| <p> |
| JXPath supports the notion of variables. The XPath syntax for |
| accessing variables is <i>"$varName"</i>. |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| 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]"); |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| <p> |
| You can also set variables using JXPath: |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| context.setValue("$index", new Integer(3)); |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| <p><b>Note:</b> generally speaking, you can only <i>change</i> the |
| value of an existing variable this way, you cannot <i>define</i> |
| a new variable. If you do want to be able to define a new variable |
| dynamically, implement a <code>defineVariable()</code> |
| method on your custom AbstractFactory and call |
| <code>createPathAndSetValue()</code> rather than |
| <code>setValue()</code>. The restrictions described in the |
| "Creating Objects" section still apply. |
| </p> |
| <p> |
| When a variable contains a JavaBean or a collection, you can |
| traverse the bean or collection as well: |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| ... |
| 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); |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| <p/> |
| |
| |
| <subsection name="Custom Variable Pools"> |
| <p> |
| 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. |
| </p> |
| <p> |
| See the |
| <a href="apidocs/org/apache/commons/jxpath/servlet/package-summary.html">org.apache.commons.jxpath.servlet</a> |
| package for an example of just that. |
| </p> |
| </subsection> |
| </section> |
| |
| <section name="Servlet Contexts"> |
| <p> |
| The <code>org.apache.commons.jxpath.servlet</code> package |
| contains classes that make it easy to use XPath to access |
| values in various sevlet contexts: "page" (for JSPs), |
| "request", "session" and "application". |
| </p> |
| <p> |
| See static methods of the class |
| <a href="apidocs/org/apache/commons/jxpath/servlet/JXPathServletContexts.html"><code>JXPathServletContexts</code></a>. |
| They allocate various servlet-related JXPathContexts. |
| </p> |
| |
| |
| <subsection name="JSP Page Context"> |
| <p> |
| The JXPathContext returned by |
| <code>getPageContext(PageContext pageContext)</code> |
| provides access to all scopes via the |
| <code>PageContext.findAttribute()</code> method. Thus, |
| an expression like <code>"foo"</code> will first look |
| for the attribute named <code>"foo"</code> in the |
| <code>"page"</code> context, then the <code>"request"</code> |
| context, then the <code>"session"</code> one and |
| finally in the <code>"application"</code> context. |
| </p> |
| <p> |
| If you need to limit the attibute lookup to just one scope, |
| you can use the pre-definded variables <code>"page"</code>, |
| <code>"request"</code>, <code>"session"</code> and |
| <code>"application"</code>. For example, the |
| expression <code>"$session/foo"</code> extracts the |
| value of the <i>session</i> attribute named <code>"foo"</code>. |
| </p> |
| </subsection> |
| |
| |
| <subsection name="Servlet Request Context"> |
| <p> |
| The |
| <code>getRequestContext(ServletRequest request, ServletContext servletContext)</code> |
| method will give you a context that checks the request |
| scope first, then (if there is a session) the session |
| context, then the application context. |
| </p> |
| </subsection> |
| |
| |
| <subsection name="HttpSession Context"> |
| <p> |
| The |
| <code>getSessionContext(HttpSession session, ServletContext servletContext)</code> |
| method will give you a context that checks the session |
| context, then the application context. |
| </p> |
| </subsection> |
| |
| |
| <subsection name="ServletContext Context"> |
| <p> |
| Finally, |
| <code>getApplicationContext(ServletContext servletContext)</code> |
| method will give you a context that checks the application |
| context. |
| </p> |
| </subsection> |
| <p> |
| All these methods cache the JXPathContexts they create within |
| the corresponding scopes. Subsequent calls use the |
| JXPathContexts created earlier. |
| </p> |
| </section> |
| |
| |
| <section name="Pointers"> |
| <p> |
| Often, rather than getting a node in the object graph, you need to |
| find out where in the graph that node is. In such situations you |
| will need to employ <i>Pointers</i>. A Pointer is an object that |
| represents the specific location in the object graph. Effectively, |
| it is a simple XPath leading from the context root to the selected |
| node. That simple XPath can be used to repeatedly acquire the same |
| node of the graph without performing a costly search. |
| Let's say, you invoke the JXPath search process by calling the |
| <code>getPointer()</code> method: |
| </p> |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| Pointer ptr = context.getPointer("//address[zipCode='90190']") |
| System.out.println(ptr); |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| <p> |
| This code will find the address with zipCode = 90190 and |
| return a Pointer describing that node's location. The printed line |
| will look something like this: |
| <code>/vendor[2]/location[1]/address[3]</code>. It |
| provides an unambiguous description of the node's location in the object graph |
| and a fast XPath leading directly to that node. |
| </p> |
| <p> |
| Here's another example: |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| Pointer ptr = context.getPointer("employees[$i]/addresses[$j]") |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| <p> |
| Let's say, at the time of execution the value of the variable i is 1 |
| and j = 3. If we call <code>ptr.asPath()</code>, it returns a simple |
| XPath: <code>"/employees[1]/addresses[3]"</code>; this path does not |
| have a dependency on the variables, it will remain the same when the |
| variables change. |
| </p> |
| <p> |
| If you need to perform an exhaustive search for all nodes in the graph |
| matching a certain XPath, you can get JXPath to produce an iterator |
| returning pointers for all of discovered locations: |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| Iterator homeAddresses = context.iteratePointers("//employee/address[@name='home']"); |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| <p> |
| Each Pointer returned by the iterator will represent a home address object in |
| the graph. |
| </p> |
| <p> |
| It is a good idea to use pointers whenever you need to access |
| the same node of a graph repeatedly. |
| </p> |
| <p> |
| JXPath is optimized to interpret XPaths produced by Pointers |
| much faster than many other types of XPaths. |
| </p> |
| </section> |
| |
| <section name="Relative Contexts"> |
| <p> |
| If you need to evaluate multiple paths relative to a certain node |
| in the object graph, you might want to create a relative JXPathContext. |
| </p> |
| <p> |
| First, obtain the pointer for the location that is supposed to be the root |
| the relative context. Then obtain the relative context by calling |
| <code>context.getRelativeContext(pointer)</code>. |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| JXPathContext context = JXPathContext.newContext(bean); |
| |
| Pointer addressPtr = context.getPointer("/employees[1]/addresses[2]"); |
| |
| JXPathContext relativeContext = |
| context.getRelativeContext(addressPtr); |
| |
| // Evaluate relative path |
| String zipCode = (String)relativeContext.getValue("zipCode"); |
| |
| // Evaluate absolute path |
| String name = (String)relativeContext.getValue("/employees[1]/name"); |
| |
| // Use the parent axis to locate the employee for the current address |
| Double salary = (Double)relativeContext.getValue("../salary"); |
| |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| </section> |
| |
| <section name="Extension Functions"> |
| <p> |
| JXPath supports standard XPath functions right out of the box. |
| It also supports "standard" extension functions, which are |
| basically a bridge to Java, as well as entirely custom extension |
| functions. |
| </p> |
| |
| |
| <subsection name="Standard Extension Functions"> |
| <p> |
| Using the standard extension functions, you can call |
| methods on objects, static methods on classes and create |
| objects using any constructors. All class names should be |
| fully qualified. |
| </p> |
| <p> |
| Here's how you can create new objects: |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| Book book = (Book)context. |
| getValue("com.myco.books.Book.new('John Updike')"); |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| <p> |
| Here's how you can call static methods: |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| Book book = (Book)context. |
| getValue("com.myco.books.Book.getBestBook('John Updike')"); |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| <p> |
| Here's how you can call regular methods: |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| String firstName = (String)context. |
| getValue("getAuthorsFirstName($book)"); |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| <p> |
| As you can see, the target of the method is specified as |
| the first parameter of the function. |
| </p> |
| </subsection> |
| |
| |
| <subsection name="Custom Extension Functions"> |
| <p> |
| Collections of custom extension functions can be |
| implemented as |
| <a href="apidocs/org/apache/commons/jxpath/Functions.html"><code>Functions</code></a> |
| objects or as Java classes, whose methods become extension |
| functions. |
| </p> |
| <p> |
| Let's say the following class implements various formatting |
| operations: |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| public class Formats { |
| public static String date(Date d, String pattern){ |
| return new SimpleDateFormat(pattern).format(d); |
| } |
| ... |
| } |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| <p> |
| We can register this class with a JXPathContext: |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| context.setFunctions(new ClassFunctions(Formats.class, "format")); |
| ... |
| |
| context.getVariables().declareVariable("today", new Date()); |
| String today = |
| (String)context.getValue("format:date($today, 'MM/dd/yyyy')"); |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| <p> |
| You can also register whole packages of Java classes using |
| PackageFunctions. |
| </p> |
| <p> |
| Also, see |
| <a href="apidocs/org/apache/commons/jxpath/FunctionLibrary.html"><code>FunctionLibrary</code></a>, |
| which is a class that allows you to register multiple sets |
| of extension functions with the same JXPathContext. |
| </p> |
| </subsection> |
| |
| |
| <subsection name="Expression Context"> |
| <p> |
| A custom function can get access to the context in which it |
| is being evaluated. ClassFunctions and PackageFunctions |
| have special support for methods and constructors that have |
| <a href="apidocs/org/apache/commons/jxpath/ExpressionContext.html"><code>ExpressionContext</code></a> |
| as the first argument. When such an extension function is |
| invoked, it is passed an object that implements the |
| ExpressionContext interface. The function can then gain |
| access to the "current" object in the currently evaluated |
| context. |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| public class MyExtensionFunctions { |
| public static boolean isDate(ExpressionContext context){ |
| Pointer pointer = context.getContextNodePointer(); |
| if (pointer == null){ |
| return false; |
| } |
| return pointer.getValue() instanceof Date; |
| } |
| ... |
| } |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| <p> |
| You can then register this extension function using |
| ClassFunctions and call it like this: |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| "//.[myext:isDate()]" |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| <p> |
| This expression will find all nodes of the graph that are |
| dates. |
| </p> |
| </subsection> |
| |
| <subsection name="Collections as Arguments"> |
| <p> |
| There are two ways a collection can be passed to an extension function: |
| as a <a href="apidocs/org/apache/commons/jxpath/NodeSet.html"><code>NodeSet</code></a> |
| or as a Collection proper. If the argument type is declared |
| as NodeSet, JXPath will pass a NodeSet object, otherwise it will take values |
| out of the node set and pass those to the function as a regular collection. |
| NodeSet, in addition to providing access to the values, also provides access |
| to pointers. |
| Note that a collection is often passed to an extension function by value and |
| cannot be modified. |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| public class MyExtensionFunctions { |
| ... |
| public static boolean contains(NodeSet nodeSet, Object value){ |
| Iterator iter = nodeSet.getPointers().iterator(); |
| while (iter.hasNext()) { |
| Pointer item = (Pointer)iter.next(); |
| if (item.getValue().equals(value)){ |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| // Alternative implementation |
| public static boolean contains(List list, Object value){ |
| Iterator iter = list.iterator(); |
| while (iter.hasNext()) { |
| Object item = iter.next(); |
| if (item.getValue().equals(value)){ |
| return true; |
| } |
| } |
| return false; |
| } |
| } |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| <p> |
| You can call this function to find all people who have a |
| certain phone number: |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| "/addressBook/contact[myext:contains(phoneNumbers, '555-5555']" |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| <p> |
| In JXPath version 1.1, a function argument declared as Object would be |
| passed as a NodeSet. In version 1.2, this behavior was changed such |
| that a declared argument type of Object triggers the conversion of |
| the NodeSet to its list of values. The simplest way to avoid this |
| conversion, thereby receiving the untouched NodeSet as the function |
| argument, is to declare the argument as a NodeSet. For such times as |
| this may prove impractical, however, a version 1.1-compatible |
| TypeConverter implementation, |
| (org.apache.commons.jxpath.util.JXPath11CompatibleTypeConverter), |
| has been provided in version 1.3. To enable this: |
| </p> |
| <source> |
| TypeUtils.setTypeConverter(new JXPath11CompatibleTypeConverter()); |
| </source> |
| </subsection> |
| <subsection name="Collection as the Return Value"> |
| <p> |
| A custom function can return a collection of arbitrary objects or a NodeSet. |
| The simple implementation of NodeSet, |
| <a href="apidocs/org/apache/commons/jxpath/BasicNodeSet.html#setLocale">BasicNodeSet</a>, |
| may come in handy. |
| </p> |
| </subsection> |
| </section> |
| |
| |
| <section name="Type Conversions"> |
| <p> |
| JXPath automatically performs the following type convertions: |
| </p> |
| <table> |
| <tr> |
| <th> |
| From type |
| </th> |
| <th> |
| To type |
| </th> |
| <th> |
| Operation |
| </th> |
| </tr> |
| <tr> |
| <td><i>null</i> |
| </td> |
| <td><i>primitive</i> |
| </td> |
| <td> |
| false, zero |
| </td> |
| </tr> |
| <tr> |
| <td><i>any</i> |
| </td> |
| <td> |
| String |
| </td> |
| <td> |
| Calls toString() |
| </td> |
| </tr> |
| <tr> |
| <td> |
| Boolean |
| </td> |
| <td><i>any</i> Number |
| </td> |
| <td> |
| True = 1, false = 0 |
| </td> |
| </tr> |
| <tr> |
| <td><i>any</i> Number |
| </td> |
| <td><i>any other</i> Number |
| </td> |
| <td> |
| Truncates if needed |
| </td> |
| </tr> |
| <tr> |
| <td> |
| String |
| </td> |
| <td><i>any primitive type</i> |
| </td> |
| <td> |
| Parses the string |
| </td> |
| </tr> |
| <tr> |
| <td><i>array</i> |
| </td> |
| <td><i>array</i> |
| </td> |
| <td> |
| Creates a new array of the same size and converts every |
| element |
| </td> |
| </tr> |
| <tr> |
| <td><i>array</i> |
| </td> |
| <td><i>Collection</i> |
| </td> |
| <td> |
| Creates a collection and adds to it all elements of the |
| array. Note that it will only know how to create the |
| collection if the type is a concrete class, List or Set |
| </td> |
| </tr> |
| <tr> |
| <td><i>Collection</i> |
| </td> |
| <td><i>array</i> |
| </td> |
| <td> |
| Creates a new array the same size as the collection, |
| converts and copies every element of the collection |
| into the array. |
| </td> |
| </tr> |
| <tr> |
| <td><i>Collection</i> |
| </td> |
| <td><i>Collection</i> |
| </td> |
| <td> |
| Creates a collection and copies the source collection |
| into the new collection. Note that it will only know |
| how to create the collection if the type is a concrete |
| class, List or Set |
| </td> |
| </tr> |
| <tr> |
| <td><i>non-empty array</i> |
| </td> |
| <td><i>any</i> |
| </td> |
| <td> |
| Takes the first element of the array |
| <br/> |
| and (recursively) converts it to the needed |
| type |
| </td> |
| </tr> |
| <tr> |
| <td><i>non-empty collection</i> |
| </td> |
| <td><i>any</i> |
| </td> |
| <td> |
| Takes the first element of the array |
| <br/> |
| and (recursively) converts it to the needed |
| type |
| </td> |
| </tr> |
| <tr> |
| <td> |
| NodeSet |
| </td> |
| <td> |
| any |
| </td> |
| <td> |
| Extracts a list of values from the NodeSet and |
| (recursively) converts the list to the needed type. |
| </td> |
| </tr> |
| </table> |
| </section> |
| |
| |
| <section name="Internationalization"> |
| <p> |
| For DOM Documents JXPathContext supports internationalization |
| XPath-style. A locale can be declared on an XML Element like |
| this: |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| <book xml:lang="fr">Les Miserables</book> |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| <p> |
| You can then use the <code>lang</code> function in XPath |
| to find nodes for a specific language: |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| "//book[lang('fr')] |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| <p> |
| The <code>"lang"</code> boolean function is supported for |
| non-DOM objects as well. It tests the Locale set on the |
| JXPathContext (or the default locale). See |
| <a href="apidocs/org/apache/commons/jxpath/JXPathContext.html#setLocale">JXPathContext.setLocale()</a>. |
| </p> |
| <p> |
| You can also utilize the <code>xml:lang</code> attribute, |
| whose value is the name of the locale, whether in a DOM |
| document or outside. |
| </p> |
| </section> |
| |
| |
| <section name="Nested Contexts"> |
| <p> |
| If you need to use the same configuration (variables, functions, abstract |
| factories, locale, leniency etc.) |
| while interpreting XPaths with different beans, it makes sense to put the |
| configuration in a separate context and specify that context as a |
| parent context every time you allocate a new JXPathContext for |
| a JavaBean. This way you don't need to waste time fully |
| configuring every context. |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| JXPathContext sharedContext = JXPathContext.newContext(null); |
| sharedContext.getVariables().declareVariable("title", "Java"); |
| sharedContext.setFunctions(new MyExtensionFunctions()); |
| sharedContext.setLocale(Locale.CANADA); |
| sharedContext.setFactory(new MyFactory()); |
| |
| ... |
| |
| JXPathContext context = JXPathContext.newContext(sharedContext, auth); |
| |
| Iterator javaBooks = |
| context.iterate("books[preprocessTitle(title) = $title]"); |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| </section> |
| |
| |
| <section name="Compiled Expressions"> |
| <p> |
| When JXPath is asked to evaluate an expression for the first |
| time, it compiles it and caches its compiled representation. |
| This mechanism reduces the overhead caused by compilation. However, in |
| some cases JXPath's own caching may not be sufficient- |
| JXPath caches have limited size and they are automatically cleared |
| once in a while. |
| </p> |
| <p> |
| Here's how you can precompile an XPath expression: |
| </p> |
| |
| <!--============================ + SOURCE + ============================--> |
| <source> |
| <b/> |
| CompiledExpression expr = context.compile(xpath); |
| ... |
| Object value = expr.getValue(context); |
| </source> |
| <!--============================ - SOURCE - ============================--> |
| |
| <p> |
| Use compiled expressions if you need to satisfy any of the following |
| requirements: |
| </p> |
| <ul> |
| <li> |
| There is a relatively small number of XPaths your |
| application works with, and it needs to evaluate those |
| XPaths multiple times. |
| </li> |
| <li> |
| Some XPaths need to be precompiled at initialization time for speed. |
| </li> |
| <li> |
| The syntax of some XPaths needs to be checked before they |
| are used for the first time. |
| </li> |
| </ul> |
| </section> |
| |
| |
| <section name="Customizing JXPath"> |
| <p> |
| JXPath can be customized on several levels. |
| </p> |
| <ul> |
| <li> |
| You can provide custom JXPathBeanInfo objects to customize |
| lists of properties of JavaBeans available to JXPath. |
| </li> |
| <li> |
| You can easily add support for object types similar to Map. |
| All you need to do is implement the DynamicPropertyHandler |
| interface and register the implementation with |
| JXPathIntrospector. |
| </li> |
| <li> |
| You can add support for types of object models JXPath does |
| not support out of the box. An example of such model would |
| be an alternative implementation of XML parse tree (e.g. |
| DOM4J etc). You will need to implement two or three classes to |
| allow JXPath to traverse properties of these custom |
| objects. |
| </li> |
| <li> |
| The most dramatic customization of JXPath can be done at |
| the level of JXPathContextFactory- you can transparently |
| provide an alternative implementation of all top level |
| APIs. |
| </li> |
| </ul> |
| |
| |
| <subsection name="Custom JXPathBeanInfo"> |
| <p> |
| JXPath uses JavaBeans introspection to discover properties |
| of JavaBeans. You can provide alternative property lists by |
| supplying custom JXPathBeanInfo classes (see |
| <a href="apidocs/org/apache/commons/jxpath/JXPathBeanInfo.html"><code>JXPathBeanInfo</code></a>). |
| </p> |
| </subsection> |
| |
| |
| <subsection name="Custom DynamicPropertyHandler"> |
| <p> |
| JXPath uses various implementations of the |
| DynamicPropertyHandler interface to access properties of |
| objects similar to Map. |
| </p> |
| <p> |
| The <code>org.apache.commons.jxpath.servlet</code> |
| package has several examples of custom |
| DynamicPropertyHandlers. |
| </p> |
| </subsection> |
| |
| |
| <subsection name="Custom Pointers and Iterators"> |
| <p> |
| Architecturally, multiple model support is made possible by |
| the notions of a |
| <a href="apidocs/org/apache/commons/jxpath/ri/model/NodePointer.html">NodePointer</a> |
| and |
| <a href="apidocs/org/apache/commons/jxpath/ri/model/NodeIterator.html">NodeIterator</a>, |
| which are simple abstract classes that are extended in |
| different ways to traverse graphs of objects of different |
| kinds. The NodePointer/NodeIterator APIs are designed with |
| models like JavaBeans in mind. They directly support |
| indexed collections. As a result, XPaths like |
| <code>"foo[10]"</code> can be executed as |
| <code>"getFoo(9)"</code> or <code>"getFoo()[9]"</code>, |
| or <code>"getFoo().get(9)"</code>, depending on the |
| type of collection. This flexibility is disguised well |
| enough by the APIs of the abstract classes, so we can still |
| have a natural implementation of traversal of object |
| models, such as DOM, that do not have the same notion of |
| collection. |
| </p> |
| <p> |
| To add support for a new object model, build custom |
| implementations of NodePointer and NodeIterator as well as |
| <a href="apidocs/org/apache/commons/jxpath/ri/model/NodePointerFactory.html">NodePointerFactory</a>. |
| Then register the new factory with |
| <a href="apidocs/org/apache/commons/jxpath/ri/JXPathContextReferenceImpl.html">JXPathContextReferenceImpl</a>. |
| </p> |
| <p> |
| See existing NodePointerFactories for examples of how |
| that's done: |
| <ul> |
| <li> |
| BeanPointerFactory works with JavaBeans |
| </li> |
| <li> |
| DynamicPointerFactory works with Dynamic beans like |
| Map, HttpRequest and such |
| </li> |
| <li> |
| ContainerPointerFactory works with Container |
| objects like XMLDocumentContainer |
| </li> |
| <li> |
| DOMPointerFactory works with DOM Nodes |
| </li> |
| </ul> |
| </p> |
| </subsection> |
| |
| |
| <subsection name="Alternative JXPath Implementation"> |
| <p> |
| The core JXPath class, JXPathContext, allows for 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. JXPath comes |
| bundled with a default implementation called Reference |
| Implementation. |
| </p> |
| </subsection> |
| </section> |
| </body> |
| </document> |