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

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

The
group-by
option also allows an item to belong to more than one group. Suppose that an employee can work for several departments, and that the
department
attribute is extended to be a whitespace-separated list of department names. If you are using a schema-aware processor that annotates this attribute as belonging to a list-valued type, then all the examples we have written above will handle this situation without change. When you write
group-by=“@department”
, the value of the expression is atomized, and if the type is a list-valued type, this will return the sequence of atomic values contained in the attribute. The item with this grouping key is then allocated to one group for each department. I was careful to output the department name by referring to

; if I had written

the output would have been rather confusing, because instead of listing the name of the single department to which all the employees in this group belong, the code would list all the deparments to which the first employee in the group belongs.

Using group-adjacent

The
group-adjacent
option attaches significance not only to the value of the grouping key but also to the order of items in the population. So it shouldn't be a surprise to find that many of its applications come with document-oriented XML, where order is typically much more signicant than with data-oriented XML. However, I've also seen it used with great effect to analyze time-sequence data.

Here's a simple but common example: given a


consisting of

elements and

elements, you want to convert the

elements into


elements, and the

elements into


  • elements, with a

      element wrapped around a sequence of consecutive bullets. You can do this as follows:


         


            

                           group-adjacent=“if (self::bullet) then 0 else position()”>

                 

            

         



      The grouping condition ensures that adjacent

      elements go in a group together, while each

      element goes in a group by itself (calling
      position()
      ensures each

      element gets a unique grouping key—you could also have used
      generate-id()
      ). We are only interested in the rule that processes the first bullet:


        


            

          



      This template rule processes the group of adjacent bullets by outputting the necessary


        element to the result tree, and inside this it creates the elements that represent each individual bullet, by calling another template rule (in a different mode) to process each one. The full stylesheet is in
        bullets.xsl
        , a sample source file in
        bullets.xml
        .

        Now look at a more complex example, involving the formatting of a Shakespeare play. You can download the text of all Shakespeare's plays, marked up in XML by Jon Bosak, at
        http://metalab.unc.edu/bosak/xml/eg/shaks200.zip
        .

        Example: Grouping Consecutive Elements by Name

        This example shows how to tackle a problem in which the content of an element (in this case, a

        ) consists of a number of

        elements followed by a number of

        elements.

        Source

        You can run this example on any of the Shakespeare plays. For convenience, the download directory contains the file
        ado-scene1.xml
        , containing the first scene from
        Much Ado About Nothing
        .

        In this markup, a

        element consists of a sequence of

        elements interleaved with stage directions. A

        contains one or more

        elements indicating who is speaking, and one or more

        elements indicating what they are saying. So in
        Hamlet
        you have speeches like this:


        HAMLET

        My fate cries out,

        And makes each petty artery in this body

        As hardy as the Nemean lion's nerve.

        Still am I call'd. Unhand me, gentlemen.

        By heaven, I‘ll make a ghost of him that lets me!

        I say, away! Go on; I‘ll follow thee.


        and also speeches with multiple speakers:


        ROSENCRANTZ

        GUILDENSTERN

        We'll wait upon you.


        There are very few occasions where Shakespeare allows two characters to speak together for more than a single line (the witches’ speech in
        Macbeth
        is tagged as
        ALL
        ), but here is an example from
        Timon of Athens
        :


        PHRYNIA

        TIMANDRA

        Well, more gold: what then?

        Believe‘t, that we’ll do any thing for gold.


        Output

        Suppose that you want to output each speech as a row in a table, with the speakers listed in one column and the text in the other. It should look like this (you wouldn't normally make the table cells visible in this way, but it helps to be able to see the structure):

        PHRYNIA TIMANDRA
        More counsel with more money, bounteous Timon.
        TIMON
        More whore, more mischief first; I have given you earnest.
        ALCIBIADES
        Strike up the drum towards Athens! Farewell, Timon: If I thrive well, I'll visit thee again.
        TIMON
        If I hope well, I'll never see thee more.

        Stylesheet

        So what does the stylesheet look like?

        The content of a

        element consists of two groups: a group containing consecutive

        elements and a group containing consecutive

        elements. So you could try to write it like this:


          

          

            

               

                  

                   

               

            

          

          


        Here we are using the name of an element as its grouping key.

        But I omitted one complication. Within the sequence of

        elements, there can also be a

        representing a stage direction, thus:


        TIMON

        Long live so, and so die.

        Exit APEMANTUS

        I am quit.

        More things like men! Eat, Timon, and abhor them.


        When this happens you would want to output it, in its proper place, in italics:

        TIMON
        Long live so, and so die.
        Exit APEMANTUS
        I am quit.
        More things like men! Eat, Timon, and abhor them.

        What does this do to the stylesheet?

        The second group, the one that comprises the right-hand column of the table, no longer shares a common element name. What you can do, however, is allocate

        elements to one group, and anything else to a different group.


          

          

                               group-adjacent=“if (self::SPEAKER) then 0 else 1”>

            

               

                  

                  

               

            

          

          


        The fact that you output the content of the

        and

        elements using

        means that you don't have to change the body of this rule to handle

        elements as well; all you need to do is add a template rule with
        match=“SPEECH/STAGEDIR”
        to handle them.

        To complete the stylesheet, you need to add template rules for the individual elements such as

        . These are straightforward, so I will not list them here. You can find the complete stylesheet in
        speech.xsl
        .

  • Other books

    Violets & Violence by Morgan Parker
    How Doctors Think by Jerome Groopman
    Stolen Hearts by Karen Erickson
    Pleasure Horse by Bonnie Bryant
    Benediction by Kent Haruf
    Possession by S.K. Falls
    Gathering Shadows by Nancy Mehl
    Saving CeeCee Honeycutt by Beth Hoffman