高级 muenchian 分组:按子集合中的项目分组
Advanced muenchian grouping: group by items in child collection
我熟悉 XSL 中的简单 muenchian 分组,但我遇到了一个问题,老实说我什至不知道如何处理它。
所以我有一个 XML:
<whiskies>
<whisky name="ABC" percent="" region="" type="">
<tastingNotesCollection/>
<bottles>
<bottle price="" size="" level="0" date=""/>
<bottle price="" size="" level="70" date=""/>
<bottle price="" size="" level="100" date=""/>
</bottles>
<comments/>
</whisky>
<whisky name="DEF" percent="" region="" type="">
<tastingNotesCollection/>
<bottles>
<bottle price="" size="" level="0" date=""/>
<bottle price="" size="" level="100" date=""/>
</bottles>
<comments/>
</whisky>
<whisky name="GHI" percent="" region="" type="">
<tastingNotesCollection/>
<bottles>
<bottle price="" size="" level="30" date=""/>
</bottles>
<comments/>
</whisky>
<whiskies>
目标是按瓶中的级别对威士忌进行分组:
所以 level="0"
被认为是空的。
从 level="1"
到 level="99"
的任何内容都被认为是开放的。
level="100"
视为未开封。
因此转换后的结果(将在 HTML 中完成)应该如下所示:
<h1>Empty</h1>
<ul>
<li>ABC</li>
<li>DEF</li>
</ul>
<h1>Open</h1>
<ul>
<li>ABC</li>
<li>GHI</li>
</ul>
<h1>Unopened</h1>
<ul>
<li>ABC</li>
<li>DEF</li>
</ul>
如您所见,同一种威士忌可以出现在多个组中,具体取决于瓶子的数量以及这些瓶子的装满程度。
第二个问题是,“开放”组没有确切的值,可以是 1 到 99 之间的任意值。
所以,是的,我真的不知道这是否可以解决,甚至不知道如何开始。任何提示表示赞赏。
我认为您不想为此使用 Muenchian 分组。您需要定义一个键来枚举 1 到 99 范围内的所有值 - 我相信这会带走使用键本来可以带来的任何优势。
由于您的结果只有 3 组或最多 3 组(您的问题在这方面不明确),您可以简单地做:
XSLT 1.0
<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:template match="/whiskies">
<output>
<group status="empty">
<xsl:for-each select="whisky[bottles/bottle/@level=0]">
<name>
<xsl:value-of select="@name"/>
</name>
</xsl:for-each>
</group>
<group status="open">
<xsl:for-each select="whisky[bottles/bottle[@level>0 and @level < 100]]">
<name>
<xsl:value-of select="@name"/>
</name>
</xsl:for-each>
</group>
<group status="unopened">
<xsl:for-each select="whisky[bottles/bottle/@level=100]">
<name>
<xsl:value-of select="@name"/>
</name>
</xsl:for-each>
</group>
</output>
</xsl:template>
</xsl:stylesheet>
得到(将输入固定为格式正确的XML!):
结果
<?xml version="1.0" encoding="utf-8"?>
<output>
<group status="empty">
<name>ABC</name>
<name>DEF</name>
</group>
<group status="open">
<name>ABC</name>
<name>GHI</name>
</group>
<group status="unopened">
<name>ABC</name>
<name>DEF</name>
</group>
</output>
对 HTML 输出进行自己的调整。
已添加:
这是一种使用键的替代方法(尽管仍然不是 Muenchian 分组),它的性能可能更高:
<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="w" match="whisky" use="bottles/bottle/@level" />
<xsl:key name="w1" match="whisky" use="boolean(bottles/bottle[@level!=0 and @level!=100])" />
<xsl:template match="/whiskies">
<output>
<group status="empty">
<xsl:for-each select="key('w', 0)">
<name>
<xsl:value-of select="@name"/>
</name>
</xsl:for-each>
</group>
<group status="open">
<xsl:for-each select="key('w1', true())">
<name>
<xsl:value-of select="@name"/>
</name>
</xsl:for-each>
</group>
<group status="unopened">
<xsl:for-each select="key('w', 100)">
<name>
<xsl:value-of select="@name"/>
</name>
</xsl:for-each>
</group>
</output>
</xsl:template>
</xsl:stylesheet>
甚至:
<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="bottle" match="bottle" use="ceiling(@level div 99)" />
<xsl:template match="/whiskies">
<output>
<group status="empty">
<xsl:for-each select="key('bottle', 0)/../..">
<name>
<xsl:value-of select="@name"/>
</name>
</xsl:for-each>
</group>
<group status="open">
<xsl:for-each select="key('bottle', 1)/../..">
<name>
<xsl:value-of select="@name"/>
</name>
</xsl:for-each>
</group>
<group status="unopened">
<xsl:for-each select="key('bottle', 2)/../..">
<name>
<xsl:value-of select="@name"/>
</name>
</xsl:for-each>
</group>
</output>
</xsl:template>
</xsl:stylesheet>
如果您确实想使用 xsl:key
,您可以使用过滤条件创建其中的 3 个:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" />
<xsl:key name="Empty" match="whisky[bottles/bottle/@level=0]" use="@name"/>
<xsl:key name="Open" match="whisky[bottles/bottle/@level[. > 1 and . < 99]]" use="@name"/>
<xsl:key name="Unopened" match="whisky[bottles/bottle/@level=100]" use="@name"/>
<xsl:template match="/">
<xsl:variable name="whiskies" select="/whiskies/whisky/@name"/>
<xsl:for-each select="document('')/xsl:stylesheet/xsl:key/@name">
<xsl:variable name="status" select="."/>
<h1><xsl:value-of select="$status"/></h1>
<ul>
<xsl:for-each select="$whiskies[key($status, .)]">
<li><xsl:value-of select="."/></li>
</xsl:for-each>
</ul>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
我熟悉 XSL 中的简单 muenchian 分组,但我遇到了一个问题,老实说我什至不知道如何处理它。
所以我有一个 XML:
<whiskies>
<whisky name="ABC" percent="" region="" type="">
<tastingNotesCollection/>
<bottles>
<bottle price="" size="" level="0" date=""/>
<bottle price="" size="" level="70" date=""/>
<bottle price="" size="" level="100" date=""/>
</bottles>
<comments/>
</whisky>
<whisky name="DEF" percent="" region="" type="">
<tastingNotesCollection/>
<bottles>
<bottle price="" size="" level="0" date=""/>
<bottle price="" size="" level="100" date=""/>
</bottles>
<comments/>
</whisky>
<whisky name="GHI" percent="" region="" type="">
<tastingNotesCollection/>
<bottles>
<bottle price="" size="" level="30" date=""/>
</bottles>
<comments/>
</whisky>
<whiskies>
目标是按瓶中的级别对威士忌进行分组:
所以 level="0"
被认为是空的。
从 level="1"
到 level="99"
的任何内容都被认为是开放的。
level="100"
视为未开封。
因此转换后的结果(将在 HTML 中完成)应该如下所示:
<h1>Empty</h1>
<ul>
<li>ABC</li>
<li>DEF</li>
</ul>
<h1>Open</h1>
<ul>
<li>ABC</li>
<li>GHI</li>
</ul>
<h1>Unopened</h1>
<ul>
<li>ABC</li>
<li>DEF</li>
</ul>
如您所见,同一种威士忌可以出现在多个组中,具体取决于瓶子的数量以及这些瓶子的装满程度。 第二个问题是,“开放”组没有确切的值,可以是 1 到 99 之间的任意值。
所以,是的,我真的不知道这是否可以解决,甚至不知道如何开始。任何提示表示赞赏。
我认为您不想为此使用 Muenchian 分组。您需要定义一个键来枚举 1 到 99 范围内的所有值 - 我相信这会带走使用键本来可以带来的任何优势。
由于您的结果只有 3 组或最多 3 组(您的问题在这方面不明确),您可以简单地做:
XSLT 1.0
<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:template match="/whiskies">
<output>
<group status="empty">
<xsl:for-each select="whisky[bottles/bottle/@level=0]">
<name>
<xsl:value-of select="@name"/>
</name>
</xsl:for-each>
</group>
<group status="open">
<xsl:for-each select="whisky[bottles/bottle[@level>0 and @level < 100]]">
<name>
<xsl:value-of select="@name"/>
</name>
</xsl:for-each>
</group>
<group status="unopened">
<xsl:for-each select="whisky[bottles/bottle/@level=100]">
<name>
<xsl:value-of select="@name"/>
</name>
</xsl:for-each>
</group>
</output>
</xsl:template>
</xsl:stylesheet>
得到(将输入固定为格式正确的XML!):
结果
<?xml version="1.0" encoding="utf-8"?>
<output>
<group status="empty">
<name>ABC</name>
<name>DEF</name>
</group>
<group status="open">
<name>ABC</name>
<name>GHI</name>
</group>
<group status="unopened">
<name>ABC</name>
<name>DEF</name>
</group>
</output>
对 HTML 输出进行自己的调整。
已添加:
这是一种使用键的替代方法(尽管仍然不是 Muenchian 分组),它的性能可能更高:
<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="w" match="whisky" use="bottles/bottle/@level" />
<xsl:key name="w1" match="whisky" use="boolean(bottles/bottle[@level!=0 and @level!=100])" />
<xsl:template match="/whiskies">
<output>
<group status="empty">
<xsl:for-each select="key('w', 0)">
<name>
<xsl:value-of select="@name"/>
</name>
</xsl:for-each>
</group>
<group status="open">
<xsl:for-each select="key('w1', true())">
<name>
<xsl:value-of select="@name"/>
</name>
</xsl:for-each>
</group>
<group status="unopened">
<xsl:for-each select="key('w', 100)">
<name>
<xsl:value-of select="@name"/>
</name>
</xsl:for-each>
</group>
</output>
</xsl:template>
</xsl:stylesheet>
甚至:
<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="bottle" match="bottle" use="ceiling(@level div 99)" />
<xsl:template match="/whiskies">
<output>
<group status="empty">
<xsl:for-each select="key('bottle', 0)/../..">
<name>
<xsl:value-of select="@name"/>
</name>
</xsl:for-each>
</group>
<group status="open">
<xsl:for-each select="key('bottle', 1)/../..">
<name>
<xsl:value-of select="@name"/>
</name>
</xsl:for-each>
</group>
<group status="unopened">
<xsl:for-each select="key('bottle', 2)/../..">
<name>
<xsl:value-of select="@name"/>
</name>
</xsl:for-each>
</group>
</output>
</xsl:template>
</xsl:stylesheet>
如果您确实想使用 xsl:key
,您可以使用过滤条件创建其中的 3 个:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" />
<xsl:key name="Empty" match="whisky[bottles/bottle/@level=0]" use="@name"/>
<xsl:key name="Open" match="whisky[bottles/bottle/@level[. > 1 and . < 99]]" use="@name"/>
<xsl:key name="Unopened" match="whisky[bottles/bottle/@level=100]" use="@name"/>
<xsl:template match="/">
<xsl:variable name="whiskies" select="/whiskies/whisky/@name"/>
<xsl:for-each select="document('')/xsl:stylesheet/xsl:key/@name">
<xsl:variable name="status" select="."/>
<h1><xsl:value-of select="$status"/></h1>
<ul>
<xsl:for-each select="$whiskies[key($status, .)]">
<li><xsl:value-of select="."/></li>
</xsl:for-each>
</ul>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>