XSLT数据合并

时间:2013-08-27 13:14:16

标签: xml xslt merge data-manipulation

我对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,日期,年份,DESC和AMOUNT需要放入标签中,因此如果有2个记录具有相同的DEBITNO,则会有2个行项目,如果有5个记录具有相同的DEBITNO,则结果记录将有5个订单项。

我希望这是有道理的。

这样的事情可能吗?

此致

2 个答案:

答案 0 :(得分: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"/>
       </
     </
   </
  </
 </
</   

答案 1 :(得分:0)

对凯先生关于不提供解决方案的决定充分尊重,xslt 1.0中的这个解决了您的具体案例,也是一个解决方案,适用于您可以拥有 multiroot <的更一般情况/ em>需要多个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处理器不支持在current()定义中使用k2函数

如果您想为您的案例提供更简单的解决方案(不支持本地分组),您可以使用此类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