【问题标题】:Grouping parent node based on child elements values and sequence number根据子元素值和序列号对父节点进行分组
【发布时间】:2011-01-13 00:22:26
【问题描述】:

我需要使用 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>

【问题讨论】:

  • 请用{}按钮格式化代码
  • 对于分组问题,您确实需要告诉我们您是否可以使用 XSLT 2.0,或者您是否坚持使用 XSLT 1.0。使用 2.0 进行分组非常。此外,如果您已经解决了问题的一部分(分组)并且被另一部分(编号)困住了,那么向我们展示您已经走了多远会很有帮助 - 它可能需要一个相当小的调整,或者您的方法可能已经完全被误导了。

标签: xslt


【解决方案1】:

这个 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>

【讨论】:

  • +1 我会使用 Childs by Parent 和 Adress 只是为了便于阅读
猜你喜欢
  • 1970-01-01
  • 2021-05-17
  • 2017-09-02
  • 1970-01-01
  • 1970-01-01
  • 2016-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多