2016-08-01 93 views
1

我周围搜索,发现这个网站上很多帖子是有用的让我这么远。确定独特的子节点数XSLT

我想使用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> 
+1

对于特定的问题(但对于所有XSLT问题),您需要明确您是否使用XSLT 1.0或2.0。解决方案可能非常不同。 –

回答

0

您使用Muenchian分组的,所以我假设你正在使用XSLT 1.0(一样大Muenchian分组的是,有更简单的方法在XSLT 2.0分组)。

但是你需要改变主要的是你的ChildKey的定义,你实际上是在寻找每一个可能的父属性不同的子元素,所以你需要定义像这样的关键:

<xsl:key name="ChildKey" match="child" use="concat(../@attribute, '|', .)"/> 

然后,你combined计数变量的设置如下,计算对于给定的parent属性的不同子元素:

<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> 
+0

谢谢。这工作完美! – gorticus