简体   繁体   English

平面XML使用XSLT进行嵌套

[英]flat XML to nested using XSLT

Been spending too much time on this.."f$%" Hope you can share of your experience. 在此上花了太多时间。.“ f $%”希望您能分享您的经验。 I have the source flat XML arriving from external db in the following structure: 我有以下结构中来自外部数据库的源平面XML:

 <?xml version="1.0" encoding="utf-8"?>
    <ns:MT_ActualCosts xmlns:ns="http://percite:scmaster/actual_costs">
        <row>
            <EVENT_ID>106</EVENT_ID>
            <LINE_NUMBER>0</LINE_NUMBER>
            <INVOICE_NUMBER>9999</INVOICE_NUMBER>
            <INVOICE_DATE>2015-02-09 00:00:00.0</INVOICE_DATE>
            <CURRENCY_CODE>USD</CURRENCY_CODE>
            <TOTAL_AMOUNT_NET>0001</TOTAL_AMOUNT_NET>
            <RO_NUMBER>102808</RO_NUMBER>
        </row>
        <row>
            <EVENT_ID>106</EVENT_ID>
            <LINE_NUMBER>1</LINE_NUMBER>
            <INVOICE_NUMBER>24444</INVOICE_NUMBER>
            <PLANT>0003</PLANT>
            <ALLOCATION_AMOUNT>122</ALLOCATION_AMOUNT>
        </row>
        <row>
            <EVENT_ID>109</EVENT_ID>
            <LINE_NUMBER>0</LINE_NUMBER>
            <INVOICE_NUMBER>24458</INVOICE_NUMBER>
            <INVOICE_DATE>2015-02-09 00:00:00.0</INVOICE_DATE>
            <CURRENCY_CODE>USD</CURRENCY_CODE>
            <TOTAL_AMOUNT_NET>0011</TOTAL_AMOUNT_NET>
            <RO_NUMBER>102813</RO_NUMBER>
        </row>
        <row>
            <EVENT_ID>109</EVENT_ID>
            <LINE_NUMBER>1</LINE_NUMBER>
            <INVOICE_NUMBER>24458</INVOICE_NUMBER>
            <PLANT>0003</PLANT>
            <ALLOCATION_AMOUNT>11.1</ALLOCATION_AMOUNT>
        </row>
        <row>
            <EVENT_ID>108</EVENT_ID>
            <LINE_NUMBER>0</LINE_NUMBER>
            <INVOICE_NUMBER>24535</INVOICE_NUMBER>
            <INVOICE_DATE>2015-02-19 00:00:00.0</INVOICE_DATE>
            <CURRENCY_CODE>USD</CURRENCY_CODE>
            <TOTAL_AMOUNT_NET>11</TOTAL_AMOUNT_NET>
            <RO_NUMBER>102811</RO_NUMBER>
        </row>
        <row>
            <EVENT_ID>108</EVENT_ID>
            <LINE_NUMBER>1</LINE_NUMBER>
            <INVOICE_NUMBER>24535</INVOICE_NUMBER>
            <PLANT>0002</PLANT>
            <ALLOCATION_AMOUNT>11</ALLOCATION_AMOUNT>
        </row>
        <row>
            <EVENT_ID>171</EVENT_ID>
            <LINE_NUMBER>0</LINE_NUMBER>
            <INVOICE_NUMBER>24645</INVOICE_NUMBER>
            <INVOICE_DATE>2015-02-28 00:00:00.0</INVOICE_DATE>
            <CURRENCY_CODE>USD</CURRENCY_CODE>
            <TOTAL_AMOUNT_NET>999999</TOTAL_AMOUNT_NET>
            <RO_NUMBER>103063</RO_NUMBER>
        </row>
        <row>
            <EVENT_ID>171</EVENT_ID>
            <LINE_NUMBER>1</LINE_NUMBER>
            <INVOICE_NUMBER>24645</INVOICE_NUMBER>
            <PLANT>0001</PLANT>
            <ALLOCATION_AMOUNT>11.47</ALLOCATION_AMOUNT>
        </row>
        <row>
            <EVENT_ID>171</EVENT_ID>
            <LINE_NUMBER>2</LINE_NUMBER>
            <INVOICE_NUMBER>24645</INVOICE_NUMBER>
            <PLANT>0001</PLANT>
            <ALLOCATION_AMOUNT>11.53</ALLOCATION_AMOUNT>
        </row>
    </ns:MT_ActualCosts>


My requested Target Structure should be something like this:

[![enter image description here][1]][1]

I need to group under the Header segments RecordLine Segments of the same `EVENT_ID`.

Currently my XSLT can't create the needed structure.
this is my XSLT:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:ns0="http://percite:scmaster/actual_costs">
    <xsl:output method="xml" indent="yes"/>

    <!-- xsi:noNamespaceSchemaLocation="\\palnt03\palramnet-redirect$\IL-Users\My-Documents\nimrod_g\SAP\Projects\ScMaster\Finance\ActualCosts\development\xsd"> -->
    <xsl:template match="/">
    <ns0:MT_ActualCostPreNormalized>
    <xsl:for-each select= "ns0:MT_ActualCosts/row">
        <xsl:if test="LINE_NUMBER=0">
            <Header>
            <EVENT_ID><xsl:value-of select="EVENT_ID"></xsl:value-of>
            </EVENT_ID>
            <LINE_NUMBER>
            <xsl:value-of select="LINE_NUMBER"/>
            </LINE_NUMBER>
            <INVOICE_NUMBER>
                    <xsl:value-of select="INVOICE_NUMBER"/>
                    </INVOICE_NUMBER>
                    <CURRENCY_CODE>
                    <xsl:value-of select="CURRENCY_CODE"/>
                    </CURRENCY_CODE>
                    <TOTAL_AMOUNT_NET>
                    <xsl:value-of select="TOTAL_AMOUNT_NET"/>
                    </TOTAL_AMOUNT_NET>
                    <RO_NUMBER>
                    <xsl:value-of select="RO_NUMBER"/>
                    </RO_NUMBER>
                    <PLANT>
                    <xsl:value-of select="PLANT"/>
                    </PLANT>
                    <ALLOCATION_AMOUNT>
                    <xsl:value-of select="ALLOCATION_AMOUNT"/>
                    </ALLOCATION_AMOUNT>
            </Header>
        </xsl:if>
                <xsl:if test="LINE_NUMBER!=0">
                        <RecordLine>
                        <EVENT_ID><xsl:value-of select="EVENT_ID"></xsl:value-of>
                        </EVENT_ID>
                        <LINE_NUMBER>
                        <xsl:value-of select="LINE_NUMBER"/>
                        </LINE_NUMBER>
                        <INVOICE_NUMBER>
                        <xsl:value-of select="INVOICE_NUMBER"/>
                        </INVOICE_NUMBER>
                        <CURRENCY_CODE>
                        <xsl:value-of select="CURRENCY_CODE"/>
                        </CURRENCY_CODE>
                        <TOTAL_AMOUNT_NET>
                        <xsl:value-of select="TOTAL_AMOUNT_NET"/>
                        </TOTAL_AMOUNT_NET>
                        <RO_NUMBER>
                        <xsl:value-of select="RO_NUMBER"/>
                        </RO_NUMBER>
                        <PLANT>
                        <xsl:value-of select="PLANT"/>
                        </PLANT>
                        <ALLOCATION_AMOUNT>
                        <xsl:value-of select="ALLOCATION_AMOUNT"/>
                        </ALLOCATION_AMOUNT>
                        </RecordLine>
                </xsl:if>
        </xsl:for-each>
    </ns0:MT_ActualCostPreNormalized>
    </xsl:template>
    </xsl:stylesheet> 


  [1]: http://i.stack.imgur.com/yklFq.jpg

After implemenitng most of the code provided by Daniel Haley it seems like the solution is very near. 在实现了Daniel Haley提供的大多数代码之后,看来解决方案已经接近了。 Follwoing Martin's request I am adding here the current XSLT used+the current result XML. 按照Martin的要求,我要在此处添加当前使用的XSLT +当前结果XML。 I will try and clerify my rules for the XSLT program: 1.Each record from the source XML should be analyzed as followed: if LINE_NUMBER = 0 then this is a header record and should produce a segment**.(it shouldnt be added to the segment )** - if LINE_NUMBER is > 0 and its EVENT_ID equals to the row produced the segment the this is a RecordLine in the context of the same segment and should open a segment under the same ." Few problems can be seen in the result xml: 我将尝试阐明我的XSLT程序规则:1.应该按以下方式分析源XML中的每个记录:如果LINE_NUMBER = 0,则这是标头记录,应产生一个段**。(不应将其添加到段)**-如果LINE_NUMBER> 0并且其EVENT_ID等于生成该段的行,则这是同一段上下文中的RecordLine,应在同一段下打开一个段。”结果xml:

  1. The first 4 groups of Headers-RecordLines comes out nicley (EventIDs 100 to 104) .but on EVENT_ID 105 something went wrong. 前4组Headers-RecordLines来自nicley(事件ID 100至104)。但是在EVENT_ID 105上出了点问题。 it can be see that the row with LINE_NUMBER=0 created a Header segment but also added the data twice inside a record line. 可以看到LINE_NUMBER = 0的行创建了一个Header段,而且还在记录行中两次添加了数据。 this is wrong result. 这是错误的结果。
  2. from this point on, all the records are getting messed up. 从那时起,所有记录都被弄乱了。 Currently I can't say why this happened. 目前我不能说为什么会这样。 I have added part of the source XML (as image) as comming from our testing db. 我已经从测试数据库中添加了部分源XML(作为图像)。 I have added part of the result XML (as image)Hope these notes will clearify the issue. 我已将结果XML的一部分添加为图像(希望如此)。希望这些说明可以解决问题。

Source XML part with event 105 带有事件105的源XML部分

Result XML part with event 105 结果XML部分带有事件105

As you write that you want to group elements I guess as a starting point you can use for-each-group instead of for-each : 当您写到要对元素进行分组时,我想可以使用for-each-group代替for-each作为起点:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
xmlns:ns0="http://percite:scmaster/actual_costs">

    <xsl:output indent="yes"/>

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

    <xsl:template match="/*">
        <ns0:MT_ActualCostPreNormalized>
          <xsl:for-each-group select="row" group-by="EVENT_ID">
              <Header>
                  <xsl:apply-templates select="EVENT_ID, LINE_NUMBER, current-group()"/>
              </Header>
          </xsl:for-each-group>
        </ns0:MT_ActualCostPreNormalized>
    </xsl:template>

    <xsl:template match="row">
        <RecordLine>
            <xsl:apply-templates/>
        </RecordLine>
    </xsl:template>
</xsl:transform>

You can list further elements you want to have below Header in the apply-templates . 您可以在apply-templates Header下面列出希望包含的其他元素。

Since you're using XSLT 2.0, you can use xsl:for-each-group ( see XSLT 2.0 grouping ) to group by EVENT_ID . 由于您使用的是XSLT 2.0,因此可以使用xsl:for-each-group请参阅XSLT 2.0分组 )按EVENT_ID 分组

Also, use an identity transform to handle all of the elements that don't need to change. 另外,使用身份转换来处理所有不需要更改的元素。

Example... 例...

XML Input XML输入

<ns:MT_ActualCosts xmlns:ns="http://percite:scmaster/actual_costs">
    <row>
        <EVENT_ID>106</EVENT_ID>
        <LINE_NUMBER>0</LINE_NUMBER>
        <INVOICE_NUMBER>9999</INVOICE_NUMBER>
        <INVOICE_DATE>2015-02-09 00:00:00.0</INVOICE_DATE>
        <CURRENCY_CODE>USD</CURRENCY_CODE>
        <TOTAL_AMOUNT_NET>0001</TOTAL_AMOUNT_NET>
        <RO_NUMBER>102808</RO_NUMBER>
    </row>
    <row>
        <EVENT_ID>106</EVENT_ID>
        <LINE_NUMBER>1</LINE_NUMBER>
        <INVOICE_NUMBER>24444</INVOICE_NUMBER>
        <PLANT>0003</PLANT>
        <ALLOCATION_AMOUNT>122</ALLOCATION_AMOUNT>
    </row>
    <row>
        <EVENT_ID>109</EVENT_ID>
        <LINE_NUMBER>0</LINE_NUMBER>
        <INVOICE_NUMBER>24458</INVOICE_NUMBER>
        <INVOICE_DATE>2015-02-09 00:00:00.0</INVOICE_DATE>
        <CURRENCY_CODE>USD</CURRENCY_CODE>
        <TOTAL_AMOUNT_NET>0011</TOTAL_AMOUNT_NET>
        <RO_NUMBER>102813</RO_NUMBER>
    </row>
    <row>
        <EVENT_ID>109</EVENT_ID>
        <LINE_NUMBER>1</LINE_NUMBER>
        <INVOICE_NUMBER>24458</INVOICE_NUMBER>
        <PLANT>0003</PLANT>
        <ALLOCATION_AMOUNT>11.1</ALLOCATION_AMOUNT>
    </row>
    <row>
        <EVENT_ID>108</EVENT_ID>
        <LINE_NUMBER>0</LINE_NUMBER>
        <INVOICE_NUMBER>24535</INVOICE_NUMBER>
        <INVOICE_DATE>2015-02-19 00:00:00.0</INVOICE_DATE>
        <CURRENCY_CODE>USD</CURRENCY_CODE>
        <TOTAL_AMOUNT_NET>11</TOTAL_AMOUNT_NET>
        <RO_NUMBER>102811</RO_NUMBER>
    </row>
    <row>
        <EVENT_ID>108</EVENT_ID>
        <LINE_NUMBER>1</LINE_NUMBER>
        <INVOICE_NUMBER>24535</INVOICE_NUMBER>
        <PLANT>0002</PLANT>
        <ALLOCATION_AMOUNT>11</ALLOCATION_AMOUNT>
    </row>
    <row>
        <EVENT_ID>171</EVENT_ID>
        <LINE_NUMBER>0</LINE_NUMBER>
        <INVOICE_NUMBER>24645</INVOICE_NUMBER>
        <INVOICE_DATE>2015-02-28 00:00:00.0</INVOICE_DATE>
        <CURRENCY_CODE>USD</CURRENCY_CODE>
        <TOTAL_AMOUNT_NET>999999</TOTAL_AMOUNT_NET>
        <RO_NUMBER>103063</RO_NUMBER>
    </row>
    <row>
        <EVENT_ID>171</EVENT_ID>
        <LINE_NUMBER>1</LINE_NUMBER>
        <INVOICE_NUMBER>24645</INVOICE_NUMBER>
        <PLANT>0001</PLANT>
        <ALLOCATION_AMOUNT>11.47</ALLOCATION_AMOUNT>
    </row>
    <row>
        <EVENT_ID>171</EVENT_ID>
        <LINE_NUMBER>2</LINE_NUMBER>
        <INVOICE_NUMBER>24645</INVOICE_NUMBER>
        <PLANT>0001</PLANT>
        <ALLOCATION_AMOUNT>11.53</ALLOCATION_AMOUNT>
    </row>
</ns:MT_ActualCosts>

XSLT 2.0 XSLT 2.0

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

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

  <xsl:template match="/*">
    <ns:MT_ActualCostPreNormalized>
      <!--Group rows by EVENT_ID.-->
      <xsl:for-each-group select="row" group-by="EVENT_ID">
        <!--Optional sort by EVENT_ID.-->
        <xsl:sort select="current-grouping-key()"/>
        <Header>
          <!--Apply templates to the children of row's with a LINE_NUMBER of 0 
          followed by row's that have a LINE_NUMBER that isn't equal to 0.-->
          <xsl:apply-templates select="current-group()[LINE_NUMBER=0]/*,
            current-group()[not(LINE_NUMBER=0)]">
            <!--Optional sort by LINE_NUMBER.-->
            <xsl:sort select="LINE_NUMBER"/>
          </xsl:apply-templates>
        </Header>
      </xsl:for-each-group>
    </ns:MT_ActualCostPreNormalized>
  </xsl:template>

  <!--Because of the apply-templates, the only row elements matched 
  should be row's with a LINE_NUMBER > 0.-->
  <xsl:template match="row">
    <RecordLine>
      <xsl:apply-templates/>
    </RecordLine>          
  </xsl:template>

</xsl:stylesheet>

XML Output XML输出

<ns:MT_ActualCostPreNormalized xmlns:ns="http://percite:scmaster/actual_costs">
   <Header>
      <EVENT_ID>106</EVENT_ID>
      <LINE_NUMBER>0</LINE_NUMBER>
      <INVOICE_NUMBER>9999</INVOICE_NUMBER>
      <INVOICE_DATE>2015-02-09 00:00:00.0</INVOICE_DATE>
      <CURRENCY_CODE>USD</CURRENCY_CODE>
      <TOTAL_AMOUNT_NET>0001</TOTAL_AMOUNT_NET>
      <RO_NUMBER>102808</RO_NUMBER>
      <RecordLine>
         <EVENT_ID>106</EVENT_ID>
         <LINE_NUMBER>1</LINE_NUMBER>
         <INVOICE_NUMBER>24444</INVOICE_NUMBER>
         <PLANT>0003</PLANT>
         <ALLOCATION_AMOUNT>122</ALLOCATION_AMOUNT>
      </RecordLine>
   </Header>
   <Header>
      <EVENT_ID>108</EVENT_ID>
      <LINE_NUMBER>0</LINE_NUMBER>
      <INVOICE_NUMBER>24535</INVOICE_NUMBER>
      <INVOICE_DATE>2015-02-19 00:00:00.0</INVOICE_DATE>
      <CURRENCY_CODE>USD</CURRENCY_CODE>
      <TOTAL_AMOUNT_NET>11</TOTAL_AMOUNT_NET>
      <RO_NUMBER>102811</RO_NUMBER>
      <RecordLine>
         <EVENT_ID>108</EVENT_ID>
         <LINE_NUMBER>1</LINE_NUMBER>
         <INVOICE_NUMBER>24535</INVOICE_NUMBER>
         <PLANT>0002</PLANT>
         <ALLOCATION_AMOUNT>11</ALLOCATION_AMOUNT>
      </RecordLine>
   </Header>
   <Header>
      <EVENT_ID>109</EVENT_ID>
      <LINE_NUMBER>0</LINE_NUMBER>
      <INVOICE_NUMBER>24458</INVOICE_NUMBER>
      <INVOICE_DATE>2015-02-09 00:00:00.0</INVOICE_DATE>
      <CURRENCY_CODE>USD</CURRENCY_CODE>
      <TOTAL_AMOUNT_NET>0011</TOTAL_AMOUNT_NET>
      <RO_NUMBER>102813</RO_NUMBER>
      <RecordLine>
         <EVENT_ID>109</EVENT_ID>
         <LINE_NUMBER>1</LINE_NUMBER>
         <INVOICE_NUMBER>24458</INVOICE_NUMBER>
         <PLANT>0003</PLANT>
         <ALLOCATION_AMOUNT>11.1</ALLOCATION_AMOUNT>
      </RecordLine>
   </Header>
   <Header>
      <EVENT_ID>171</EVENT_ID>
      <LINE_NUMBER>0</LINE_NUMBER>
      <INVOICE_NUMBER>24645</INVOICE_NUMBER>
      <INVOICE_DATE>2015-02-28 00:00:00.0</INVOICE_DATE>
      <CURRENCY_CODE>USD</CURRENCY_CODE>
      <TOTAL_AMOUNT_NET>999999</TOTAL_AMOUNT_NET>
      <RO_NUMBER>103063</RO_NUMBER>
      <RecordLine>
         <EVENT_ID>171</EVENT_ID>
         <LINE_NUMBER>1</LINE_NUMBER>
         <INVOICE_NUMBER>24645</INVOICE_NUMBER>
         <PLANT>0001</PLANT>
         <ALLOCATION_AMOUNT>11.47</ALLOCATION_AMOUNT>
      </RecordLine>
      <RecordLine>
         <EVENT_ID>171</EVENT_ID>
         <LINE_NUMBER>2</LINE_NUMBER>
         <INVOICE_NUMBER>24645</INVOICE_NUMBER>
         <PLANT>0001</PLANT>
         <ALLOCATION_AMOUNT>11.53</ALLOCATION_AMOUNT>
      </RecordLine>
   </Header>
</ns:MT_ActualCostPreNormalized>

Working Example 工作实例

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM