Class XPathExpressionEngine
- All Implemented Interfaces:
ExpressionEngine
A specialized implementation of the ExpressionEngine
interface that is able to evaluate XPATH expressions.
This class makes use of Commons JXPath for handling XPath expressions and mapping them to the nodes of a hierarchical configuration. This makes the rich and powerful XPATH syntax available for accessing properties from a configuration object.
For selecting properties arbitrary XPATH expressions can be used, which select single or multiple configuration
nodes. The associated Configuration
instance will directly pass the specified property keys into this engine.
If a key is not syntactically correct, an exception will be thrown.
For adding new properties, this expression engine uses a specific syntax: the "key" of a new property must consist of two parts that are separated by whitespace:
- An XPATH expression selecting a single node, to which the new element(s) are to be added. This can be an arbitrary complex expression, but it must select exactly one node, otherwise an exception will be thrown.
- The name of the new element(s) to be added below this parent node. Here either a single node name or a complete path of nodes (separated by the "/" character or "@" for an attribute) can be specified.
Some examples for valid keys that can be passed into the configuration's addProperty()
method follow:
"/tables/table[1] type"
This will add a new type
node as a child of the first table
element.
"/tables/table[1] @type"
Similar to the example above, but this time a new attribute named type
will be added to the first
table
element.
"/tables table/fields/field/name"
This example shows how a complex path can be added. Parent node is the tables
element. Here a new branch
consisting of the nodes table
, fields
, field
, and name
will be added.
"/tables table/fields/field@type"
This is similar to the last example, but in this case a complex path ending with an attribute is defined.
Note: This extended syntax for adding properties only works with the addProperty()
method.
setProperty()
does not support creating new nodes this way.
From version 1.7 on, it is possible to use regular keys in calls to addProperty()
(i.e. keys that do not have
to contain a whitespace as delimiter). In this case the key is evaluated, and the biggest part pointing to an
existing node is determined. The remaining part is then added as new path. As an example consider the key
"tables/table[last()]/fields/field/name"
If the key does not point to an existing node, the engine will check the paths
"tables/table[last()]/fields/field"
, "tables/table[last()]/fields"
, "tables/table[last()]"
,
and so on, until a key is found which points to a node. Let's assume that the last key listed above can be resolved
in this way. Then from this key the following key is derived: "tables/table[last()] fields/field/name"
by
appending the remaining part after a whitespace. This key can now be processed using the original algorithm. Keys of
this form can also be used with the setProperty()
method. However, it is still recommended to use the old
format because it makes explicit at which position new nodes should be added. For keys without a whitespace delimiter
there may be ambiguities.
- Since:
- 1.3
-
Field Summary
FieldsModifier and TypeFieldDescription(package private) static final String
Constant for the attribute delimiter.private static final int
Constant for a default size of a key buffer.private final XPathContextFactory
The internally used context factory.private static final char
Constant for the end of an index expression.private static final String
Constant for the delimiters for splitting node paths.(package private) static final String
Constant for the path delimiter.private static final String
Constant for a space which is used as delimiter in keys for adding properties.private static final char
Constant for the start of an index expression. -
Constructor Summary
ConstructorsConstructorDescriptionCreates a new instance ofXPathExpressionEngine
with default settings.XPathExpressionEngine
(XPathContextFactory factory) Creates a new instance ofXPathExpressionEngine
and sets the context factory. -
Method Summary
Modifier and TypeMethodDescriptionattributeKey
(String parentKey, String attributeName) Returns the key of an attribute.<T> String
canonicalKey
(T node, String parentKey, NodeHandler<T> handler) Determines a "canonical" key for the specified node in the expression language supported by this implementation.private static <T> List
<QueryResult<T>> convertResults
(List<?> results) Converts the objects returned as query result from the JXPathContext to query result objects.private <T> org.apache.commons.jxpath.JXPathContext
createContext
(T root, NodeHandler<T> handler) Creates theJXPathContext
to be used for executing a query.(package private) <T> NodeAddData
<T> createNodeAddData
(String path, QueryResult<T> parentNodeResult) Creates aNodeAddData
object as a result of aprepareAdd()
operation.private static <T> QueryResult
<T> createResult
(Object resObj) Creates aQueryResult
object from the given result object of a query.private static <T> int
determineIndex
(T parent, T child, NodeHandler<T> handler) Determines the index of the given child node in the node list of its parent.private static int
findKeySeparator
(String key) Determines the position of the separator in a key for adding new properties.private <T> String
generateKeyForAdd
(T root, String key, NodeHandler<T> handler) Tries to generate a key for adding a property.(package private) XPathContextFactory
Gets theXPathContextFactory
used by this instance.private static void
invalidPath
(String path, String msg) Helper method for throwing an exception about an invalid path.<T> String
nodeKey
(T node, String parentKey, NodeHandler<T> handler) Returns the key for the specified node in the expression language supported by an implementation.<T> NodeAddData
<T> prepareAdd
(T root, String key, NodeHandler<T> handler) Returns information needed for an add operation.<T> List
<QueryResult<T>> query
(T root, String key, NodeHandler<T> handler) Finds the nodes and/or attributes that are matched by the specified key.
-
Field Details
-
PATH_DELIMITER
Constant for the path delimiter.- See Also:
-
ATTR_DELIMITER
Constant for the attribute delimiter.- See Also:
-
NODE_PATH_DELIMITERS
Constant for the delimiters for splitting node paths.- See Also:
-
SPACE
Constant for a space which is used as delimiter in keys for adding properties.- See Also:
-
BUF_SIZE
private static final int BUF_SIZEConstant for a default size of a key buffer.- See Also:
-
START_INDEX
private static final char START_INDEXConstant for the start of an index expression.- See Also:
-
END_INDEX
private static final char END_INDEXConstant for the end of an index expression.- See Also:
-
contextFactory
The internally used context factory.
-
-
Constructor Details
-
XPathExpressionEngine
public XPathExpressionEngine()Creates a new instance ofXPathExpressionEngine
with default settings. -
XPathExpressionEngine
XPathExpressionEngine(XPathContextFactory factory) Creates a new instance ofXPathExpressionEngine
and sets the context factory. This constructor is mainly used for testing purposes.- Parameters:
factory
- theXPathContextFactory
-
-
Method Details
-
convertResults
Converts the objects returned as query result from the JXPathContext to query result objects.- Type Parameters:
T
- the type of results to be produced- Parameters:
results
- the list with results from the context- Returns:
- the result list
-
createResult
Creates aQueryResult
object from the given result object of a query. Because of the node pointers involved result objects can only be of two types:- nodes of type T
- attribute results already wrapped in
QueryResult
objects
- Type Parameters:
T
- the type of the result to be produced- Parameters:
resObj
- the query result object- Returns:
- the
QueryResult
-
determineIndex
Determines the index of the given child node in the node list of its parent.- Type Parameters:
T
- the type of the nodes involved- Parameters:
parent
- the parent nodechild
- the child nodehandler
- the node handler- Returns:
- the index of this child node
-
findKeySeparator
Determines the position of the separator in a key for adding new properties. If no delimiter is found, result is -1.- Parameters:
key
- the key- Returns:
- the position of the delimiter
-
invalidPath
Helper method for throwing an exception about an invalid path.- Parameters:
path
- the invalid pathmsg
- the exception message
-
attributeKey
Description copied from interface:ExpressionEngine
Returns the key of an attribute. The passed inparentKey
must reference the parent node of the attribute. A concrete implementation must concatenate this parent key with the attribute name to a valid key for this attribute.- Specified by:
attributeKey
in interfaceExpressionEngine
- Parameters:
parentKey
- the key to the node owning this attributeattributeName
- the name of the attribute in question- Returns:
- the resulting key referencing this attribute
-
canonicalKey
Determines a "canonical" key for the specified node in the expression language supported by this implementation. This means that always a unique key if generated pointing to this specific node. For most concrete implementations, this means that an index is added to the node name to ensure that there are no ambiguities with child nodes having the same names. This implementation works similar tonodeKey()
, but always adds an index expression to the resulting key.- Specified by:
canonicalKey
in interfaceExpressionEngine
- Type Parameters:
T
- the type of the node to be processed- Parameters:
node
- the node, for which the key must be constructedparentKey
- the key of this node's parent (can be null for the root node)handler
- theNodeHandler
for accessing the node- Returns:
- the canonical key of this node
-
createContext
Creates theJXPathContext
to be used for executing a query. This method delegates to the context factory.- Parameters:
root
- the configuration root nodehandler
- the node handler- Returns:
- the new context
-
createNodeAddData
Creates aNodeAddData
object as a result of aprepareAdd()
operation. This method interprets the passed in path of the new node.- Type Parameters:
T
- the type of the nodes involved- Parameters:
path
- the path of the new nodeparentNodeResult
- the parent node
-
generateKeyForAdd
Tries to generate a key for adding a property. This method is called if a key was used for adding properties which does not contain a space character. It splits the key at its single components and searches for the last existing component. Then a key compatible key for adding properties is generated.- Parameters:
root
- the root node of the configurationkey
- the key in questionhandler
- the node handler- Returns:
- the key to be used for adding the property
-
getContextFactory
XPathContextFactory getContextFactory()Gets theXPathContextFactory
used by this instance.- Returns:
- the
XPathContextFactory
-
nodeKey
Returns the key for the specified node in the expression language supported by an implementation. This method is called whenever a property key for a node has to be constructed, e.g. by thegetKeys()
method. This implementation creates an XPATH expression that selects the given node (under the assumption that the passed in parent key is valid). As thenodeKey()
implementation ofDefaultExpressionEngine
this method does not return indices for nodes. So all child nodes of a given parent with the same name have the same key.- Specified by:
nodeKey
in interfaceExpressionEngine
- Type Parameters:
T
- the type of the node to be processed- Parameters:
node
- the node, for which the key must be constructedparentKey
- the key of this node's parent (can be null for the root node)handler
- theNodeHandler
for accessing the node- Returns:
- this node's key
-
prepareAdd
Returns information needed for an add operation. This method gets called when new properties are to be added to a configuration. An implementation has to interpret the specified key, find the parent node for the new elements, and provide all information about new nodes to be added. The expected format of the passed in key is explained in the class comment.- Specified by:
prepareAdd
in interfaceExpressionEngine
- Type Parameters:
T
- the type of the node to be processed- Parameters:
root
- the root nodekey
- the key for the new propertyhandler
- theNodeHandler
for accessing the node- Returns:
- an object with all information needed for the add operation
-
query
Finds the nodes and/or attributes that are matched by the specified key. This is the main method for interpreting property keys. An implementation must traverse the given root node and its children to find all results that are matched by the given key. If the key is not correct in the syntax provided by that implementation, it is free to throw a (runtime) exception indicating this error condition. The passed inNodeHandler
can be used to gather the required information from the node object. This implementation interprets the passed in key as an XPATH expression.- Specified by:
query
in interfaceExpressionEngine
- Type Parameters:
T
- the type of the node to be processed- Parameters:
root
- the root node of a hierarchy of nodeskey
- the key to be evaluatedhandler
- theNodeHandler
for accessing the node- Returns:
- a list with the results that are matched by the key (should never be null)
-