[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

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


Subject: Re: [xsl] Answers to review questions in "Beginning XSLT": Chapter 7
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Fri, 14 Mar 2003 23:14:51 +0000

Hi Lars,

> Here are my answers to the review questions in Ch. 7 of Tennison's
> "Beginning XSLT".

Just a couple of things:

> 4. Assuming that the prefix tv is associated with the namespace
> http://www.example.com/TVGuide within the stylesheet, what kinds of
> elements do the following expressions select?
>
> Answer:
>
> Program -- any child element of . named "Program" in no namespace
> tv:* -- any child element node of . in the http://www.example.com/TVGuide
>   namespace
> tv:Program -- any child element of . named "Program" in the
>   http://www.example.com/TVGuide namespace.
> *[name() = 'Program'] -- same as just Program

Not quite. When you use the name() function, what you get depends on
the prefix that was used in the source document. If, in the source
document, the http://www.example.com/TVGuide namespace is the default
namespace, as in:

  <Program xmlns="http://www.example.com/TVGuide">
    ...
  </Program>

then name() = 'Program' might return true for that element.

I say might because if the namespace is *also* declared with the
prefix 'tv', as in:

  <Program xmlns="http://www.example.com/TVGuide"
           xmlns:tv="http://www.example.com/TVGuide">
    ...
  </Program>

then the processor is free to return either "Program" or "tv:Program".
It doesn't matter what prefix was actually used on the element, only
what prefixes are declared for the element's namespace.

With that in mind, you might want to rephrase your answers to:

> *[starts-with(name(), 'tv:')] -- any child element of . that has
>   the 'tv:' prefix in the source document (regardless of what namespace
>   'tv:' may be associated with in either document).
> *[name() = 'tv:Program'] -- any child element of . named "Program"
>   with a 'tv:' prefix in the source document.

> 5. Add XML comments to the following XSLT extract to explain what it
> does:
[snip]
> Here's an adjusted version to change the [index] from base zero to
> base one; and to display the index only if the element in question
> has siblings of the same name (i.e. other than itself):
>
>     <!-- Loop through ancestors and . (in doc order) -->
>     <xsl:for-each select="ancestor-or-self::*">
>       <!-- set 'name' variable to name of current node, incl. prefix -->
>       <xsl:variable name="name" select="name()" />
>       <!-- output '/' and name. -->
>       /<xsl:value-of select="$name" />
>       <!-- If this node has siblings of the same name, -->
>       <xsl:if test="count(../*[name() = $name]) > 1">
>         <!-- output an index predicate, e.g. [2] if this is the 2nd one. -->
>         [<xsl:value-of select="count(preceding-sibling::*[name() = $name]) + 1"
>         />]
>       </xsl:if>
>     </xsl:for-each>
>     <!-- Result: output the path of the current node. -->

Excellent. In general I'd avoid using count() if you can because naive
processors are likely to collect all the nodes that the path selects
so that they can be counted. If you use:

  preceding-sibling::*[name() = $name] or
  following-sibling::*[name() = $name]

then a processor can stop looking once it's found the first preceding
or following sibling with the same name (and doesn't even have to look
at the following siblings if it finds a preceding sibling with the
same name).

This probably makes barely any difference to the performance of the
stylesheet unless there are loads and loads of siblings; it's more of
a style thing.

Cheers,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/


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



Current Thread
Keywords