我正在使用XSLT来转换从web派生的XML,并将其动态转换为表示为输出的目标xml文件。我仍然无法做到,即使尝试了很多,谁能帮我解决这个转换。
源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>
分组以代码、hd1、hd2、hd3为基础,使得在其中具有相同代码的不同元素和hd1、hd2、hd3将被合并,并且只显示不同的字段。和。另外,我正在使用XSLT1.0。
发布于 2012-05-30 04:05:54
一个更短、更简单的XSLT1.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>解释性:门窗分组法的正确使用。
XSLT2.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>UPDATE:OP已经更改了outpu的需求。
这里是相应的修改的XSLT1.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>发布于 2012-05-29 14:14:07
我假设您的输入XML有一个root节点,它封装所有这些以生成一个格式良好的文档。我还假设所有的allocelement都拼写正确(有些拼写为alloclement)。我还假设您希望删除标记名称及其文本值所标识的重复项。
使用XSLT1.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下的文本值和子节点。
使用XSLT2.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>https://stackoverflow.com/questions/10800627
复制相似问题