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: </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> </xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>