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.
JXPathContext allows alternative implementations. This is why instead of
allocating JXPathContext directly, you should call a static
newContext 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.
JXPath Interprets XPath Syntax on Java Object Graphs
JXPath uses an intuitive interpretation of the xpath syntax in the context
of Java object graphs. Here are some examples:
Example 1: JavaBean Property Access
JXPath can be used to access properties of a JavaBean.
public class Employee {
public String getFirstName(){
...
}
}
Employee emp = new Employee();
...
JXPathContext context = JXPathContext.newContext(emp);
String fName = (String)context.getValue("firstName");
In this example, we are using JXPath to access a property of the
emp bean. In this simple case the invocation of JXPath is
equivalent to invocation of getFirstName() on the bean.
Example 2: Nested Bean Property Access
JXPath can traverse object graphs:
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");
In this case XPath is used to access a property of a nested bean.
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:
In this case, the key can be an expression, e.g. a variable.
Note: At this point JXPath only supports Maps that use strings for keys.
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 JXPathIntrospector .
Example 5: Retrieving Multiple Results
JXPath can retrieve multiple objects from a graph. Note that the method
called in this case is not getValue, but iterate.
public class Author {
public Book[] getBooks(){
...
}
}
Author auth = new Author();
...
JXPathContext context = JXPathContext.newContext(auth);
Iterator threeBooks = context.iterate("books[position() < 4]");
This returns a list of at most three books from the array of all books
written by the author.
Example 6: Setting Properties
JXPath can be used to modify property values.
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");
Example 7: Creating objects
JXPath can be used to create new objects. First, create a subclass of AbstractFactory and install it on the JXPathContext. Then
call createPathAndSetValue() instead of
"setValue". JXPathContext will invoke your AbstractFactory when it discovers
that an intermediate node of the path is null. It will not override
existing nodes.
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");
Example 8: Using Variables
JXPath supports the notion of variables. The XPath syntax for accessing
variables is "$varName".
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]");
You can also set variables using JXPath:
context.setValue("$index", new Integer(3));
Note: you can only change the value of an existing variable this
way, you cannot define a new variable.
When a variable contains a JavaBean or a collection, you can
traverse the bean or collection as well:
...
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);
Example 9: Using Nested Contexts
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.
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.
Example 10: Using Standard Extension Functions
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.
Here's how you can create new objects:
Book book =
(Book) context.getValue(
"org.apache.commons.jxpath.example.Book.new ('John Updike')");
Here's how you can call static methods:
Book book =
(Book) context.getValue(
"org. apache.commons.jxpath.example.Book.getBestBook('John Updike')");
You can also register whole packages of Java classes using PackageFunctions.
Also, see FunctionLibrary , which is a class
that allows you to register multiple sets of extension functions with
the same JXPathContext.
Configuring JXPath
JXPath uses JavaBeans introspection to discover properties of JavaBeans.
You can provide alternative property lists by supplying
custom JXPathBeanInfo classes (see JXPathBeanInfo ).
Notes
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']".
JXPathContext allows alternative implementations. This is why instead of allocating JXPathContext directly, you should call a static
newContextmethod. This method will utilize the JXPathContextFactory API to locate a suitable implementation of JXPath. Bundled with JXPath comes a default implementation called Reference Implementation.JXPath Interprets XPath Syntax on Java Object Graphs
JXPath uses an intuitive interpretation of the xpath syntax in the context of Java object graphs. Here are some examples:Example 1: JavaBean Property Access
JXPath can be used to access properties of a JavaBean. In this example, we are using JXPath to access a property of theempbean. In this simple case the invocation of JXPath is equivalent to invocation of getFirstName() on the bean.Example 2: Nested Bean Property Access
JXPath can traverse object graphs: In this case XPath is used to access a property of a nested bean.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:
Example 3: Collection Subscripts
JXPath can extract elements from arrays and collections. A collection can be an arbitrary array or an instance of java.util. Collection.Note: in XPath the first element of a collection has index 1, not 0.
Example 4: Map Element Access
JXPath supports maps. To get a value use its key. Often you will need to use the alternative syntax for accessing Map elements: In this case, the key can be an expression, e.g. a variable.Note: At this point JXPath only supports Maps that use strings for keys.
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 JXPathIntrospector .
Example 5: Retrieving Multiple Results
JXPath can retrieve multiple objects from a graph. Note that the method called in this case is notgetValue, butiterate. This returns a list of at most three books from the array of all books written by the author.Example 6: Setting Properties
JXPath can be used to modify property values.Example 7: Creating objects
JXPath can be used to create new objects. First, create a subclass of AbstractFactory and install it on the JXPathContext. Then call createPathAndSetValue() instead of "setValue". JXPathContext will invoke your AbstractFactory when it discovers that an intermediate node of the path is null. It will not override existing nodes.Example 8: Using Variables
JXPath supports the notion of variables. The XPath syntax for accessing variables is "$varName". You can also set variables using JXPath: Note: you can only change the value of an existing variable this way, you cannot define a new variable.When a variable contains a JavaBean or a collection, you can traverse the bean or collection as well:
Example 9: Using Nested Contexts
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.Using Custom Variable Pools
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.Example 10: Using Standard Extension Functions
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.Here's how you can create new objects:
Here's how you can call static methods: Here's how you can call regular methods: As you can see, the target of the method is specified as the first parameter of the function.Example 11: Using Custom Extension Functions
Collections of custom extension functions can be implemented as Functions objects or as Java classes, whose methods become extenstion functions.Let's say the following class implements various formatting operations:
We can register this class with a JXPathContext: You can also register whole packages of Java classes using PackageFunctions.Also, see FunctionLibrary , which is a class that allows you to register multiple sets of extension functions with the same JXPathContext.
Configuring JXPath
JXPath uses JavaBeans introspection to discover properties of JavaBeans. You can provide alternative property lists by supplying custom JXPathBeanInfo classes (see JXPathBeanInfo ).Notes
- 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']".
See XPath Tutorial by W3Schools. Also see XML Path Language (XPath) Version 1.0
You will also find more information and examples in JXPath User's Guide