我想将元素分组到xml文件中(使用XSLT 1.0)。我尝试使用xsl:key函数。如果所有元素都有一个键,它工作正常。但我必须处理没有钥匙的元素。 实际上,没有键的元素被组合在一起。但我需要的是,如果元素没有键,则元素被分组到最后定义的键。
我希望我的代码片段更加明显。
如果第一个元素没有密钥,则应将其分组到第一个定义的密钥。
输入XML
<position>
<item>
<ZUZ_ID>001</ZUZ_ID>
<BRUTTO>154.70</BRUTTO>
</item>
<item>
<ZUZ_ID/>
<BRUTTO>2.73</BRUTTO>
</item>
<item>
<ZUZ_ID>002</ZUZ_ID>
<BRUTTO>17.85</BRUTTO>
</item>
<item>
<ZUZ_ID>001</ZUZ_ID>
<BRUTTO>17.85</BRUTTO>
</item>
</position>
实际XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="myGroup" match="item" use="normalize-space(./ZUZ_ID)"/>
<xsl:template match="position">
<groups>
<xsl:for-each select="./item[count(.|key('myGroup', normalize-space(ZUZ_ID))[1]) = 1]">
<group><xsl:value-of select="(ZUZ_ID)"/></group>
<xsl:for-each select="key('myGroup',(ZUZ_ID))">
<item><xsl:value-of select="(BRUTTO)"/></item>
</xsl:for-each>
</xsl:for-each>
</groups>
</xsl:template>
</xsl:stylesheet>
实际结果XML
<groups>
<group>001</group>
<item>154.70</item>
<item>17.85</item>
<group/>
<item>2.73</item>
<group>002</group>
<item>17.85</item>
</groups>
所需的输出XML
<groups>
<group>001</group>
<item>154.70</item>
<item>17.85</item>
<item>2.73</item>
<group>002</group>
<item>17.85</item>
</groups>
另一个例子
Item 1 (ZUZID="")
Item 2 (ZUZID="1")
Item 3 (ZUZID="1")
Item 4 (ZUZID="2")
Item 5 (ZUZID="")
Item 6 (ZUZID="")
Item 7 (ZUZID="3")
这应该分组到
Group 1 (Item 1, Item 2, Item 3)
Group 2 (Item 4, Item 5, Item 6)
Group 3 (Item 7)
另一个例子
Item 1 (ZUZID="")
Item 2 (ZUZID="")
这应该分组到一个包含所有第1项和第2项
的组另一个XML输入示例
<position>
<item>
<ZUZ_ID/>
<BRUTTO>10</BRUTTO>
</item>
<item>
<ZUZ_ID>001</ZUZ_ID>
<BRUTTO>20</BRUTTO>
</item>
<item>
<ZUZ_ID>001</ZUZ_ID>
<BRUTTO>30</BRUTTO>
</item>
<item>
<ZUZ_ID>002</ZUZ_ID>
<BRUTTO>40</BRUTTO>
</item>
<item>
<ZUZ_ID/>
<BRUTTO>50</BRUTTO>
</item>
</position>
期望输出
<groups>
<group>001</group>
<item>10</item>
<item>20</item>
<item>30</item>
<group>002</group>
<item>40</item>
<item>50</item>
</groups>
答案 0 :(得分:1)
你的元素有一个键,它是空字符串,如果你想根据前面的兄弟定义一个键,那么使用
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="myGroup" match="item" use="(ZUZ_ID[normalize-space()] | preceding-sibling::item[normalize-space(ZUZ_ID)]/ZUZ_ID)[last()]"/>
<xsl:template match="position">
<groups>
<xsl:for-each select="./item[count(.|key('myGroup', (ZUZ_ID[normalize-space()] | preceding-sibling::item[normalize-space(ZUZ_ID)]/ZUZ_ID)[last()])[1]) = 1]">
<group><xsl:value-of select="(ZUZ_ID)"/></group>
<xsl:for-each select="key('myGroup',(ZUZ_ID))">
<item><xsl:value-of select="(BRUTTO)"/></item>
</xsl:for-each>
</xsl:for-each>
</groups>
</xsl:template>
</xsl:stylesheet>
但请注意,输出顺序为
<groups>
<group>001</group>
<item>154.70</item>
<item>2.73</item>
<item>17.85</item>
<group>002</group>
<item>17.85</item>
</groups>
如果您想要处理更多案件,那么您可以为不同案件添加钥匙
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="myGroup"
match="item[normalize-space(ZUZ_ID)]"
use="ZUZ_ID"/>
<xsl:key name="myGroup"
match="item[not(normalize-space(ZUZ_ID)) and preceding-sibling::item[normalize-space(ZUZ_ID)]]"
use="preceding-sibling::item[normalize-space(ZUZ_ID)][1]/ZUZ_ID"/>
<xsl:key name="myGroup"
match="item[not(normalize-space(ZUZ_ID)) and not(preceding-sibling::item[normalize-space(ZUZ_ID)])]"
use="following-sibling::item[normalize-space(ZUZ_ID)][1]/ZUZ_ID"/>
<xsl:template match="position">
<groups>
<xsl:for-each select="./item[count(.|key('myGroup', (ZUZ_ID[normalize-space()] | preceding-sibling::item[normalize-space(ZUZ_ID)]/ZUZ_ID)[last()])[1]) = 1]">
<group><xsl:value-of select="(ZUZ_ID)"/></group>
<xsl:for-each select="key('myGroup',(ZUZ_ID))">
<item><xsl:value-of select="(BRUTTO)"/></item>
</xsl:for-each>
</xsl:for-each>
</groups>
</xsl:template>
</xsl:stylesheet>
未经测试,因为您没有提供任何XML输入样本。
答案 1 :(得分:1)
我更愿意在两个过程中执行此操作,首先为每个项目配备一个ID。然后分组变得简单。
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="item-by-id" match="item" use="@id"/>
<xsl:template match="/position">
<!-- first pass -->
<xsl:variable name="items">
<xsl:for-each select="item">
<item id="{ZUZ_ID[normalize-space()] | preceding-sibling::item[normalize-space(ZUZ_ID)][1][not(normalize-space(current()/ZUZ_ID))]/ZUZ_ID | following-sibling::item[normalize-space(ZUZ_ID)][1][not(normalize-space(current()/ZUZ_ID))]/ZUZ_ID }">
<xsl:value-of select="BRUTTO" />
</item>
</xsl:for-each>
</xsl:variable>
<!-- output -->
<groups>
<xsl:for-each select="exsl:node-set($items)/item[count(. | key('item-by-id', @id)[1]) = 1]">
<group>
<xsl:value-of select="@id"/>
</group>
<xsl:for-each select="key('item-by-id', @id)">
<item>
<xsl:value-of select="."/>
</item>
</xsl:for-each>
</xsl:for-each>
</groups>
</xsl:template>
</xsl:stylesheet>