问题
I'm pretty new to XSLT and I've been struggling to replicate the solution mentioned here XSL for-each: how to detect last node? for longer than I'm willing to admit :(
I've setup this fiddle. https://xsltfiddle.liberty-development.net/naZXVFi
I was hoping I could use just the value-of + separator, vs choose / when xslt tools, as it did seem more idiomatic.
- I can't get the separator to show up;
- nor can I select just the child of skill, I always get the descendants too. That's to say, I shouldn't see any
detail
in the output. - bonus: not sure why that meta tag is not self closing (warning in the html section)
Desired output:
skill1, skill2, skill3, skill4, skill5
(no comma space for the last one)
Any help would be greatly appreciated. Thanks.
EDIT: including the code here too: xml: (need to add ref to xslt):
<?xml version="1.0" encoding="utf-8" ?>
<?xml-stylesheet type="text/xsl" href="test.xsl"?> <!-- not in fiddle -->
<skills>
<skill>skill1</skill>
<skill>skill2</skill>
<skill>skill3
<details>
<detail>detail1</detail>
<detail>detail2</detail>
</details>
</skill>
<skill>skill4</skill>
<skill>skill5</skill>
</skills>
And test.xsl
:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
xmlns:array="http://www.w3.org/2005/xpath-functions/array"
exclude-result-prefixes="#all"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<xsl:output method="html" indent="yes" html-version="5"/>
<xsl:template match="/">
<html>
<head>
<title>.NET XSLT Fiddle Example</title>
</head>
<body>
<xsl:for-each select="/skills/skill">
<xsl:value-of select="." separator=", "/>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
回答1:
In general, with XSLT 2/3 to output a sequence separated by some separator string, you simply use xsl:value-of select="$sequence"
with the appropriate separator string in the separator
attribute (and no for-each
):
<xsl:template match="skills">
<xsl:value-of select="skill/text()[normalize-space()]/normalize-space()" separator=", "/>
</xsl:template>
https://xsltfiddle.liberty-development.net/naZXVFi/1
In most cases you would just need select="skill" separator=", "
but given your descendants and the white space you seem to want to eliminate the select
expression above is a bit more complicated.
回答2:
Martin has given you the detailed work-through to get the final result including getting rid of the extra spaces etc, but at a high level, here's how to use xsl:value-of
with separator
correctly.
You have:
<body>
<xsl:for-each select="/skills/skill">
<xsl:value-of select="." separator=", "/>
</xsl:for-each>
</body>
This says that for each skill node, take the content of that node and display it. Notably, the value-of only sees one skill at a time, so there is nothing to join with the comma separator.
The answer which would get you what you want is:
<body>
<xsl:value-of select="/skills/skill" separator=", "/>
</body>
This says to take the set of skill nodes and display them joined by comma separators. You can see the output at https://xsltfiddle.liberty-development.net/naZXVFi/4
来源:https://stackoverflow.com/questions/62005912/xslt3-joining-values-with-separator