我面临以下问题:
如果我有以下XML数据:
<Input>
<Error>
<Info>
<Code> 111 </Code>
<Value>Hello User </Value>
</Info>
<Info>
<Code>118</Code>
<Value>01</Value>
</Info>
</Error>
<Error>
<Info>
<Code> 111 </Code>
<Value>Bye User </Value>
</Info>
<Info>
<Code>118</Code>
<Value>01</Value>
</Info>
</Error>
<Error>
<Info>
<Code> 111 </Code>
<Value>Dead User </Value>
</Info>
<Info>
<Code>118</Code>
<Value>06</Value>
</Info>
</Error>
<Error>
<Info>
<Code> 111 </Code>
<Value>Killed User </Value>
</Info>
<Info>
<Code>118</Code>
<Value>08</Value>
</Info>
</Error>
</Input>
如何知道输出应该类似于
,我如何为上面的内容构建XSLT转换<RecNum>"Value found inside VALUE[2]"</RecNum>
<Error-Description> "Value found inside Value[1]" </Error-Description>
请注意,并不总是我有相同的输出。我确信,每个Error
元素中每次都有2个Info
元素和2个Value
元素。
然而,我不知道我在同一个Error
中有多少Value[2]
个元素,所以有时我有3个Error
元素,所有元素都有2个Info
标签,但这三个错误,他们的Info[2]/Value/text()
是相同的。
因此上述输入的输出应该是这样的
<Errors>
<Module>
<RecNum>1 </RecNum>
<Error-Description>Hello user </Error-Description>
<Error-Description>By User </Error-Description>
</Module>
<Module>
<RecNum>6 </RecNum>
<Error-Description> Dead User </Error-Description>
</Module>
<Module>
<RecNum>8 </RecNum>
<Error-Description> Killed User </Error-Description>
</Module>
</Errors>
请注意,我没有02,03,04,05,07,09等的值......
我只有01,06&amp;的值。 08有时可能会有所不同。如果你愿意,怎么办这样的逻辑?
答案 0 :(得分:3)
我建议在精神上使用模板时尽量避免xsl:for-each
支持真正的XSLT :
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kErrorByVal" match="Error" use="*[2]/Value"/>
<xsl:template match="/*">
<Errors>
<xsl:apply-templates select=
"*[generate-id()=generate-id(key('kErrorByVal',*[2]/Value)[1])]"/>
</Errors>
</xsl:template>
<xsl:template match="Error">
<Module>
<RecNum><xsl:value-of select="*[2]/Value"/></RecNum>
<xsl:apply-templates select="key('kErrorByVal',*[2]/Value)/*[1]/Value"/>
</Module>
</xsl:template>
<xsl:template match="Value">
<Error-Description><xsl:value-of select="."/></Error-Description>
</xsl:template>
</xsl:stylesheet>
在提供的XML文档上应用此转换时:
<Input>
<Error>
<Info>
<Code> 111 </Code>
<Value>Hello User </Value>
</Info>
<Info>
<Code>118</Code>
<Value>01</Value>
</Info>
</Error>
<Error>
<Info>
<Code> 111 </Code>
<Value>Bye User </Value>
</Info>
<Info>
<Code>118</Code>
<Value>01</Value>
</Info>
</Error>
<Error>
<Info>
<Code> 111 </Code>
<Value>Dead User </Value>
</Info>
<Info>
<Code>118</Code>
<Value>06</Value>
</Info>
</Error>
<Error>
<Info>
<Code> 111 </Code>
<Value>Killed User </Value>
</Info>
<Info>
<Code>118</Code>
<Value>08</Value>
</Info>
</Error>
</Input>
产生了想要的正确结果:
<Errors>
<Module>
<RecNum>01</RecNum>
<Error-Description>Hello User </Error-Description>
<Error-Description>Bye User </Error-Description>
</Module>
<Module>
<RecNum>06</RecNum>
<Error-Description>Dead User </Error-Description>
</Module>
<Module>
<RecNum>08</RecNum>
<Error-Description>Killed User </Error-Description>
</Module>
</Errors>
答案 1 :(得分:0)
此样式表使用键来标识具有相同Error
的所有Info[2]/Value
个节点。这被称为 Muenchian 方法。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:output method="xml" indent="yes"/>
<xsl:key name="error-by-code" match="Error" use="Info[2]/Value"/>
<xsl:template match="/">
<Errors>
<xsl:apply-templates select="Input/Error"/>
</Errors>
</xsl:template>
<xsl:template match="Error">
<xsl:variable name="error-code" select="Info[2]/Value"/>
<xsl:if test="generate-id() = generate-id(key('error-by-code', $error-code)[1])">
<Module>
<RecNum>
<xsl:value-of select="Info[2]/Value"/>
</RecNum>
<xsl:for-each select="key('error-by-code', $error-code)">
<Error-Description>
<xsl:value-of select="Info[1]/Value"/>
</Error-Description>
</xsl:for-each>
</Module>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
<强>输出强>
<?xml version="1.0" encoding="utf-8"?>
<Errors>
<Module>
<RecNum>01</RecNum>
<Error-Description>Hello User </Error-Description>
<Error-Description>Bye User </Error-Description>
</Module>
<Module>
<RecNum>06</RecNum>
<Error-Description>Dead User </Error-Description>
</Module>
<Module>
<RecNum>08</RecNum>
<Error-Description>Killed User </Error-Description>
</Module>
</Errors>
答案 2 :(得分:0)
这是没有任何ifs和变量的相同方法。它会检查所有错误值并对其进行分组。第二个for-each仅在第二个Info标签中选择所需的字符串。
这种方法应该是解决问题的快捷方法
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="errors-by-id" match="Error" use="Info[2]/Value" />
<xsl:template match="Input">
<xsl:for-each select="Error[count(. | key('errors-by-id', Info[2]/Value)[1]) = 1]">
<xsl:sort select="Info[2]/Value" />
<Modul>
<RecNum>
<xsl:value-of select="Info[2]/Value" />
</RecNum>
<xsl:for-each select="key('errors-by-id', Info[2]/Value)">
<Error-Description>
<xsl:value-of select="Info[1]/Value"/>
</Error-Description>
</xsl:for-each>
</Modul>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>