Each Location Rule is specified as a text expression (called Location Rule Specification), which has the following form:
matching_ETs [matching_condition] -> element_location_path
matching_ETs
(ET1 | ET1 | ... | ETn)
ETn
is an Element Type name.
*
), which will include
all elements regardless of their type
matching_condition
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
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
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.
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:
'Class'
-- represents a Java class'Interface'
-- represents a Java interface
'extends'
attribute in both 'Class'
and 'Interface'
Element Types.
Classes may also implement certain interfaces, which is reflected by the
'implements'
attribute in the 'Class'
Element Types.
<!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') */
lrules = Array (
LocationRule("* -> extends^::(Class|Interface)", true),
LocationRule("Class -> implements^::Interace", true)
);
/* 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) */
findElementsByLRules(classElement, lrules, "Interface")