XSLT合并同一父项下的多个节点

时间:2019-02-14 10:54:09

标签: xslt

输入XML是

<Operations>
     <ID>10</ID>
     <UserArea>
        <AdditionalPhantomInformation>
            <PhantomItem>
                <ItemCode>41341288</ItemCode>
                <SubComponent>40241289</SubComponent>
                <Position>1</Position>
            </PhantomItem>
        </AdditionalPhantomInformation>
    </UserArea>
    <ConsumedItem>          
        <LineNumber>3</LineNumber>
        <ParentItem>40241288</ParentItem>
    </ConsumedItem>
    <UserArea>
        <AdditionalPhantomInformation>
            <PhantomItem>
                <ItemCode>41341288</ItemCode>
                <SubComponent>40241302</SubComponent>
                <Position>5</Position>
            </PhantomItem>
        </AdditionalPhantomInformation>
    </UserArea>
</Operations>

我的预期输出是

    <Operations>
        <ID>10</ID>
        <UserArea>
            <AdditionalPhantomInformation>
                <PhantomItem>
                    <ItemCode>41341288</ItemCode>
                    <SubComponent>40241289</SubComponent>
                   <Position>1</Position>
                </PhantomItem>
                <PhantomItem>
                    <ItemCode>41341288</ItemCode>
                    <SubComponent>40241302</SubComponent>
                    <Position>5</Position>
                </PhantomItem>  
            </AdditionalPhantomInformation>
        </UserArea>
        <ConsumedItem>            
          <LineNumber>3</LineNumber>
          <ParentItem>40241288</ParentItem>
        </ConsumedItem>
    </Operations>  

我搜索了各种资源并尝试过,但是我无法正确使用xslt。我不知道如何使用xsl:for-each-group。请帮忙。我正在使用XSLT 2.0。

1 个答案:

答案 0 :(得分:0)

您在这里不一定需要xsl:for-each-group,因为您所做的只是将特定节点组合为一个。

从身份模板开始...

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

或者,如果您可以使用XSLT 3.0。...

<xsl:mode on-no-match="shallow-copy"/>

然后有一个匹配第一个UserArea的模板,该模板进行合并...

  <xsl:template match="UserArea[1]">
    <xsl:copy>
      <xsl:apply-templates select="node()|following-sibling::UserArea/node()" />
    </xsl:copy>
  </xsl:template>

然后,您只需要另一个模板即可确保其他UserArea元素不会以其原始位置输出。

<xsl:template match="UserArea" />

尝试使用此XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:output method="xml" indent="yes" />
  <xsl:strip-space elements="*" />

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="UserArea[1]">
    <xsl:copy>
      <xsl:apply-templates select="node()|following-sibling::UserArea/node()" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="UserArea" />
</xsl:stylesheet>

注意,如果您确实想使用xsl:for-each-group,则可以这样做

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:output method="xml" indent="yes" />
  <xsl:strip-space elements="*" />

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Operations">
    <xsl:copy>
      <xsl:for-each-group select="*" group-by="name()">
        <xsl:choose>
          <xsl:when test="current-grouping-key() = 'UserArea'">
            <xsl:copy>
              <xsl:apply-templates select="current-group()/node()" />
            </xsl:copy>
          </xsl:when>
          <xsl:otherwise>
            <xsl:apply-templates select="current-group()" />
          </xsl:otherwise>
        </xsl:choose>
      </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

如果您希望合并的节点不是UserArea,则具有易于扩展的优点。