XSLT 2.0 and XPath 2.0 Programmer's Reference, 4th Edition (721 page)

BOOK: XSLT 2.0 and XPath 2.0 Programmer's Reference, 4th Edition
9.27Mb size Format: txt, pdf, ePub

The next stage is to convert this flat sequence into a hierarchy, in which lines with
level=“1”
(for example) turn into XML elements that contain the corresponding
level=“2”
lines.

Any problem that involves adding hierarchic levels to the result tree can be regarded as a grouping problem, and it should therefore be no surprise that we tackle it using the

instruction. A group in this case consists of a level N element together with the following elements up to the next one at level N. So this is a positional grouping rather than a value-based grouping. The option that we use to tackle this is the
group-starting-with
attribute, whose value is a match pattern that is used to recognize the first element in each group.

A single application of

creates one extra level in the result tree. In this example, we have a variable number of levels, so we want to apply the instruction a variable number of times. First, we group the overall sequence of

elements so that each level 0 line starts a new group. Within this group, we perform a further grouping so that each level 1 line starts a new group, and so on up to the maximum depth of the hierarchy. As one might expect, the process is recursive: we write a recursive template that performs the grouping at level N, and that calls itself to perform the level N+1 grouping. This is what it looks like:


  

  

  

                  group-starting-with=“*[xs:integer(@level) eq $level]”>

    

      

      

      

        

                        select=“current-group()[position() != 1]”/>

        

                        select=“$level + 1”/>

      

    

  


In the recursive call I originally set the population parameter to
current-group()
except .
. This ought to work, but it produces incorrect output in Altova. Altova also fails to indent the output—this is reasonable, since the specification advises against indenting data that is known to contain mixed content.

When this is called to process all the

elements with the
$level
parameter set to zero, it forms one group for each line having the attribute
level=“0”
, containing that line and all the following lines up to the next one with
level=“0”
. It then processes each of these groups by creating an element to represent the level 0 line (the name of this element is taken from the GEDCOM tag, and its ID and REF attributes are copied unless they are empty), and constructs the content of this new element by means of a recursive call, processing all elements in the group except the first, and looking this time for level 1 lines as the ones that start a new group. The process continues until there are no lines at the next level (the

instruction does nothing if the population to be grouped is empty).

The remaining code in the stylesheet simply invokes this recursive template to process all the lines at level 0:


  

    

    

  


This main template represents the entry point to the stylesheet. I added the attribute
match=“/”
because at the time of writing, the Altova XSLT 2.0 processor requires a source document to be supplied, even though it is not used. In principle, however, XSLT 2.0 allows a transformation to be invoked with no source document, by naming a template where execution is to start. I use the name
main
as a matter of convention.

Other books

Aftershock by Mark Walden
GirlNextDoor by Lyra Marlowe
Luca's Bad Girl by Amy Andrews
Vanished by Danielle Steel
Prairie Fire by Catherine Palmer
Paying the Price by Julia P. Lynde
The Roar of the Crowd by Rich Wallace