我已经四处搜索,发现这个网站上有很多帖子对我这么做很有帮助。
我正在尝试使用xslt来组合共享公共属性值的元素及其子元素。我已经设法使用xsl:keys执行此操作。
我坚持的部分是我还需要基本上重现原始树,除非具有特定属性的父元素与我正在生成的组合结构匹配,那么父元素应该没有子元素。您可以在提供的示例输入/输出中看到这一点。输出的第二部分中的<parent attribute="two"/>
没有子节点,因为它最初包含所有子节点。
XML输入格式:
<root>
<parent attribute="one">
<child>one</child>
<child>two</child>
<child>three</child>
</parent>
<parent attribute="two">
<child>one</child>
<child>two</child>
<child>three</child>
</parent>
<parent attribute="one">
<child>two</child>
<child>three</child>
<child>four</child>
</parent>
<extra>
<extra>
<parent attribute="two">
<child>three</child>
</parent>
</extra>
</extra>
</root>
所需的输出格式:
<root>
<first>
<new attribute="one">
<child>one</child>
<child>two</child>
<child>three</child>
<child>four</child>
</new>
<new attribute="two">
<child>one</child>
<child>two</child>
<child>three</child>
</new>
</first>
<second>
<parent attribute="one">
<child>one</child>
<child>two</child>
<child>three</child>
</parent>
<parent attribute="two"/>
<parent attribute="one">
<child>two</child>
<child>three</child>
<child>four</child>
</parent>
<extra>
<extra>
<parent attribute="two">
<child>three</child>
</parent>
</extra>
</extra>
</second>
</root>
我目前的尝试涉及重复使用为输出的第一部分创建的密钥。我的目标是简单地将总唯一子计数与当前父子计数进行比较,以确定当前父节点是否包含所有组合子节点。我尝试了许多类似的方法来产生这个组合计数,如下所示,但我开始认为我正在解决这个问题,因为我要么返回每个子元素的计数或当前父元素子计数。
我没有考虑保留第二部分的原始结构的其余部分,因为这不是当时的紧迫问题。
任何建议都将不胜感激。如果我不善于搜索而其他人有类似的问题,请随时指示我。
XSLT:
<?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"/>
<xsl:strip-space elements="*"/>
<xsl:key name="ParentKey" match="parent" use="@attribute"/>
<xsl:key name="ChildKey" match="parent/child" use="../@attribute"/>
<xsl:template match="@*|node()">
<xsl:apply-templates select="@*|node()" />
</xsl:template>
<xsl:template match="/">
<xsl:element name="first">
<xsl:for-each select="//parent[count(. | key('ParentKey', @attribute)[1]) = 1]">
<xsl:element name="new">
<xsl:attribute name="attribute">
<xsl:value-of select="@attribute"/>
</xsl:attribute>
<xsl:apply-templates select="child[count(. | key('ChildKey', @attribute)[1]) = 1]"/>
</xsl:element>
</xsl:for-each>
</xsl:element>
<xsl:element name="second">
<xsl:apply-templates select="//parent" mode="second"/>
</xsl:element>
</xsl:template>
<xsl:template match="child">
<xsl:element name="child">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
<xsl:template match="parent" mode="second">
<xsl:element name="parent">
<xsl:attribute name="attribute">
<xsl:value-of select="@attribute"/>
</xsl:attribute>
<!-- currently problematic line -->
<xsl:variable name="combinedCount" select="count(//parent/child[count(. | key('ChildKey', @attribute)[1]) = 1])"/>
<xsl:variable name="currentCount" select="count(child)"/>
<xsl:if test="not($combinedCount = $currentCount)">
<xsl:apply-templates select="child"/>
</xsl:if>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
答案 0 :(得分:0)
您正在使用Muenchian Grouping,所以我假设您使用的是XSLT 1.0(与Muenchian Grouping一样,在XSLT 2.0中有更简单的方法进行分组)。
但您需要更改的主要内容是您对ChildKey
的定义,因为您实际上正在为每个可能的父属性寻找不同的子元素,因此您需要像这样定义您的键:
<xsl:key name="ChildKey" match="child" use="concat(../@attribute, '|', .)"/>
然后,您的combined
计数变量设置如下,以计算给定父属性的不同子元素:
<xsl:variable name="combinedCount" select="count(key('ParentKey', @attribute)/child[count(. | key('ChildKey', concat(../@attribute, '|', .))[1]) = 1])"/>
试试这个XSLT。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="ParentKey" match="parent" use="@attribute"/>
<xsl:key name="ChildKey" match="child" use="concat(../@attribute, '|', .)"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<xsl:copy>
<first>
<xsl:for-each select="//parent[count(. | key('ParentKey', @attribute)[1]) = 1]">
<new attribute="{@attribute}">
<xsl:apply-templates select="child[count(. | key('ChildKey', @attribute)[1]) = 1]"/>
</new>
</xsl:for-each>
</first>
<second>
<xsl:apply-templates />
</second>
</xsl:copy>
</xsl:template>
<xsl:template match="parent">
<parent attribute="{@attribute}">
<!-- currently problematic line -->
<xsl:variable name="combinedCount" select="count(key('ParentKey', @attribute)/child[count(. | key('ChildKey', concat(../@attribute, '|', .))[1]) = 1])"/>
<xsl:variable name="currentCount" select="count(child)"/>
<xsl:if test="not($combinedCount = $currentCount)">
<xsl:apply-templates select="child"/>
</xsl:if>
</parent>
</xsl:template>
</xsl:stylesheet>