开发者

In XSL, do something like in C# : list.Select(x=>x.ID).Distinct();

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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜