Although eventually they are string, when you design a template in the Template Designer, the Location Paths are normally not needed to be entered directly. Rather, they are constructed using special dialogs or can be selected in the Location Path Chooser, as shown on this screenshot:
The structure of each Location Path used in FlexDoc is the same as in XPath and looks as the following:
Step1 / Step2 / ... / StepN
Step1, ..., StepN-1
StepN
The interpretation of a Location Step consists of taking some initial set of DSM nodes (called step input set) and producing by it another set of DSM nodes (called step result set). How exactly it is done depends on the step's settings (see below). Those settings, in fact, specify how the step is interpreted against only one initial node. The entire result set is produced as a union of the result sets of the step interpretations against every node in the input set.
As a whole, the Location Path is interpreted as follows:
Every Element Location Step has the following structure:
axis :: ETs [filter]
axis
child
axis::
prefix is specified in the location step).
self
child-or-self
descendant
descendant-or-self
attribute^
attribute
is the name of a certain context element's attribute
(whose type should be either IDREF
or IDREF[]
).
Such a specification is interpreted as follows:
When the context element contains an attribute with 'attribute'
name,
all values of that attribute are interpreted as the identifiers of some elements contained
in the DSM.
Each identifier is used to find a corresponding element, and, if found,
that element is added to the step's result set.
Example:
elementReference^::ClassDoc
{ expr }
The elements included in that axis are produced by a FlexQuery expression
specified between the curly brackets. The expression should return an enumeration
of new elements, which it may produce from the step's context node (the element)
passed to the expression as the
generator context element
(accessible via the contextElement
property).
For example, the step:
child::Person
{ findChildren("Person") }::Person
Note: The expression specified in formula-axis should always return the
Enumeration
type. Otherwise, the generator will raise an error.
GOMElement
or DSMElement
types (objects of other types will be ignored).
When null
value is returned, it is interpreted as the empty enumeration.
ETs
(ET1 | ET1 | ... | ETn)
,
where each ETn
is an Element Type name.
*
), which will include
all elements regardless of their type
filter
When specified, this subquery is executed for each element to be included in the step's result set.
The element is included only when the subquery returns true
.
The tested element is accessible within the subquery as the
generator context element
(via the contextElement
property).
The previous context element is restored again after the Location Path processing is finished.
@attribute
attribute
is the name of the searched attribute.
The Attribute Location Paths are normally used to collect values of
the same attribute by a number of elements at once.
The interpretation result of such a Location Path is a vector of all values of all attributes found.
lpath1 | lpath2 | ... | lpathN
Matching Element Types [matching condition] → Element Location Path
Matching Element Types
*
matching condition
false
the rule will be ignored.
This is similar to the enabling condition of template components.
The tested element is accessible within the expression as the
generator context element (via the contextElement
property).
Element Location Path
Exactly, it works as follows:
Matching Element Types
.
matching condition
specified,
the context element must also comply with it (i.e. the condition subquery returns true
).
Element Location Path
specified in the rule is interpreted against the context element. The new elements produced by it are added to the result set.
<!ELEMENT field> <!ELEMENT method> <!ELEMENT class (field*,method*,class*)> <!ELEMENT package (class*,package*)>
* → descendant::class
package → child-or-self::package/child::class
descendant
-axes.
At that, the search will involve all the element subtree attached to the context node.
However, in some situations it may be needed to limit the search to only some branches of the subtree.
Constructing Element Location Paths
using only descendant
-axes may be not enough to achieve the necessary effect.
Even more difficulties arise when the search in indefinite depth need to involve
link
- or
formula
-axes.
That problem was solved in FlexDoc by introducing Recursive Location Rules.
Recursive Location Rules are the same normal
Element Location Rules, but in addition marked with a special
recursive flag
.
This affects how such rules are interpreted.
A vector of Element Location Rules that includes some recursive rules is interpreted in repeating steps. On each step, some new elements are produced, which are added to the result set. Those new elements become also the input for the next step and so on, until no new elements are produced.
Precisely, this works as follows:
Such steps are repeated until no new elements are found.
FlexDoc distinguishes elements by their ID. Therefore, only those elements are considered the new ones whose IDs have not yet occured on the previous iterations. Such an approach helps to prevent the infinite looping when the processed elements contains cyclic references, however, it requires each element to have a unique ID.
The new DTD will be the following:
<!ELEMENT field> <!ELEMENT method> <!ELEMENT class (field*,method*,class*,interface*)> <!ELEMENT interface (field*,method*)> <!ELEMENT package (class*,interface*,package*)> <!ATTLIST class extends IDREF> <!ATTLIST interface extends IDREFS> <!ATTLIST class implements IDREFS>
class → extends^::class
class → implements^::interface
interface → extends^::interface
interface
type.
TargetETs
), which the elements included in the generated
EIS must comply with.
* → child::TargetETs * → descendant::TargetETs * → child-or-self::TargetETs * → descendant-or-self::TargetET
Defining a single Location Rule:
null
it is made the
context element.
Then, the expression is processed and the next element is produced.
TargetETs
), which the elements included in the generated
EIS must comply with.
contextElement
property).
The expression should return the Enumeration
type.
The returned enumeration should contain objects of GOMElement
or DSMElement
types (objects of other types will be ignored).
The null
value returned by the expression will be interpreted as empty enumeration.
On the other hand, it is an equivalent of the usage of formula
-axis
in a single Location Rule: * → { expr }::TargetETs
Precisely, this type of filtering works as follows:
true
, the element previously associated with
that key in the result enumeration is replaced with the current element.
Otherwise, the current element is skipped over and the processing goes to the next element.
The element is passed to the query as the generator context element.
The value returned by the query should be an object good to be a hash key. The null
value is also allowed.
When you need to filter elements by several keys
with different types so that only the whole set of keys generated for each element
must be unique, you can do it by creating a single compound filtering key
using HashKey()
function.
When specified, this query will be executed for each initial element whose key is repeating (that is, when there was an early processed element with the same key). The element is passed to the query as the generator context element.
If the query returns true
, the old element will be replaced with the current element in the result enumeration.
If the preference condition is not specified or returns false
,
the current element with the repeating key will be filtered out (removed from the result enumeration).
Conversely, specifying in this field only "true"
(which will be also a valid expression) will have an effect that for all initial elements
associated with the same key only the last of them will appear in the result enumeration.
true
, the element is included in the result enumeration.
Otherwise, it will be skipped over.
The tested element is passed to the query as the generator context element.
The elements of the EIS are sorted by the value of the specified attribute (according to its data type).
Additional settings:
The elements of the EIS are sorted by their names (i.e. the names of their Element Types) in lexicographical order. This option makes sense when the EIS contains many elements of the different types.
Additional settings:
The elements of the EIS are sorted by their values (regarding data types)
Additional settings:
This is the most general method of sorting the EIS. It includes all previous methods and allows much more, though it might seem a little complicated. In this case, the elements of the EIS are sorted by an arbitrary compound key generated for each element.
Each compound key consists of a certain sequence of the subkeys:
subkey1; subkey2; ...; subkeyN
Each subkey has its own method of calculation. This method also determines the subkey's data type, according to which the corresponding subkeys are compared.
The subkey calculation method can be specified as one of the following:
The value of the subkey is assigned from the value of an element or attribute retrieved by the specified Location Path. The Location Path is interpreted relatively to the EIS element for which the whole key is generated. The Location Path also determines the subkey's data type.
The value of the subkey is calculated by the specified FlexQuery-expression, which also determines the subkey's data type. The expression should derive the subkey value from the EIS element for which the whole key is generated. For doing so, the element is temporarily made the generator's context element and in this way can be accessed from within the expression.
For instance, this can be requested via settings of some template parameters.
This is controlled by the “Sorting Condition” – a boolean FlexQuery. When specified, it is calculated each time before sorting starts. When the query returnsfalse
, no sorting is done.
After the initial elements have been collected, filtered and sorted, the result sequence of elements is broken into groups according to the grouping keys generated for each element by the FlexQuery specified in the “Expression for Grouping Key” of the Element Iterator.
Each continuous subsequence of elements with equal grouping keys produces a group. As a result, the sequence of elements prepared for iterations is converted into a sequence of element groups. The ordering of elements in each group remains the same as in the initial sequence.
Since groups are not elements, the
Element Iterator
cannot iterate by them directly.
So, it will iterate by the first elements taken from each group.
However, at that, on each iteration step, the
'iterator.groupElements'
property will be updated so as
to provide the enumeration of all elements in the given group.
This allows you to specify a nested iterator that will iterate by the elements in the group.
In the simplest case, the iteration scope of the nested Element Iterator should be specified as custom with the following Expression for Element Enumeration:
parentIterator.groupElements
'GOMIterator.groupElements'
property are also available.
Notes:
'GOMIterator.groupElements'
property returns
a new element enumeration (i.e. a new
java.util.Enumeration
object) each time it is accessed.
But, the elements contained in the enumeration will be the same.
This allows you to specify several nested sibling
Element Iterators
(within the same parent one) to iterate the elements of the same group in different ways.