在for-each中找到xslt的唯一节点

时间:2013-10-08 08:05:41

标签: xslt xslt-1.0

源XML:

<r:root xmlns:r="http://root/">
<p:parent xmlns:p="http://parent/">
    <p:name>John</name>
    <p:age>30</age>
    <c:child xmlns:c="http://child/">
        <c:cname>John_child_1</cname>
        <c:cage/>
        <c:ItemNumber>1</ItemNumber>
    </child>
    <c:child xmlns:c="http://child/">
        <c:cname>John_child_2</cname>
        <c:cage/>
        <c:ItemNumber>2</ItemNumber>
    </child>
    <c:child xmlns:c="http://child/">
        <c:cname>John_child_3</cname>
        <c:cage/>
        <c:ItemNumber>1</ItemNumber>
    </child>
</parent>
<p:parent>
    <p:name>Doe</name>
    <p:age>40</age>
    <c:child xmlns:c="http://child/">
        <c:cname>Doe_child_1</cname>
        <c:cage/>
        <c:ItemNumber>2</ItemNumber>
    </child>
    <c:child xmlns:c="http://child/">
        <c:cname>Doe_child_2</cname>
        <c:cage/>
        <c:ItemNumber>2</ItemNumber>
    </child>
</parent>
...
...
...

目标XML:

<root>
<f:father xmlns:f="http://father/">
    <f:name>John</name>
    <f:age>30</age>
    <f:UniqueItemNumber>1</UniqueItemNumber>
    <c:child xmlns:c="http://child/">
        <c:cname>John_child_1</cname>
        <c:cage/>
        <c:ItemNumber>1</ItemNumber>
    </child>
    <c:child xmlns:c="http://child/">
        <c:cname>John_child_3</cname>
        <c:cage/>
        <c:ItemNumber>1</ItemNumber>
    </child>
</father>
<f:father xmlns:f="http://father/">
    <f:name>John</name>
    <f:age>30</age>
    <f:UniqueItemNumber>2</UniqueItemNumber>
    <c:child xmlns:c="http://child/">
        <c:cname>John_child_2</cname>
        <c:cage/>
        <c:ItemNumber>2</ItemNumber>
    </child>
</father>
<f:father xmlns:f="http://father/">
    <f:name>Doe</name>
    <f:age>40</age>
    <f:UniqueItemNumber>2</UniqueItemNumber>
    <c:child xmlns:c="http://child/">
        <c:cname>Doe_child_1</cname>
        <c:cage/>
        <c:ItemNumber>2</ItemNumber>
    </child>
    <c:child xmlns:c="http://child/">
        <c:cname>Doe_child_2</cname>
        <c:cage/>
        <c:ItemNumber>2</ItemNumber>
    </child>
</father>
....
...

我有一个源xml,我想使用XSLT将其转换为显示的目标xml。

在源代码中,我们可以拥有多个父元素,每个元素包含多个子元素。要生成目标,首先我们应该为每个父项找到所有子项的ItemNumber的不同列表。因此,应该为源xml中的每个唯一ItemNumber映射目标xml中的父元素。你可以说它就像是sql的group-by子句,我们在每个Parent的ItemNumber上进行分组。我希望这个例子可以解释这种情况。

我一直在尝试各种各样的事情,但还没有达到解决方案的附近。我在形成解决方案时遇到了多个问题: 1.我认为我不能应用“Muenchian Method”,因为我需要为每个Parent找到唯一的ItemNumber。因此,必须在for-each(父)元素内定义键。我在这里很困惑。 我想,我应该为每个人(父母)提供一个顶级水平。在其中,一种确定唯一ItemNumber的方法。然后,当我尝试使用获取Parent Name时,我得不到任何东西,因为当控件在第二个for-each(uniqueItemNumber)内时,xpath(/ name)isn; t无效。解释这个问题很难。

我希望我能在这里找到解决方案。提前谢谢。

1 个答案:

答案 0 :(得分:0)

可以使用Muenchian分组在这样的元素中分组,诀窍是在每个父元素中包含一些独特的东西作为分组键的一部分。其generate-id()通常是一个很好的候选人。

<xsl:key name="childrenByNumber "match="c:child"
    use="concat(generate-id(..), '+', c:ItemNumber)"/>

如果要在父项中提取组,则以相同的方式构造查找键:

<xsl:template match="p:parent">
  <xsl:variable name="p" select="."/>
  <xsl:for-each select="c:child[generate-id() =
      generate-id(key('childrenByNumber', concat(generate-id($p), '+', c:ItemNumber))[1])]">
    <f:father xmlns:f="http://father/">
      <f:name><xsl:value-of select="$p/p:name"/></f:name>
      <f:age><xsl:value-of select="$p/p:age"/></f:age>
      <f:uniqueItemNumber>
        <xsl:value-of select="c:ItemNumber"/>
      </f:uniqueItemNumber>
      <xsl:copy-of select="key('childrenByNumber', concat(generate-id($p), '+', c:ItemNumber))"/>
    </f:father>
  </xsl:for-each>
</xsl:template>