xsl-list
[Top] [All Lists]

Answers to review questions in "Beginning XSLT": Chapter 7

2003-03-14 13:36:58
Hi all,
Here are my answers to the review questions in Ch. 7 of Tennison's
"Beginning XSLT".  Comments, corrections or clarifications are appreciated.
My hope is that these threads (including responses), stored in the archive,
can be of value to anyone working through Beginning XSLT and wanting to check
their answers.


Ch. 7

1. Draw a node tree for the following document, including
   whitespace-only text nodes, whitespace in text nodes, the
   namespaces of the elements and attributes, and namespace nodes:

<Films xmlns="http://www.example.com/Films";>
  <Film year="1994">
    <Name>The Shawshank Redemption</Name>
    <per:Director xmlns:per="http://www.example.com/People";>
      Frank Darabont
    </per:Director>

  </Film>
</Films>


Answer:

root:/
|
|-element: {http://www.example.com/Films} Films
  |=namespace: xml {http://www.w3.org/XML/1998/namespace}
  |    [The book didn't mention the xml namespace nodes, though it did
  |     say any namespace-aware application understands the xml: prefix
  |     automatically.  These nodes were generated by both Saxon and IE.]
  |=namespace: {http://www.example.com/Films}
  |
  |-text: &#xA;&#x20;&#x20;
  |
  |-element: {http://www.example.com/Films} Film
  | |=namespace: xml {http://www.w3.org/XML/1998/namespace}
  | |=namespace: (default) {http://www.example.com/Films}
  | |=attribute: {} year: 1994
  | |
  | |-text: &#xA;&#x20;&#x20;&#x20;&#x20;
  | |
  | |-element: {http://www.example.com/Films} Name
  | | |=namespace: xml {http://www.w3.org/XML/1998/namespace}
  | | |=namespace: {http://www.example.com/Films}
  | | |
  | | |-text: The Shawshank Redemption
  | |
  | |-text: &#xA;&#x20;&#x20;&#x20;&#x20;
  | |
  | | element: {http://www.example.com/People} Director
  | | |=namespace: xml {http://www.w3.org/XML/1998/namespace}
  | | |=namespace: {http://www.example.com/Films}
  | | |=namespace: per {http://www.example.com/People}
  | | |
  | | |-text: &#xA;&#x20;&#x20;&#x20;&#x20;&#x20;&#x20;Frank 
Darabont&#xA;&#x20;&#x20;&#x20;&#x20;
  | |
  | |-text: &#xA;&#xA;&#x20;&#x20;
  |
  |-text: &#xA


2. What would the node tree from the previous question look like if you included
   the following in your XSLT stylesheet?

<xsl:strip-space elements="Films" />


Answer:

The two whitespace-only text nodes that are children of the Films element
would be gone.


3. What kinds of nodes do the following patterns match? What are the default
priorities of templates that use these patterns

Answer:

text() -- Any text node. -0.5 
text()[normalize-space()] -- Any text node that contains non-whitespace. 0.5
Program//comment() -- Any comment node descendant of any element named
  Program. 0.5
CastMember[1] -- Any CastMember element that is the first CastMember child of
  its parent (in document order). 0.5
CastMember[position() != last()] -- Any CastMember element that
  is not the last CastMember child of its parent. 0.5
tv:Program -- Any element Program whose namespace URI is the one associated
  in the stylesheet with the tv: prefix. 0
@xsi:* -- any attribute node in the namespace associated in the stylesheet
  with the xsi: prefix. -0.25
Actor/Name | Character/Name -- any element called Name whose parent is
  called either Actor or Character. 0.5


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
*[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.
*[local-name() = 'Program'] -- any child element of . named "Program",
  regardless of any prefix or namespace.
*[namespace-uri() = 'http://www.example.com/TVGuide'] -- same as tv:*
*[local-name() = 'Program' and
  namespace-uri() = 'http://www.example.com/TVGuide'] -- same as tv:Program


5. Add XML comments to the following XSLT extract to explain what it does:

Answer:

    <!-- 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's parent has children of the same name
           (which is always true... probably not what we want) -->
      <xsl:if test="../*[name() = $name]">
        <!-- output a base-zero index predicate,
             e.g. [1] if this is the 2nd one. -->
        [<xsl:value-of select="count(preceding-sibling::*[name() = $name])" />]
      </xsl:if>
    </xsl:for-each>
    <!-- Result: output the path of the current node. -->


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. -->


6. Create a location path that selects, from a <Program> element, the
   <Series> children of the preceding <Program> elements in the same
   <Channel> element (in other words, siblings of the current
   <Program> element).

Answer:

  select="preceding-sibling::Program/Series"


7. Based on the answer to the previous question, create an expression
   that tests whether the current <Program> element's <Series> child
   element *is*the*same*as* the <Series> element child of any preceding
   <Program> elements in the same <Channel> element.

     (* I take this to mean "is = to; i.e. has the same string value as")

Answer:

  test="Series = preceding-sibling::Program/Series"


8. Based on the answer to the previous question, create a location
   path that selects, from a <Channel> element, all those <Program>
   elements whose <Series> child element is NOT the same as any
   <Series> element child of the preceding <Program> elements in the
   same <Channel> element.

Answer:

  select="Program[not(Series = preceding-sibling::Program/Series)]"


Lars


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