基于子元素值和序列号对父节点进行分组

时间:2011-01-12 15:49:40

标签: xslt

我需要使用xslt转换XML。

逻辑:

如果父级具有不同的子地址,则拆分父级,并使用父级名称附加序列号。还需要孩子的行号。 这里我们可能有多个父节点,每个父节点可能有更多的子节点。

我已经尝试了很多方法来实现这一点,并且我坚持在foreach中生成序列号。所以任何人都可以尝试并为此提供解决方案。

源XML如下:

<Data>
   <Parent>
      <Name>P1</Name>
      <Child>
        <Name>CName1</Name>
        <Address>Address1</Address>
      </Child>
      <Child>
        <Name>CName2</Name>
        <Address>Address2</Address>
      </Child>
      <Child>
        <Name>CName3</Name>
        <Address>Address1</Address>
      </Child>
   </Parent>

   <Parent>
     <Name>P2</Name>
       <Child>
         <Name>CName1</Name>
         <Address>Address1</Address>
       </Child>
   </Parent>
</Data>

目标XML应如下所示:

<Data>
  <Parent>
     <Name>P1_1</Name>
     <Address>Address1</Address>
     <Child>
       <LineNumber>1</LineNumber>
       <Name>CName1</Name>
     </Child>
     <Child>
        <LineNumber>2</LineNumber>
        <Name>CName3</Name>
     </Child>
  </Parent>

  <Parent>
      <Name>P1_2</Name>
      <Address>Address2</Address>
      <Child>
         <LineNumber>1</LineNumber>
         <Name>CName2</Name>
      </Child>
  </Parent>

  <Parent>
      <Name>P2_1</Name>
      <Address>Address1</Address>
      <Child>
          <LineNumber>1</LineNumber>
          <Name>CName1</Name>
       </Child>
  </Parent>
</Data>

1 个答案:

答案 0 :(得分:3)

此XSLT 1.0转换:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:key name="kAddress" match="Child" use="concat(generate-id(..), '|', Address)" />

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

  <xsl:template match="Parent">
    <xsl:variable name="parent" select="." />
    <xsl:for-each select="Child[
      generate-id()
      = 
      generate-id(key('kAddress', concat(generate-id($parent), '|', Address))[1])
    ]">
      <Parent>
        <Name><xsl:value-of select="concat(../Name, '_', position())" /></Name>
        <xsl:copy-of select="Address" />
        <xsl:apply-templates select="
          key('kAddress', concat(generate-id($parent), '|', Address))
        " />
      </Parent>
    </xsl:for-each>
  </xsl:template>

  <xsl:template match="Child">
    <xsl:copy>
      <xsl:copy-of select="@*" />
      <LineNumber><xsl:value-of select="position()" /></LineNumber>
      <xsl:apply-templates select="node()[not(self::Address)]" />
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

为您的样本生成以下输出:

<Data>
    <Parent>
        <Name>P1_1</Name>
        <Address>Address1</Address>
        <Child>
            <LineNumber>1</LineNumber>
            <Name>CName1</Name>
        </Child>
        <Child>
            <LineNumber>2</LineNumber>
            <Name>CName3</Name>
        </Child>
    </Parent>
    <Parent>
        <Name>P1_2</Name>
        <Address>Address2</Address>
        <Child>
            <LineNumber>1</LineNumber>
            <Name>CName2</Name>
        </Child>
    </Parent>
    <Parent>
        <Name>P2_1</Name>
        <Address>Address1</Address>
        <Child>
            <LineNumber>1</LineNumber>
            <Name>CName1</Name>
        </Child>
    </Parent>
</Data>