org.apache.commons.jxpath
abstract public class: JXPathContext [javadoc |
source]
java.lang.Object
org.apache.commons.jxpath.JXPathContext
Direct Known Subclasses:
JXPathContextReferenceImpl
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:
Address addr = (Address)context.getValue("homeAddress");
Example 3: Collection Subscripts
JXPath can extract elements from arrays and collections.
public class Integers {
public int[] getNumbers(){
...
}
}
Integers ints = new Integers();
...
JXPathContext context = JXPathContext.newContext(ints);
Integer thirdInt = (Integer)context.getValue("numbers[3]");
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.
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");
Often you will need to use the alternative syntax for accessing Map
elements:
String homeZipCode =
(String) context.getValue("addresses[@name='home']/zipCode");
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.
JXPathContext varContext = JXPathContext.newContext(null);
varContext.getVariables().declareVariable("title", "Java");
JXPathContext context = JXPathContext.newContext(varContext, auth);
Iterator javaBooks = context.iterate("books[title = $title]");
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:
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')");
Here's how you can call regular methods:
String firstName = (String)context.getValue("getAuthorsFirstName($book)");
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:
public class Formats {
public static String date(Date d, String pattern){
return new SimpleDateFormat(pattern).format(d);
}
...
}
We can register this class with a JXPathContext:
context.setFunctions(new ClassFunctions(Formats.class, "format"));
...
context.getVariables().declareVariable("today", new Date());
String today = (String)context.getValue("format:date($today, 'MM/dd/yyyy')");
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- author:
Dmitri
- Plotnikov
- version:
$
- Revision: 1.25 $ $Date: 2004/06/29 21:15:46 $
Field Summary |
---|
protected JXPathContext | parentContext | |
protected Object | contextBean | |
protected Variables | vars | |
protected Functions | functions | |
protected AbstractFactory | factory | |
protected IdentityManager | idManager | |
protected KeyManager | keyManager | |
protected HashMap | decimalFormats | |
Constructor: |
protected JXPathContext(JXPathContext parentContext,
Object contextBean) {
this.parentContext = parentContext;
this.contextBean = contextBean;
}
This constructor should remain protected - it is to be overridden by
subclasses, but never explicitly invoked by clients. |
Method from org.apache.commons.jxpath.JXPathContext Summary: |
---|
compile, compilePath, createPath, createPathAndSetValue, getContextBean, getContextPointer, getDecimalFormatSymbols, getFactory, getFunctions, getIdentityManager, getKeyManager, getLocale, getNamespaceContextPointer, getNamespaceURI, getParentContext, getPointer, getPointerByID, getPointerByKey, getRelativeContext, getValue, getValue, getVariables, isLenient, iterate, iteratePointers, newContext, newContext, registerNamespace, removeAll, removePath, selectNodes, selectSingleNode, setDecimalFormatSymbols, setFactory, setFunctions, setIdentityManager, setKeyManager, setLenient, setLocale, setNamespaceContextPointer, setValue, setVariables |
Methods from java.lang.Object: |
---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Method from org.apache.commons.jxpath.JXPathContext Detail: |
public static CompiledExpression compile(String xpath) {
if (compilationContext == null) {
compilationContext = JXPathContext.newContext(null);
}
return compilationContext.compilePath(xpath);
}
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. |
abstract protected CompiledExpression compilePath(String xpath)
Overridden by each concrete implementation of JXPathContext
to perform compilation. Is called by compile() . |
abstract public Pointer createPath(String xpath)
|
abstract public Pointer createPathAndSetValue(String xpath,
Object value)
|
public Object getContextBean() {
return contextBean;
}
Returns the JavaBean associated with this context. |
abstract public Pointer getContextPointer()
Returns a Pointer for the context bean. |
public DecimalFormatSymbols getDecimalFormatSymbols(String name) {
if (decimalFormats == null) {
if (parentContext != null) {
return parentContext.getDecimalFormatSymbols(name);
}
return null;
}
return (DecimalFormatSymbols) decimalFormats.get(name);
}
|
public AbstractFactory getFactory() {
if (factory == null && parentContext != null) {
return parentContext.getFactory();
}
return 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. |
public Functions getFunctions() {
if (functions != null) {
return functions;
}
if (parentContext == null) {
return GENERIC_FUNCTIONS;
}
return null;
}
Returns the set of functions installed on the context. |
public IdentityManager getIdentityManager() {
if (idManager == null && parentContext != null) {
return parentContext.getIdentityManager();
}
return idManager;
}
Returns this context's identity manager. If none has been installed,
returns the identity manager of the parent context. |
public KeyManager getKeyManager() {
if (keyManager == null && parentContext != null) {
return parentContext.getKeyManager();
}
return keyManager;
}
Returns this context's key manager. If none has been installed,
returns the key manager of the parent context. |
public Locale getLocale() {
if (locale == null) {
if (parentContext != null) {
return parentContext.getLocale();
}
else {
locale = Locale.getDefault();
}
}
return 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(). |
public Pointer getNamespaceContextPointer() {
throw new UnsupportedOperationException(
"Namespace registration is not implemented by " + getClass());
}
|
public String getNamespaceURI(String prefix) {
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
setNamespaceContextPointer . |
public JXPathContext getParentContext() {
return parentContext;
}
Returns the parent context of this context or null. |
abstract public Pointer getPointer(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. |
public Pointer getPointerByID(String id) {
IdentityManager manager = getIdentityManager();
if (manager != null) {
return manager.getPointerByID(this, id);
}
else {
throw new JXPathException(
"Cannot find an element by ID - "
+ "no IdentityManager has been specified");
}
}
Locates a Node by its ID. |
public Pointer getPointerByKey(String key,
String value) {
KeyManager manager = getKeyManager();
if (manager != null) {
return manager.getPointerByKey(this, key, value);
}
else {
throw new JXPathException(
"Cannot find an element by key - "
+ "no KeyManager has been specified");
}
}
Locates a Node by a key value. |
abstract public JXPathContext getRelativeContext(Pointer pointer)
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. |
abstract public Object getValue(String xpath)
Evaluates the xpath and returns the resulting object. Primitive
types are wrapped into objects. |
abstract public Object getValue(String xpath,
Class requiredType)
Evaluates the xpath, converts the result to the specified class and
returns the resulting object. |
public Variables getVariables() {
if (vars == null) {
vars = new BasicVariables();
}
return vars;
}
Returns the variable pool associated with the context. If no such
pool was specified with the setVariables() method,
returns the default implementation of Variables,
BasicVariables . |
public boolean isLenient() {
if (!lenientSet && parentContext != null) {
return parentContext.isLenient();
}
return lenient;
}
|
abstract public Iterator iterate(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. |
abstract public Iterator iteratePointers(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. |
public static JXPathContext newContext(Object contextBean) {
return getContextFactory().newContext(null, contextBean);
}
Creates a new JXPathContext with the specified object as the root node. |
public static JXPathContext newContext(JXPathContext parentContext,
Object contextBean) {
return getContextFactory().newContext(parentContext, contextBean);
}
Creates a new JXPathContext with the specified bean as the root node and
the specified parent context. Variables defined in a parent context can
be referenced in XPaths passed to the child context. |
public void registerNamespace(String prefix,
String namespaceURI) {
throw new UnsupportedOperationException(
"Namespace registration is not implemented by " + getClass());
}
Registers a namespace prefix. |
abstract public void removeAll(String xpath)
Removes all elements of the object graph described by the xpath. |
abstract public void removePath(String xpath)
Removes the element of the object graph described by the xpath. |
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;
}
Finds all nodes that match the specified XPath. |
public Object selectSingleNode(String xpath) {
Pointer pointer = getPointer(xpath);
if (pointer == null) {
return null;
}
return pointer.getNode();
}
Finds the first object that matches the specified XPath. It is equivalent
to getPointer(xpath).getNode() . Note, that this method
produces the same result as getValue() on object models
like JavaBeans, but a different result for DOM/JDOM etc., because it
returns the Node itself, rather than its textual contents. |
public void setDecimalFormatSymbols(String name,
DecimalFormatSymbols symbols) {
if (decimalFormats == null) {
decimalFormats = new HashMap();
}
decimalFormats.put(name, symbols);
}
Sets DecimalFormatSymbols for a given name. The DecimalFormatSymbols can
be referenced as the third, optional argument in the invocation of
format-number (number,format,decimal-format-name) function.
By default, JXPath uses the symbols for the current locale. |
public void setFactory(AbstractFactory factory) {
this.factory = factory;
}
Install an abstract factory that should be used by the
createPath() and createPathAndSetValue()
methods. |
public void setFunctions(Functions functions) {
this.functions = functions;
}
Install a library of extension functions. |
public void setIdentityManager(IdentityManager idManager) {
this.idManager = idManager;
}
Install an identity manager that will be used by the context
to look up a node by its ID. |
public void setKeyManager(KeyManager keyManager) {
this.keyManager = keyManager;
}
Install a key manager that will be used by the context
to look up a node by a key value. |
public void setLenient(boolean lenient) {
this.lenient = lenient;
lenientSet = true;
}
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 not
thrown.
By default, lenient = false |
public void setLocale(Locale locale) {
this.locale = locale;
}
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
Locale.getDefault() |
public void setNamespaceContextPointer(Pointer namespaceContextPointer) {
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
getContextPointer() |
abstract public void setValue(String xpath,
Object value)
Modifies the value of the property described by the supplied xpath.
Will throw an exception if one of the following conditions occurs:
- The xpath does not in fact describe an existing property
- The property is not writable (no public, non-static set method)
|
public void setVariables(Variables vars) {
this.vars = vars;
}
Installs a custom implementation of the Variables interface. |