[xsl] Answers to review questions in "Beginning XSLT": Chapter 9

Subject: [xsl] Answers to review questions in "Beginning XSLT": Chapter 9
From: "Lars Huttar" <lars_huttar@xxxxxxx>
Date: Wed, 19 Mar 2003 15:21:19 -0600
1. Which two XSLT elements can be parents of <xsl:sort> elements?

Answer:
<xsl:apply-templates> and <xsl:for-each>.


2. What language is used when you sort alphabetically?

Answer:
The language specified by the 'lang' attribute of the <xsl:sort> element,
or by default, a language "determined from the system environment."
(XSLT rec)


3. What does the following piece of code do?

  <xsl:apply-templates select="Program">
    <xsl:sort select="position()" data-type="number" order="descending" />
  </xsl:apply-templates>

Answer:
This applies templates to all "Program" element children of the current node,
in reverse document order.


4. What order will the <Program> elements be sorted in with the following code?
  
  <xsl:variable name="series" select="'Series'" />
  <xsl:apply-templates select="Program">
    <xsl:sort select="$series" />
    <xsl:sort select="Title" />
  </xsl:apply-templates>

Answer:
They will be sorted by the value of the Title child element.
The first <xsl:sort> select sorts by the constant 'Series', so all
nodes will sort equally by this criterion.
Items that have an empty Title will come before those that have
a non-empty Title, and will be processed in document order
(guaranteed?).

To get the desired result, i.e. to sort by Series then Title,
change the first <xsl:sort> element to:
    <xsl:sort select="*[local-name()=$series]" />
This assumes we don't care about the namespace of the Series element,
which seems fine to me.  Otherwise we could insert "and namespace-uri()=''".
or whatever.


5. What does the following piece of code do?

  <xsl:variable name="sortType">
    <xsl:choose>
      <xsl:when test="$sortBy = 'rating'">number</xsl:when>
      <xsl:otherwise>text</xsl:otherwise>
    </xsl:choose>
  </xsl:variable>
  <xsl:apply-templates select="Program">
    <xsl:sort select="@rating[$sortBy = 'rating'] |
                      Series[$sortBy = 'series'] |
                      Title[$sortBy = 'title']"
              data-type="${sortType}" />
  </xsl:apply-templates>


Answer:

It processes the Program child elements, sorted by the value of either
their @rating attributes, their Series children, or their Title children,
as determined by the value of the variable $sortBy (which is probably
[based on] a parameter passed to the stylesheet).
The <xsl:sort>'s select attribute unions three nodesets, only one of
which will be non-empty, since $sortBy cannot be equal to more than
one of 'rating', 'series', or 'title'.  (Even if $sortBy is a nodeset?)
In effect this is a lot like the x ? y : z operator in C or the (cond ...)
expression in Lisp (without as much short-circuiting).

The $sortType variable ensures that if the sort criterion is a numeric
one (rating), XSL will sort numerically instead of alphabetically.


6. What two ways can you use to generate a number giving the position
   of a node within the source tree?

Answer:
position() and <xsl:number>.


7. What's the biggest difference between using position() and using
   <xsl:number> to number items?

<xsl:number> gives the number of a node based on its position in the
source tree.  position() gives the number based on its position in the
current node list.  (The current node list is determined by the
enclosing <xsl:for-each> or <xsl:apply-templates> instruction, or,
within an XPath expression, by the current step.)

<xsl:number>, being an instruction for generating text in the result
tree, also has facilities for formatting numbers in different
ways and numbering at multiple levels.


8. What does the following piece of code generate?

    <xsl:for-each select="Program">
      <xsl:variable name="format">
        <xsl:choose>
          <xsl:when test="position() mod 3 = 1">{1}</xsl:when>
          <xsl:when test="position() mod 3 = 2">[A]</xsl:when>
          <xsl:otherwise>(i)</xsl:otherwise>
        </xsl:choose>
      </xsl:variable>
      <xsl:number format="{$format}" />
      ...
    </xsl:for-each>

Answer:
It generates a horrible mess where the numbering goes {1}, [B], (iii),
{4}, [E], (vi), etc.  But I'd like to see it switch between Greek
and Hebrew, Thai and Tamil.  :-)  (Side note: out of curiosity, I tried
adding in a fourth format using Unicode Khmer digit one, &#x17E1;.
XSLT Programmer's Reference says any Unicode digit one should work.
Saxon processed it properly, generating &#6115; (Khmer digit three)
for the third item; but IE/MSXML didn't seem to recognize &#x17E1 as a digit.)


9. What different values can the level attribute on <xsl:number> take
   and how does its value change the numbering of a node?

Answer:

'single', 'any', or 'multiple'.
With level='single', we are computing position of a node among siblings.
With level='any', we are computing position within the whole document
regardless of level.
With 'multiple', we are computing multiple positions among siblings at
various levels.

All of these types of numbering are constrained by the 'count' and 'from'
patterns.  Position is computed in a list of nodes matching the 'count'
pattern, starting from the most recent node matching the 'from' pattern.


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread