Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

choose branch based on node type? 1

Status
Not open for further replies.

csteinhilber

Programmer
Aug 2, 2002
1,291
US
I have the following XML generated by a legacy system.

Code:
  <retail_items>
      <book>
         <title>...</title>
         <author>...</author>
         <publish_date>...</publish_date>
      </book>
      <book>
         <title>...</title>
         <author>...</author>
         <publish_date>...</publish_date>
      </book>
      <cassette>
         <title>...</title>
         <artist>...</artist>
         <tracks>
             <track>...</track>
         </tracks>
      </cassette>
      <periodical>
         <title>...</title>
         <publisher>...</publisher>
         <frequency>...</frequency>
      </periodical>
      <book>
         <title>...</title>
         <author>...</author>
         <publish_date>...</publish_date>
      </book>
  </retail_items>

I can think of many ways to reformat the XML to make it more useful, but unfortunately that's not possible. Yet I still need to be able to apply XSLT to transform it into usable output (in this case, just HTML).

Anyway... the challenge is to apply unique templates depending on the type of node of each retail item (book, cassette, etc).

But the problem is that each of the items needs to output in the order that they are listed in the XML. So I can't simply do a
Code:
    <xsl:template match="book">
for instance (I don't think), because that would innevitably group all the books together.

The solution I thought would work would be to use a choose:when block... but I can't figure out how to compare the node type in the test expression.

I tried something like:
Code:
<xsl:stylesheet version="1.0" 
   xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform">[/URL]

   <xsl:template match="/">
      <xsl:apply-templates select="retail_items" />
   </xsl:template>


   <xsl:template match="retail_items">
     <xsl:choose>
     <xsl:when test="@XmlName = 'book'">
        <!-- eventually this would stub out to a template specifically for formatting a book, etc -->
        <p>It's a book!</p>
     </xsl:when>
     <xsl:when test="@XmlName = 'cassette'">
        <p>It's a cassette!</p>
     </xsl:when>
     <xsl:when test="@XmlName = 'periodical'">
        <p>It's a periodical!</p>
     </xsl:when>
     <xsl:otherwise>
        <p>Unrecognized item type</p>
     </xsl:otherwise>
     </xsl:choose>
   </xsl:template>
</xsl:stylesheet>

for the above XML, the desired output (at this testing stage at least) should be:
Code:
   It's a book
   It's a book
   It's a cassette
   It's a periodical
   It's a book

But I only get "Unrecognized item type" (and only one instance at that... which is equally confusing).

Anyone know how to compare the actual node type/name in a test expression? Or have any other insight as to how this could be accomplished?

Thanks!


-Carl
 
Nevermind... finally found the name() function.

Code:
<xsl:stylesheet version="1.0" 
   xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform">[/URL]

   <xsl:template match="/">
      <xsl:apply-templates select="retail_items" />
   </xsl:template>


   <xsl:template match="retail_items">
     <xsl:choose>
     <xsl:when test="name() = 'book'">
        <!-- eventually this would stub out to a template specifically for formatting a book, etc -->
        <p>It's a book!</p>
     </xsl:when>
     <xsl:when test="name() = 'cassette'">
        <p>It's a cassette!</p>
     </xsl:when>
     <xsl:when test="name() = 'periodical'">
        <p>It's a periodical!</p>
     </xsl:when>
     <xsl:otherwise>
        <p>Unrecognized item type</p>
     </xsl:otherwise>
     </xsl:choose>
   </xsl:template>
</xsl:stylesheet>

Is this the best/most efficient way to do this, given this mess of an XML file?


-Carl
 
Whoops... sorry... also had to go to a for-each loop... forgot about that.
Code:
<xsl:stylesheet version="1.0" 
   xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform">[/URL]

   <xsl:template match="/">

	   <xsl:for-each select="retail_items/*">
		 <xsl:choose>
		 <xsl:when test="name()='book'">
			<p>It's a book!</p>
		 </xsl:when>
		 <xsl:when test="name()='cassette'">
			<p>It's a cassette!</p>
		 </xsl:when>
		 <xsl:when test="name()='periodical'">
			<p>It's a periodical!</p>
		 </xsl:when>
		 <xsl:otherwise>
			<p>Unrecognized item type</p>
		 </xsl:otherwise>
		 </xsl:choose>
	   </xsl:for-each>
    </xsl:template>

</xsl:stylesheet>

Not quite sure why ??


-Carl
 
Just use apply-templates:
Code:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform">[/URL]
  <xsl:output method="xml" doctype-public="-//W3C//DTD XHTML 1.1//EN" doctype-system="[URL unfurl="true"]http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"[/URL] omit-xml-declaration="yes"/>
  <xsl:template match="/">
    <xsl:apply-templates select="retail_items"/>
  </xsl:template>
  <xsl:template match="retail_items">
    <html>
      <head>
        <title>My page</title>
      </head>
      <body>
        <xsl:apply-templates/>
      </body>
    </html>
  </xsl:template>
  <xsl:template match="book">
    <p>It's a book!</p>
  </xsl:template>
  <xsl:template match="cassette">
    <p>It's a cassette!</p>
  </xsl:template>
  <xsl:template match="periodical">
    <p>It's a periodical!</p>
  </xsl:template>
  <xsl:template match="node()">
    <p>Unrecognized item type</p>
  </xsl:template>
</xsl:stylesheet>

Jon

"I don't regret this, but I both rue and lament it.
 
Thanks Jon.

I couldn't get this to work when I tried it (hence the different tact)... but your example works great. Still trying to compare it against what I'd done earlier to see where I went wrong.


-Carl
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top