My intent is in an XSL, to display only once the text node for set of nodes with a common value. For example, I have the following XML:
<Nodes>
<Node att="1">A</Node>
<Node att="1">B</Node>
<Node att="2">C</Node>
<Node att="2">D</Node>
<Node att="3">E</Node>
</Nodes>
My output would be: "ACE"开发者_如何学编程.
I don't know what the values of the attribute "att" will be. It can be any string.
Any suggestion would be greatly appreciated!
This can even be done just in a single XPath expression:
/*/*[not(@att=preceding-sibling::*/@att)]/text()
So, wrapping it in XSLT gives us:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:copy-of select="/*/*[not(@att=preceding-sibling::*/@att)]/text()"/>
</xsl:template>
</xsl:stylesheet>
and applying this to the provided XML document:
<Nodes>
<Node att="1">A</Node>
<Node att="1">B</Node>
<Node att="2">C</Node>
<Node att="2">D</Node>
<Node att="3">E</Node>
</Nodes>
produces the wanted, correct result:
ACE
It's a FAQ. See http://www.jenitennison.com/xslt/grouping/muenchian.html
This 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="xml" indent="yes" encoding="UTF-8"/>
<xsl:key name="criteria" match="/Nodes/Node" use="@att"/>
<xsl:template match="Nodes">
<xsl:copy>
<xsl:apply-templates select="Node[generate-id() = generate-id(key('criteria', @att))]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Node">
<xsl:copy-of select="."/> <!-- Or other actions -->
</xsl:template>
</xsl:stylesheet>
Will provide the desired (if I understood correctly) output:
<?xml version="1.0" encoding="UTF-8"?>
<Nodes>
<Node att="1">A</Node>
<Node att="2">C</Node>
<Node att="3">E</Node>
</Nodes>
It would also work with input like, for example:
<Nodes>
<Node att="someRandomString">A</Node>
<Node att="1aeawe">B</Node>
<Node att="someRandomString">C</Node>
<Node att="sfdf">D</Node>
<Node att="">E</Node>
<Node att="sfdf">F</Node>
</Nodes>
Output will be:
<?xml version="1.0" encoding="UTF-8"?>
<Nodes>
<Node att="someRandomString">A</Node>
<Node att="1aeawe">B</Node>
<Node att="sfdf">D</Node>
<Node att="">E</Node>
</Nodes>
This little stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:key name="kNodeByAtt" match="Node" use="@att"/>
<xsl:template match="Node[count(.|key('kNodeByAtt',@att)[1])!=1]"/>
</xsl:stylesheet>
Output:
ACE
Edit: Just for fun XPath 2.0 solution
string-join((/Nodes/Node)[index-of(/Nodes/Node/@att,@att)[1]],'')
Result:
ACE
精彩评论