flat XML 到使用 XSLT 嵌套
flat XML to nested using XSLT
在这上面花了太多时间.."f$%"
希望你能分享你的经验。
我的源平面 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
在实施了 Daniel Haley 提供的大部分代码之后,似乎已经很接近解决方案了。
根据 Martin 的要求,我在此处添加当前使用的 XSLT + 当前结果 XML。
我将尝试澄清我的 XSLT 程序规则:
1.Each 来自来源 XML 的记录应该分析如下:
如果 LINE_NUMBER = 0 那么这是一个头记录并且应该产生一个段**。(它不应该被添加到段中)**
- 如果 LINE_NUMBER 大于 0 且其 EVENT_ID 等于生成该段的行,则这是同一段上下文中的 RecordLine,应在同一段下打开一个段。”
从结果中可以看出一些问题 xml:
- 前4组Headers-RecordLines出来nicley(EventIDs
100 到 104) 。但是在 EVENT_ID 105 上出了点问题。可以看到
LINE_NUMBER=0 的行创建了一个 Header 段,但也
在记录行中添加了两次数据。这是错误的结果。
- 从这一点开始,所有的记录都变得一团糟。
目前我不能说为什么会这样。
我添加了来自我们测试数据库的部分源 XML(如图所示)。
我已经添加了部分结果 XML(如图)希望这些注释能够解决问题。
当你写到你想要对元素进行分组时,我想作为起点你可以使用 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>
您可以在 apply-templates
中的 Header
下面列出您想要的更多元素。
由于您使用的是 XSLT 2.0,因此可以使用 xsl:for-each-group
(see XSLT 2.0 grouping) 按 EVENT_ID
进行分组。
此外,使用 identity transform 来处理所有不需要更改的元素。
示例...
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
<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输出
<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>
在这上面花了太多时间.."f$%" 希望你能分享你的经验。 我的源平面 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
在实施了 Daniel Haley 提供的大部分代码之后,似乎已经很接近解决方案了。 根据 Martin 的要求,我在此处添加当前使用的 XSLT + 当前结果 XML。 我将尝试澄清我的 XSLT 程序规则: 1.Each 来自来源 XML 的记录应该分析如下: 如果 LINE_NUMBER = 0 那么这是一个头记录并且应该产生一个段**。(它不应该被添加到段中)** - 如果 LINE_NUMBER 大于 0 且其 EVENT_ID 等于生成该段的行,则这是同一段上下文中的 RecordLine,应在同一段下打开一个段。” 从结果中可以看出一些问题 xml:
- 前4组Headers-RecordLines出来nicley(EventIDs 100 到 104) 。但是在 EVENT_ID 105 上出了点问题。可以看到 LINE_NUMBER=0 的行创建了一个 Header 段,但也 在记录行中添加了两次数据。这是错误的结果。
- 从这一点开始,所有的记录都变得一团糟。 目前我不能说为什么会这样。 我添加了来自我们测试数据库的部分源 XML(如图所示)。 我已经添加了部分结果 XML(如图)希望这些注释能够解决问题。
当你写到你想要对元素进行分组时,我想作为起点你可以使用 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>
您可以在 apply-templates
中的 Header
下面列出您想要的更多元素。
由于您使用的是 XSLT 2.0,因此可以使用 xsl:for-each-group
(see XSLT 2.0 grouping) 按 EVENT_ID
进行分组。
此外,使用 identity transform 来处理所有不需要更改的元素。
示例...
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
<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输出
<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>