在for each中使用xslt查找唯一节点

在for each中使用xslt查找唯一节点,xslt,xslt-1.0,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>

源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>
...
...
...

约翰
30
约翰·希德
1.
约翰·夏尔2
2.
约翰·夏尔3
1.
雌鹿
40
Doe_child_1
2.
Doe_child_2
2.
...
...
...

目标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>
....
...

约翰
30
1.
约翰·希德
1.
约翰·夏尔3
1.
约翰
30
2.
约翰·夏尔2
2.
雌鹿
40
2.
Doe_child_1
2.
Doe_child_2
2.
....
...

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

在源代码中,我们可以有多个父元素,每个都包含多个子元素。要生成目标,首先我们应该找到每个父项的所有子项的ItemNumber的不同列表。因此,应该为源xml中的每个唯一ItemNumber映射目标xml中的父元素。您可以说,这类似于sql的GROUPBY子句,其中我们根据每个父级的ItemNumber进行分组。我希望这个例子能够解释这种情况

我一直在尝试各种各样的事情,但还没有接近解决方案。我在制定解决方案时遇到了多个问题: 1.我不认为我可以应用“Muenchian方法”,因为我需要为每个父项找到唯一的ItemNumber。因此,必须在for每个(父)元素的内部定义键。我在这里感到困惑。 2.我想,我应该为每一位(家长)制定一个最高级别。在它里面,一种确定唯一ItemNumber的方法。然后,当我尝试使用获取父名称时,我什么也得不到,因为xpath(/Name)不是;当控件位于第二个for each(uniqueItemNumber)内时无效。很难解释这个问题

我希望我能在这里找到解决办法。提前感谢。

您可以使用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>


非常感谢您的回复。请您解释一下,下面的代码段正在执行哪项任务:@user2857635这就是在输出中插入正确的
c:child
元素组的原因(当前父元素中具有当前ItemNumber的元素)。感谢Ian的解释。