Example:

The following example is from the real templates included in DocFlex/Javadoc.

The task was the following.

For an element representing a Java interface, we need to obtain all Java classes implementing that interface.

The list of interfaces implemented by a class includes:

  1. All interface directly implemented by the given class.
  2. All interfaces directly implemented by all ancestors of the given class.
  3. All ancestors of all directly implemented interfaces.
This task is rather tricky. Even though it is imaginable to write a query which would collect all implementing classes for a particular interface, it is obvious that each time such a query is executed it would involve looking through nearly all elements representing all classes and interfaces in the project. Clearly, without a special solution, such a processing would just stop the execution of the template!

Using an element map provides a necessary solution. Here's how this can be done.

The element map is created with the following call:


  prepareElementMap (
    "all-known-implementing-classes",
    findElementsByLPath (mainContext.rootElement,
      "classes^::ClassDoc[!getAttrBooleanValue('isInterface')]"
    ),
    FlexQuery (getElementIds (
      findElementsByLRules (
        Array (
          LocationRule ("* -> interfaces^::ClassDoc", true),
          LocationRule ("* -> superclass^::ClassDoc", true)
        ),
        "ClassDoc",
        FlexQuery (getAttrBooleanValue("isInterface"))
      )
    )),
  )
Here's the explanation for all parameters:
(1)

"all-known-implementing-classes"
This specifies the map identifier. It's just a string since that map is the only one for the whole generation session.
(2)

findElementsByLPath (mainContext.rootElement,
  "classes^::ClassDoc[!getAttrBooleanValue('isInterface')]"
)
This actually provides an enumeration of all classes in the project.
(3)

FlexQuery (getElementIds (
  findElementsByLRules (
    Array (
      LocationRule ("* -> interfaces^::ClassDoc", true),
      LocationRule ("* -> superclass^::ClassDoc", true)
    ),
    "ClassDoc",
    FlexQuery (getAttrBooleanValue("isInterface"))
  )
))
This is a keys subquery. It returns an array of the unique identifiers of all interfaces implemented by a given class. Those identifiers will be the hash keys associated with the given class element in the map.

The prepareElementMap() function call shown above may be specified at any location within templates before the point where the element map may be actually used. Best of all, probably, this may be somewhere within the initialization expression of the main template (see Template Properties Dialog | Processing | Init/Finish | Template Init Expression). In any case, the element map will be created only once. See prepareElementMap() function description for details.

Now, let's look how that element map may be used.

Let's suppose, the interested interface, for which we want to obtain the list of all classes implementing it, is presented by the interface element (e.g. this may be a local variable or the generator's current element). Then, the following call will return an enumeration of the classes we need:


findElementsByKey (
  "all-known-implementing-classes",
  interface.id
)
The first parameter is the element map identifier. The second parameter specifies the hash key. According to how that particular element map was created, the hash keys are the unique identifiers of the elements representing the interfaces.

See Also:

GOMElement.id, findElementsByLPath(), findElementsByLRules(), FlexQuery()