我有以下数据结构,需要使用v1
和v2
的每个组合输出每个节点的ID,其中v
等于A
。< / p>
应打印带有2,3,4,6,7
的节点。
<root>
<node>
<v>A</v>
<id>2</id>
<v1>S</v1>
<v2>S</v2>
</node>
<node>
<v>A</v>
<id>3</id>
<v1>S</v1>
<v2>S1</v2>
</node>
<node>
<v>A</v>
<id>4</id>
<v1>S2</v1>
<v2>S1</v2>
</node>
<node>
<v>B</v>
<id>5</id>
<v1>S2</v1>
<v2>S3</v2>
</node>
<node>
<v>A</v>
<id>6</id>
<v1>S2</v1>
<v2>S3</v2>
</node>
<node>
<v>A</v>
<id>7</id>
<v1>S</v1>
<v2>S3</v2>
</node>
<node>
<v>A</v>
<id>8</id>
<v1>S</v1>
<v2>S</v2>
</node>
</root>
我尝试使用xsl:key
,但遗憾的是只打印了唯一的元素(缺少id = 2)
如下所示使用preceeding
并未产生所需的结果。
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<!-- pos 1 -->
<xsl:key name="keys" match="node" use="concat(v1, '|', v2, '|', v)"/>
<!-- /pos 1 -->
<xsl:template match="root">
<xsl:for-each select="node[v='A']">
<!-- pos 1 -->
<xsl:variable name="vDups" select="key('keys', concat(v1, '|', v2, '|', v))[not(generate-id() = generate-id(current()))]" />
<xsl:if test="not($vDups)">
<node>
<xsl:value-of select="current()/id"/>
</node>
</xsl:if>
<!-- /pos 1 -->
<!-- pos 2 -->
<xsl:if test="not(preceding::node/v1=current()/v1 and preceding::node/v2 = current()/v2)">
<node>
<xsl:value-of select="id" />
</node>
</xsl:if>
<!-- /pos 2 -->
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
如何达到预期效果?
答案 0 :(得分:1)
更改密钥
<xsl:key name="keys" match="node" use="concat(v1, '|', v2, '|', v)"/>
到
<xsl:key name="keys" match="node" use="concat(v1, '|', v2, '|', v[.='A'])"/>
然后是身份模板
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
和无效模板,用于与第一次出现的键
不匹配的节点<xsl:template match="node[not(generate-id()=generate-id(key('keys', concat(v1, '|', v2, '|', v))[1]))]"/>
在行动here中查看。
答案 1 :(得分:1)
试试这个:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="keys" match="node" use="concat(v1, '|', v2,'|',v)"/>
<xsl:template match="node[v!='A']"/>
<xsl:template match="node[generate-id()!=generate-id(key('keys', concat(v1,'|',v2,'|',v))[1])]"/>
<xsl:template match="@* | node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
这有一个模板可以排除A
元素中没有v
的任何内容,另一个模板排除任何不是给定组合中的第一个。我已经包含了身份模板以按原样输出剩余的节点,但您可以将其替换为您需要的node
的任何处理。
免责声明:这是一个XSLT1解决方案,可能存在更高效的XSLT2解决方案。
答案 2 :(得分:1)
您已对此XSLT 2.0进行了标记,并在样式表中添加了version="2.0"
,在这种情况下,您可以使用xsl:for-each-group
来简化您的XSLT
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:template match="root">
<xsl:for-each-group select="node[v = 'A']" group-by="concat(v1, '|', v2)">
<node>
<xsl:value-of select="id"/>
</node>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>