问题
I would like to know the best way to delimit xml output in an xsl transform. "position() != last()" doesn't always work because it makes assumptions about the input.
This toy example demonstrates:
<xsl:template match="/">
<html>
<body>
<xsl:for-each select="//cd">
<xsl:if test="title !='Unchain my heart'">
<xsl:value-of select="title" />
<xsl:if test="position() != last()">
<xsl:text>; </xsl:text> <!-- sometimes the delimiter will end if last element is a duplicate; -->
</xsl:if>
</xsl:if>
</xsl:for-each>
</body>
</html>
</xsl:template>
will result in
... Pavarotti Gala Concert; The dock of the bay; Picture book; Red;
note the trailing semicolon.
Any ideas?
(xml data from this example http://www.w3schools.com/xsl/tryxslt.asp?xmlfile=cdcatalog&xsltfile=cdcatalog)
回答1:
Change it to:
<xsl:for-each select="//cd[title !='Unchain my heart']">
<xsl:value-of select="title" />
<xsl:if test="position() != last()">
<xsl:text>; </xsl:text>
</xsl:if>
</xsl:for-each>
or in XSLT 2.0,
<xsl:value-of select="//cd/title[. !='Unchain my heart']" separator="; "/>
回答2:
One thing you can do is use the following::
axis to see if you're in the last title.
Example:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates select="catalog/cd/title[. != 'Unchain my heart']"/>
</body>
</html>
</xsl:template>
<xsl:template match="title">
<xsl:value-of select="."/>
<xsl:if test="following::cd/title[. != 'Unchain my heart']">
<xsl:text>; </xsl:text>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
You can still use that in your xsl:for-each
if you want to keep it.
Also, if you're using XSLT 2.0 you can use the separator
attribute on xsl:value-of
.
Example:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<html>
<body>
<xsl:value-of select="catalog/cd/title[. != 'Unchain my heart']" separator="; "/>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Also, if you're trying to drop the "Unchain my heart" title, try putting it in a predicate instead of the xsl:if
(it's not wrong, just less efficient and a lot more code to do the same thing).
Example:
//cd[title != 'Unchain my heart']
or
title[. != 'Unchain my heart']
回答3:
One way would be to make a preparatory sweep on the XML to pipeline it into a better structure.
The concept here is you make your own XML then evaluate it as a node-set (separate from the source XML). This is achieved via EXSLT's node-set()
method'
I just knocked up this XMLPlayground session - hope it helps. As you can see, no trailing colon.
http://www.xmlplayground.com/054Mj7
来源:https://stackoverflow.com/questions/10954091/delimiting-the-output-for-xslt-in-non-trivial-cases