【问题标题】:XSLT Data MergeXSLT 数据合并
【发布时间】:2013-08-27 13:14:16
【问题描述】:

我对 XSLT 有非常基本的了解,目前我正在努力实现一些我仍在努力弄清楚是否可能的目标。

可以是 XSLT 1.0 或 2.0

基本上这是我的 XML 的结构

   <?xml version="1.0" encoding="windows-1252"?>
<Root>
    <DataPage>
        <Record>
            <TEMP>xxx</TEMP>
            <DEBITNO>6250281</DEBITNO>
            <DOSSIERNUMMERINT>2012365</DOSSIERNUMMERINT>
            <ID>0123456789Z60</ID>
            <DATE>31/01/2013</DATE>
            <YEAR>2006</YEAR>
            <DESC>Test Item 1</DESC>
            <AMOUNT>           38170.0000000</AMOUNT>
            <HEAD>123</HEAD>
        </Record>
    </DataPage>
    <DataPage>
        <Record>
            <TEMP>xxx</TEMP>
            <DEBITNO>6250281</DEBITNO>
            <DOSSIERNUMMERINT>2012365</DOSSIERNUMMERINT>
            <ID>0123456789Z70</ID>
            <DATE>22/02/2013</DATE>
            <YEAR>2006</YEAR>
            <DESC>Test Item 2</DESC>
            <AMOUNT>           14410.0000000</AMOUNT>
            <HEAD>123</HEAD>
        </Record>
    </DataPage>
    <DataPage>
        <Record>
            <TEMP>xxx</TEMP>
            <DEBITNO>3849322</DEBITNO>
            <DOSSIERNUMMERINT>20132394</DOSSIERNUMMERINT>
            <ID>34958701223Z20</ID>
            <DATE>06/01/2013</DATE>
            <YEAR>2006</YEAR>
            <DESC>Test Item 1</DESC>
            <AMOUNT>           33811.0000000</AMOUNT>
            <HEAD>567</HEAD>
        </Record>
    </DataPage>
</Root>

我希望输出如下

<?xml version="1.0" encoding="windows-1252"?>
<Root>
    <DataPage>
        <Record>
            <TEMP>xxx</TEMP>
            <DEBITNO>6250281</DEBITNO>
            <DOSSIERNUMMERINT>2012365</DOSSIERNUMMERINT>
            <Line>
                <ID>0123456789Z60</ID>
                <DATE>31/01/2013</DATE>
                <YEAR>2006</YEAR>
                <DESC>Test Item 1</DESC>
                <AMOUNT>           38170.0000000</AMOUNT>
            </Line>
            <Line>
                <ID>0123456789Z70</ID>
                <DATE>22/02/2013</DATE>
                <YEAR>2006</YEAR>
                <DESC>Test Item 2</DESC>
                <AMOUNT>           14410.0000000</AMOUNT>
            </Line>
            <HEAD>123</HEAD>
        </Record>
    </DataPage>
    <DataPage>
        <Record>
            <TEMP>xxx</TEMP>
            <DEBITNO>3849322</DEBITNO>
            <DOSSIERNUMMERINT>20132394</DOSSIERNUMMERINT>
            <Line>
                <ID>34958701223Z20</ID>
                <DATE>06/01/2013</DATE>
                <YEAR>2006</YEAR>
                <DESC>Test Item 1</DESC>
                <AMOUNT>           33811.0000000</AMOUNT>
            </Line>
            <HEAD>567</HEAD>
        </Record>
    </DataPage>
</Root>

所以逻辑是合并具有相同 DEBITNO 的所有记录。

合并的规则是除了 ID、日期、年份、DESC 和 AMOUNT 之外的所有内容都可以从第一次出现

ID、Date、Year、DESC 和 AMOUNT 需要放在一个标签中,因此如果有 2 条记录具有相同的 DEBITNO,则将有 2 个行项目,如果有 5 条记录具有相同的 DEBITNO,则结果记录将有 5 个订单项。

我希望这是有道理的。

这样的事情可能吗?

问候,

【问题讨论】:

    标签: xml xslt merge data-manipulation


    【解决方案1】:

    这是一个标准的分组问题。在 XSLT 2.0 中:

    <xsl:template match="Root">
     <xsl:for-each-group select="DataPage/Record" group-by="DEBITNO">
      <DataPage>
        <Record>
         <xsl:copy-of select="TEMP, DEBITNO, DOSSIERNUMMERINT"/>
         <xsl:for-each select="current-group()">
           <Line>
             <xsl:copy-of select="ID, YEAR, DATE, DESC, AMOUNT"/>
           </
         </
       </
      </
     </
    </   
    

    【讨论】:

    • 嗨,Michael,请原谅我说我对 XSLT 的了解有限。这个概念对我来说很有意义,但是把它付诸实践并不是那么重要,我认为这是给我一个想法,而不是一个实际的功能 XSLT,我正在通过它来尝试解决这个问题。谢谢!
    • 正确,我的正常风格不是为人们编写程序,而是为他们指明正确的方向并帮助他们走上学习曲线。我强烈建议您在尝试在生产代码中使用 xsl:for-each-group 之前先阅读我自己的书籍中有关 xsl:for-each-group 的内容。
    【解决方案2】:

    在充分尊重 Kay 先生关于不提供解决方案的决定的情况下,xslt 1.0 中的这个解决方案解决了您的特殊情况,也是更一般情况的解决方案,您可以通过 multiroot 包含多个root 元素并且需要本地分组

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output omit-xml-declaration="yes" method="xml" indent="yes" />
      <xsl:key name ="k1" match="DataPage[
        not(preceding-sibling::DataPage/Record/DEBITNO = Record/DEBITNO)
        ]"
        use="generate-id()"/>
    
      <xsl:key name="k2" match="DataPage[
        preceding-sibling::DataPage/Record/DEBITNO = Record/DEBITNO]"
        use="generate-id(preceding-sibling::DataPage[
          Record/DEBITNO= current()/Record/DEBITNO
        ][last()])" />
      <xsl:template match="node()|@*">
        <xsl:copy>
          <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
      </xsl:template>
      <xsl:template match="DataPage"/>
      <xsl:template match="DataPage[key('k1',generate-id())]">
        <xsl:copy>
          <Record>
            <xsl:apply-templates select="Record/TEMP
              |Record/DEBITNO
              |Record/DOSSIERNUMMERINT"/>
            <xsl:for-each select=".|key('k2',generate-id())">
              <Line>
                <xsl:apply-templates select="Record/ID
                  |Record/DATE
                  |Record/YEAR
                  |Record/DESC
                  |Record/AMOUNT"/>
              </Line>
            </xsl:for-each>
            <xsl:apply-templates select="Record/HEAD"/>
          </Record>
        </xsl:copy>
      </xsl:template>
    </xsl:stylesheet>
    

    警告:似乎某些 XSLT 处理器不支持在 k2 定义中使用 current() 函数

    如果您想要一个更简单的解决方案,只针对您的情况(不支持本地分组),您可以使用这种类似 Muenchian 的方法

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output omit-xml-declaration="yes" method="xml" indent="yes" />
      <xsl:key name ="k" match="DataPage"
        use="Record/DEBITNO"/>
    
      <xsl:template match="node()|@*">
        <xsl:copy>
          <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
      </xsl:template>
      <xsl:template match="DataPage"/>
      <xsl:template match="DataPage[ 
        generate-id() = generate-id(key('k', Record/DEBITNO)[1])
      ]">
        <xsl:copy>
          <Record>
            <xsl:apply-templates select="Record/TEMP
              |Record/DEBITNO
              |Record/DOSSIERNUMMERINT"/>
            <xsl:for-each select="key('k', Record/DEBITNO)">
              <Line>
                <xsl:apply-templates select="Record/ID
                  |Record/DATE
                  |Record/YEAR
                  |Record/DESC
                  |Record/AMOUNT"/>
              </Line>
            </xsl:for-each>
            <xsl:apply-templates select="Record/HEAD"/>
          </Record>
        </xsl:copy>
      </xsl:template>
    </xsl:stylesheet>
    

    在 xslt 1.0 中,这是一个众所周知的方法,Muenchian method

    我给自己写了一篇关于它和一些小的变化的论文。也可以找到here

    【讨论】:

    • 大家好,我并没有忘记这个帖子,或者只是接受了答案就离开了,我最近非常忙,仍然打算从两个回复中测试和学习。一旦我的日程安排允许进行一些测试,我会尽快回复。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-02-14
    • 1970-01-01
    • 2022-12-07
    • 2020-02-11
    • 1970-01-01
    • 1970-01-01
    • 2017-06-03
    相关资源
    最近更新 更多