Location Rules are special declarations that allow defining a recurrent interpretation of several interacting Location Paths.
Each Location Rule is specified as a text expression (called Location Rule Specification), which has the following form:
The rule can be interpreted against a certain initial (context) element and produce a set of other (result) elements. At that, the settings above have the following meaning:matching_ETs [matching_condition] -> element_location_path
matching_ETs
Specify the rule's Matching Element Type(s), which may have one of the forms:The rule interpretation starts from testing if the context element complies with at least one of the specified Matching Element Types. If it does not, the rule is passed over.
- A single Element Type name.
- The expression:
where each(ET1 | ET1 | ... | ETn)
ETn
is an Element Type name.- The asterisk wildcard (
*
), which will include all elements regardless of their type
matching_condition
Specify an additional (optional) Matching Condition for the context element.This should be a boolean FlexQuery expression. If it is specified, once the rule's context element is found to comply with the Matching Element Type(s), it is set as the generator context element and the query is executed. If it returns
true
, the rules is processed further, otherwise, it is passed over.
element_location_path
Once both matching tests passed, the Element Location Path specified in the right part of the rule (after the arrow) is processed against the context element. This produces a new set of elements, which becomes the rule's interpretation result.
Examples:
The following are specifications of some Location Rules used in real applications:
* -> descendant::class package -> child-or-self::package/child::class *[isVisible()] -> superclass^::ClassDoc (Package|ProgramElement) -> AnnotationDesc
Location Rule Sets
To program searching of elements, several Location Rules are defined together as a single set.
Some of the rules may be tagged with a special Recursive Flag. Such rules are called Recursive Location Rules.
The whole set of Location Rules is interpreted against a certain initial context element according to the following steps:
Step 1: All Location Rules specified in the set are interpreted against the initial context element. The elements generated by each rule are added to the total result set.
Step N+1: For each new element generated at the previous step, those Location Rules marked with the recursive flag are interpreted with this element selected as the rule's context element. The new generated elements are added to the total result set. This step is repeated until at the previous step no new elements have been produced.
At the end, the elements accumulated in the total result set become the final interpretation result.
Using Location Rules
Location Rules are used in Element Iterator sections of templates to define collecting of the iterated elements.
However, they can be equally used within FlexQuery expressions.
A set of Location Rules can be created as an array (using Array()
function), whose elements must be objects returned by calls
LocationRule()
function, which defines a single Location Rule.
Further, that array must be passed to findElementsByLRules()
function
along with the initial element against which the rules are to be interpreted.
That function will return an enumeration of all found elements.
Example:
As example of using Location Rules, let's consider the following model.
The model describes a certain Java project and may be built of elements of various types. We shall focus on only two Element Types:
Java classes and interfaces have the following relationships:'Class'
-- represents a Java class
'Interface'
-- represents a Java interface
Classes/interfaces may extend other classes/interfaces, which is reflected by the'extends'
attribute in both'Class'
and'Interface'
Element Types.
Classes may also implement certain interfaces, which is reflected by theUsing DTD specification, those attributes may be described as the following:'implements'
attribute in the'Class'
Element Types.
Now, let's we want to collect all interfaces implemented by a certain class. This would include:<!ATTLIST Class extends IDREF> <!ATTLIST Interface extends IDREFS> <!ATTLIST Class implements IDREFS>
'classElement'
parameter:
/* defining the set of Location Rules (the 'true' parameter means
'recursive rule') */
/* calling interpretation of the Location Rules
(the last parameter specify that the elements included in
the result enumeration should be filtered out to comply with
the 'Interface' element type) */
|