原文链接:https://hub.alfresco.com/t5/alfresco-content-services-hub/search-documentation/ba-p/289935#XPath_search_using_the_node_service

The node service has two methods that support XPath style searches.

/**
 * Select nodes using an xpath expression.
 * 
 * @param contextNode - the context node for relative expressions etc
 * @param XPath - the xpath string to evaluate
 * @param parameters - parameters to bind in to the xpath expression
 * @param namespacePrefixResolver - prefix to namespace mappings
 * @param followAllParentLinks - if false '..' follows only the primary parent links, if true it follows all 
 * @return a list of all the child assoc relationships to the selected nodes
 */
 public List<ChildAssocRef> selectNodes(NodeRef contextNode, 
                                        String XPath, 
                                        QueryParameterDefinition[] parameters,
                                        NamespacePrefixResolver namespacePrefixResolver,
                                        boolean followAllParentLinks);
/**
 * Select properties using an xpath expression 
 * 
 * @param contextNode - the context node for relative expressions etc
 * @param XPath - the xpath string to evaluate
 * @param parameters - parameters to bind in to the xpath expression
 * @param namespacePrefixResolver - prefix to namespace mappings
 * @param followAllParentLinks - if false '..' follows only the primary parent links, if true it follows all 
 * @return a list of property values 
 * TODO: Should be returning a property object 
 */
 public List<Serializable> selectProperties(NodeRef contextNode, 
                                            String XPath, 
                                            QueryParameterDefinition[] parameters, 
                                            NamespacePrefixResolver namespacePrefixResolver, 
                                            boolean followAllParentLinks);

1.1 Overview

Jaxen is used to evaluate the xpath expression using a custom document navigator. That means a full XPath implementation is available. The down side is that it uses the node service to navigate the node structure, essentially in the same way an XPath expression would be used against and XML DOM model. So whilst it is complete some queries will not be performant; particularly unconstrained full text search.

There are two methods to distinguish selecting only attributes and only elements. At the moment there is no support for selecting a mixture of properties and nodes. The XPath implementation supports the standard $namespace:name variable substitution and has the additional functions required by the JSR 170 specification (which hide some inbuilt functions such as contains())

Function extensions

like (SQL like pattern expressions using ? to match a singale character and % to match a string
contains (Google like full text search - in fact, the Lucene way)
deref (to follow references from reference properties to nodes

To suport these functions the node service interface defines the like() and contains() methods which are optionally supported by node service implementations. The indexing node service supports them fully.

Note: the functions contains() and like() can contain wild card elements at the start of the query but this may have performance issues.

The repository supports nodes with multiple parents. The is a much better alternative to reference nodes and can be used to avoid the limitiations with the deref() function. This raises the issue of a node having mutiple parents. The meaning of ‘..’ in path expression could be ‘find all parents’ or ‘find my primary parent’. This behaviour is controlled using the followAllParentLinks parameter on the methos calls.

XPath expressions are executed in the context of a given node - so that relative xpath expressions can be evaluated.
The store root node is ‘/‘.

A name space prefix resolver is always required. For any XPath implementation there needs to be a way to map from the prefixes used in the XPath expression to the actually URIs that they represent. For example ‘/alf:space’ would need to map ‘alf’ to the alfresco URI. The name space prefix resolver provides this support (as well as the information to navigate the name space axis, if required).

Parameters are provided as parameter defintions where the default value is used as the actual value. This identifes the fully qualified name and the type used to select the appropriate XPath type. Lists of node and attributes as parameters are not supported. We do not have property types to support this at the moment.

NOTE:

  • Property Objects
  • Collection types?

1.2 XPath Functions Available

1.2.1 Functions on Boolean Values

  • boolean
  • not
  • false
  • true

1.2.2 Functions on Numeric Values

  • number
  • ceiling
  • floor
  • round

1.2.3 Aggregate Functions

  • count
  • sum

1.2.4 Context Functions

  • last
  • position

1.2.5 Functions that Generate Sequences

  • id
  • document

1.2.6 Functions on Strings

  • string
  • concat
  • contains
  • normalize-space
  • starts-with
  • string-length
  • substring-after
  • substring-before
  • substring
  • translate

1.2.7 Functions on Nodes

  • name
  • namespace-uri
  • lang

1.2.8 Extension Functions

  • matrix-concat
  • evaluate
  • lower-case
  • upper-case
  • ends-with
  • subtypeOf
  • hasAspect
  • deref
  • like
  • contains
  • first

1.2.9 JCR Functions

  • jcr:like
  • jcr:score
  • jcr:contains
  • jcr:deref

1.3 Comparison with JSR 170

There are some differences between JSR 170 and what is provided here:

  1. This is a complete XPath implementation
  2. the like function currently also uses * meaning the same as # (could be fixed by changing the lucene implementation of wild card queries to use ? and %, not ? and *.
  3. the contains function will look at all attributes on a node and the full text representation of any content
  4. the contains function can be constrained to one attribute and the full text index
  5. the deref function can not be used in a path (as shown in the JSR 170 examples) - Jaxen does not support this
  6. the deref function must be given the full path of the attribute to dereference

1.4 Examples

Two simple examples to illustrate use in code.

// A name space resolver is required - this could be the name space service
DynamicNamespacePrefixResolver namespacePrefixResolver = new DynamicNamespacePrefixResolver(null);
namespacePrefixResolver.addDynamicNamespace(NamespaceService.ALFRESCO_PREFIX, NamespaceService.ALFRESCO_URI);
namespacePrefixResolver.addDynamicNamespace(NamespaceService.ALFRESCO_TEST_PREFIX, NamespaceService.ALFRESCO_TEST_URI);

// Select all nodes below the context node
List<ChildAssocRef> answer =  searchService.selectNodes(rootNodeRef, '*', null, namespacePrefixResolver, false);
// Find all the property values for @alftest:animal
List<Serializable> attributes = searchService.selectProperties(rootNodeRef, '//@alftest:animal', null, namespacePrefixResolver, false);

Other xpath examples and explanations:

Find all nodes with an @alftest:animal property equal to 'monkey'
'//.[@alftest:animal='monkey']'
Find all nodes directly linked to the current node
'*'
Find all nodes with one node between them and the current node
'*/*'
Find all nodes with two nodes between them and the current node
'*/*/*'
Find all nodes with three nodes between them and the current node
'*/*/*/*'
Find the parents of all nodes with three nodes between them and the current node
'*/*/*/*/..'
This may not be the same as '*/*/*' as nodes have multiples parents.
e.g. Going down we may follow a non primary child relationship and then navigate up the primary child relationship
     We may go up all parent relationships
     (We could control navigating only primary relationships)
Find all nodes below the context node (excluding the context node) 
'*//.'
Follow a named path from the current context node 
'alftest:root_p_n1'
Find all nodes below the context node (excluding the context node) that have an @alftest:animal property
'*//.[@alftest:animal]'
Find all nodes below the context node (excluding the context node) that have an @alftest:animal property equal to 'monkey'
'*//.[@alftest:animal='monkey']'
Find all nodes that have an @alftest:animal property equal to 'monkey'
(This will navigate to all nodes in the store and will have performance issues) 
'//.[@alftest:animal='monkey']'
Find all nodes that have an @alftest:animal property equal to the value of the variable $alf:test
'//.[@alftest:animal=$alf:test]'
Find the principal parent or all parents of the current context node
'..'
Find the values of all properties @alftest:animal
Again this will have performance issues as it will visit all nodes and all properties
'//@alftest:animal'
Find the values of all properties @alftest:reference
Again this will have performance issues as it will visit all nodes and all properties
'//@alftest:reference'
Derefernce the node identified by the attributes at /alftest:root_p_n1/alftest:n1_p_n3/@alftest:reference
The second attribute of the deref() function is not used at the moment
'deref(/alftest:root_p_n1/alftest:n1_p_n3/@alftest:reference, )'
Find all nodes in the store that have an attribute @alftest:animal ending with monkey
Again, this will visit all nodes in the repository.
'//*[like(@alftest:animal, '*monkey')]'
Find all nodes in the store that have an attribute @alftest:animal starting with monk
Again, this will visit all nodes in the repository.
'//*[like(@alftest:animal, 'monk*')]'
Find all nodes in the store that have an attribute @alftest:animal starting with monk
Again, this will visit all nodes in the repository.
'//*[like(@alftest:animal, 'monk%')]'
Find all nodes in the store that have an attribute @alftest:animal that equal monk%
Again, this will visit all nodes in the repository.
TODO: check the requirements for escaping here
'//*[like(@alftest:animal, 'monk\%')]'
Find all the nodes with any attribute or content containing 'monkey'
This query will have the worst performance. It visits all nodes and searches an appropriate index for the full text   
and all attribute values. It is much more efficient to use the searcher API.
'//*[contains('monkey')]'
Find all the values of any attribute wher the attrbute or content contains 'monkey'
This query will have the worst performance. It visits all nodes and searches an appropriate index for the full text   
and all attribute values. It is much more efficient to use the searcher API.
'//@*[contains('monkey')]'
Find all the nodes with any attribute or content containing 'mon?ey' e.g. monkey, monaey, ...
This query will have the worst performance. It visits all nodes and searches an appropriate index for the full text   
and all attribute values. It is much more efficient to use the searcher API.
'//*[contains('mon?ey')]'
Find all the values of any attribute wher the attrbute or content contains 'mon?ey'
This query will have the worst performance. It visits all nodes and searches an appropriate index for the full text   
and all attribute values. It is much more efficient to use the searcher API.
'//@*[contains('mon?ey')]'
Similar pattern examples to teh above
'//*[contains('m*y')]'
'//@*[contains('mon*')]'
'//*[contains('*nkey')]'
'//@*[contains('?onkey')]'
文档更新时间: 2020-02-11 11:36   作者:凌云文档