[英]Merging and rearranging xml using xslt
我正在使用XSLT转换从Web派生的XML,并迅速将其转换为目标XML文件,表示为output。 即使做了很多尝试,我仍然无法执行此操作。有人可以帮我完成此转换吗?
源XML
<allocelement>
<hd1>12</hd1>
<hd2>14</hd2>
<hd3>87</hd3>
<alc>1</alc>
<amount>4587</amount>
<code>1111</code>
</allocelement>
<alloclement>
<hd1>12</hd1>
<hd2>14</hd2>
<hd3>87</hd3>
<alc>2</alc>
<amount>80000</amount>
<code>1111</code>
</alloclement>
<alloclement>
<hd1>875</hd1>
<hd2>455</hd2>
<hd3>455</hd3>
<alc>2</alc>
<amount>80000</amount>
<code>1112</code>
</alloclement>
期望的输出
<allocelement>
<Codeheader>
<code>1111</code>
<hd1>12</hd1>
<hd2>14</hd2>
<hd3>87</hd3>
<alc>1</alc>
<amount>4587</amount>
<alc>2</alc>
<amount>80000</amount>
</codeHeader>
<CodeHeader>
<code>1112</code>
<hd1>875</hd1>
<hd2>455</hd2>
<hd3>455</hd3>
<alc>2</alc>
<amount>80000</amount>
</CodeHeader>
</allocelement>
分组是基于Code [hd1,hd2,hd3]的,以便合并具有相同Code和[hd1,hd2,hd3]的不同元素,并且仅显示不同的字段。 和。 我也在使用xslt 1.0。
我假设您的输入XML具有一个根节点,该root
将所有XML包裹起来以构成格式良好的文档。 我还要假设所有allocelement
拼写正确(您有一些拼写为alloclement
)。 我还要假设您要删除由标签名称及其文本值标识的重复项。
使用XSLT 1.0 :
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="code" match="allocelement/code" use="."/>
<xsl:key name="code-sibling"
match="allocelement/*[name() != 'code']"
use="concat(parent::*/code, '|', name(), '|', .)"/>
<xsl:template match="@* | node()" name="copy">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="root/allocelement[1]"/>
</xsl:template>
<xsl:template match="allocelement">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates
select="(. | following-sibling::allocelement)/code
[generate-id() = generate-id(key('code', .)[1])]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="code">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:value-of select="."/>
<xsl:apply-templates
select="key('code', .)/(preceding-sibling::* | following-sibling::*)
[generate-id() =
generate-id(key('code-sibling', concat(parent::*/code, '|', name(), '|', .))[1])]"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
适用于:
<root>
<allocelement>
<hd1>12</hd1>
<hd2>14</hd2>
<hd3>87</hd3>
<alc>1</alc>
<amount>4587</amount>
<code>1111</code>
</allocelement>
<allocelement>
<hd1>12</hd1>
<hd2>14</hd2>
<hd3>87</hd3>
<alc>2</alc>
<amount>80000</amount>
<code>1111</code>
</allocelement>
<allocelement>
<hd1>875</hd1>
<hd2>455</hd2>
<hd3>455</hd3>
<alc>2</alc>
<amount>80000</amount>
<code>1112</code>
</allocelement>
</root>
产生:
<root>
<allocelement>
<code>1111<hd1>12</hd1>
<hd2>14</hd2>
<hd3>87</hd3>
<alc>1</alc>
<amount>4587</amount>
<alc>2</alc>
<amount>80000</amount>
</code>
<code>1112<hd1>875</hd1>
<hd2>455</hd2>
<hd3>455</hd3>
<alc>2</alc>
<amount>80000</amount>
</code>
</allocelement>
</root>
运作方式如下。 默认路由是身份转换 。 我们首先中断allocelement
然后将变换发送到其他路径。 我们让它复制唯一code
元素(由元素的文本值标识的唯一性)及其值,然后将模板应用于共享相同值的所有code
节点的所有先前/后续同级。 这些现在将是code
节点的子节点。 然后,我们对唯一的同级(属于具有相同值,具有相同名称和相同文本值的code
的同胞进行身份转换。
一注。 混合内容绝不是一个好主意。 看看您是否真的需要在code
下混合文本值和子节点。
使用XSLT 2.0,您可以远离generate-id()
:
<xsl:template match="allocelement">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:for-each-group select="(. | following-sibling::allocelement)/code" group-by=".">
<xsl:apply-templates select="."/>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
<xsl:template match="code">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:value-of select="."/>
<xsl:for-each-group select="key('code', .)/(preceding-sibling::* | following-sibling::*)"
group-by="concat(parent::*/code, '|', name(), '|', .)">
<xsl:apply-templates select="."/>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
一个明显更短,更简单的XSLT 1.0解决方案 :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kCodeByVal" match="code" use="."/>
<xsl:template match="/*">
<allocelement>
<xsl:apply-templates/>
</allocelement>
</xsl:template>
<xsl:template match="allocelement"/>
<xsl:template match=
"allocelement
[generate-id(code) = generate-id(key('kCodeByVal', code)[1])]">
<code><xsl:value-of select="code"/>
<xsl:copy-of select=
"node()[not(self::code)]
| key('kCodeByVal', code)/../*[self::alc or self::amount]"/>
</code>
</xsl:template>
</xsl:stylesheet>
当此转换应用于以下XML文档 (包装所提供的XML片段的单个顶部元素)时:
<t>
<allocelement>
<hd1>12</hd1>
<hd2>14</hd2>
<hd3>87</hd3>
<alc>1</alc>
<amount>4587</amount>
<code>1111</code>
</allocelement>
<allocelement>
<hd1>12</hd1>
<hd2>14</hd2>
<hd3>87</hd3>
<alc>2</alc>
<amount>80000</amount>
<code>1111</code>
</allocelement>
<allocelement>
<hd1>875</hd1>
<hd2>455</hd2>
<hd3>455</hd3>
<alc>2</alc>
<amount>80000</amount>
<code>1112</code>
</allocelement>
</t>
产生想要的正确结果 :
<allocelement>
<code>1111<hd1>12</hd1>
<hd2>14</hd2>
<hd3>87</hd3>
<alc>1</alc>
<amount>4587</amount>
<alc>2</alc>
<amount>80000</amount>
</code>
<code>1112<hd1>875</hd1>
<hd2>455</hd2>
<hd3>455</hd3>
<alc>2</alc>
<amount>80000</amount>
</code>
</allocelement>
说明 :正确使用Muenchian分组方法 。
二。 XSLT 2.0解决方案-再短一点,更重要的是-语法和语义上正确 :
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<allocelement>
<xsl:for-each-group select="*" group-by="code">
<code><xsl:value-of select="code"/>
<xsl:sequence select=
"node()[not(self::code)]
| current-group()/*[self::alc or self::amount]"/>
</code>
</xsl:for-each-group>
</allocelement>
</xsl:template>
</xsl:stylesheet>
更新 :OP更改了对输出的要求。
这是相应的修改后的XSLT 1.0解决方案 :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kCodeByVal" match="code" use="."/>
<xsl:template match="/*">
<allocelement>
<xsl:apply-templates/>
</allocelement>
</xsl:template>
<xsl:template match="allocelement"/>
<xsl:template match=
"allocelement
[generate-id(code) = generate-id(key('kCodeByVal', code)[1])]">
<codeHeader>
<code><xsl:value-of select="code"/></code>
<xsl:copy-of select=
"node()[not(self::code)]
| key('kCodeByVal', code)/../*[self::alc or self::amount]"/>
</codeHeader>
</xsl:template>
</xsl:stylesheet>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.