Home > Software engineering >  How can I correct this XSLT code so that it gives the expected result?
How can I correct this XSLT code so that it gives the expected result?

Time:06-09

XML:

 <?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xml" ?>

<menu>
  <appetizers title="Work up an Appetite">
    <dish id="1" price="8.95">Crab Cakes</dish>
    <dish id="2" price="9.95">Jumbo Prawns</dish>
    <dish id="3" price="10.95">Smoked Salmon and Avocado Quesadilla</dish>
    <dish id="4" price="6.95">Caesar Salad</dish>
  </appetizers>
  <entrees title="Chow Time!">
    <dish id="5" price="19.95">Grilled Salmon</dish>
    <dish id="6" price="17.95">Seafood Pasta</dish>
    <dish id="7" price="16.95">Linguini al Pesto</dish>
    <dish id="8" price="18.95">Rack of Lamb</dish>
    <dish id="9" price="16.95">Ribs and Wings</dish>
  </entrees>
  <desserts title="To Top It Off">
    <dish id="10" price="6.95">Dame Blanche</dish>
    <dish id="11" price="5.95">Chocolat Mousse</dish>
    <dish id="12" price="6.95">Banana Split</dish>
  </desserts>
</menu>

XSLT code:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="utf-8"/>

<xsl:param name="week">2</xsl:param>

<xsl:template match="/">

 <xsl:variable name="weekmenu">
  <xsl:call-template name="getmenu"/>
 </xsl:variable>
 
 <xsl:call-template name="displaymenu">
  <xsl:with-param name="menu" select="$weekmenu"/>
 </xsl:call-template>
 
</xsl:template>

<xsl:template name="getmenu">
 <xsl:copy-of select="/menu/appetizers/dish[position() = ((($week - 1) mod count(/menu/appetizers/dish))   1)]" />
 <xsl:copy-of select="/menu/entrees/dish[position() = ((($week - 1) mod count(/menu/entrees/dish))   1)]" />
 <xsl:copy-of select="/menu/desserts/dish[position() = ((($week - 1) mod count(/menu/desserts/dish))   1)]" />
</xsl:template>

<xsl:template name="displaymenu">
 <xsl:param name="menu"/>
  <xsl:if test="$menu">
   <xsl:text>This week's menu:</xsl:text>
   <xsl:for-each select="$menu/dish">
    <xsl:text>- </xsl:text><xsl:value-of select="."/>
    <xsl:text> $</xsl:text><xsl:value-of select="@price"/>
   </xsl:for-each>
  </xsl:if>
</xsl:template>

</xsl:stylesheet>

What I get as a result of applying the above XSLT to XML file is the following:

This week’s menu:

And what I expect is:

This week’s menu:
- Caesar Salad $6.95
- Rack of Lamb $18.95
- Banana Split $6.95

How can I obtain the desired output? I'm new to XSLT so any thoughts will be appreciated.

Thank you!

CodePudding user response:

$weekmenu and $menu are result tree fragments. You cannot evaluate a path on a result tree fragment, therefore $menu/dish is invalid.

The function exsl:node-set exists outside of the XSLT 1.0 standard, but is widely supported by XSL processors. It allows you to convert the result tree fragment into a node set and then proceed as you intend:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:exsl="http://exslt.org/common">
...
 <xsl:call-template name="displaymenu">
  <xsl:with-param name="menu" select="exsl:node-set($weekmenu)"/>
 </xsl:call-template>
...
</xsl:stylesheet>

CodePudding user response:

Assuming I understand correctly the logic you want to apply here - couldn't you do simply:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="utf-8"/>

<xsl:param name="week" select="2"/>

<xsl:template match="/menu">
    <xsl:text>This week's menu:&#10;</xsl:text>
    <xsl:for-each select="*">
        <xsl:variable name="dish" select="dish[($week - 1) mod last()   1]" />
        <xsl:text>- </xsl:text>
        <xsl:value-of select="$dish"/>
        <xsl:value-of select="format-number($dish/@price, ' $0.00')"/>
        <xsl:text>&#10;</xsl:text>
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>
  • Related