调整 xml 分组的字母索引以使列相等
Adjust an alphabetical index from xml grouping to make columns equal
是按字母顺序索引创建为 3 列的场景。但是,将它们分成列的方法有一定的改进空间。
在上面的场景中,有没有办法在不破坏字母组的情况下使3列尽可能相等。
我建议采用以下方法:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="columns" select="3"/>
<xsl:template match="/countries">
<xsl:variable name="indexed-countries">
<xsl:for-each select="country">
<xsl:sort select="."/>
<country index="{position()}">
<xsl:copy-of select="@*|*"/>
</country>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="groups">
<xsl:for-each-group select="$indexed-countries/country" group-by="substring(name, 1, 1)">
<group name="{current-grouping-key()}" cumulative-size="{current-group()[last()]/@index}">
<xsl:copy-of select="current-group()"/>
</group>
</xsl:for-each-group>
</xsl:variable>
<xsl:variable name="n" select="count(country)" />
<xsl:variable name="col-limit" select="ceiling($n div $columns)" />
<!-- output -->
<xsl:copy>
<xsl:for-each select="1 to $columns">
<xsl:variable name="low" select="(. - 1) * $col-limit" />
<xsl:variable name="high" select=". * $col-limit" />
<xsl:element name="column{.}">
<xsl:copy-of select="$groups/group[$low lt @cumulative-size and @cumulative-size le $high]"/>
</xsl:element>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
根据您的输入示例,结果 将是:
<?xml version="1.0" encoding="UTF-8"?>
<countries>
<column1>
<group name="A" cumulative-size="2">
<country index="1">
<name>Argentina</name>
</country>
<country index="2" x="AU">
<name>Australia</name>
</country>
</group>
<group name="C" cumulative-size="3">
<country index="3">
<name>Chile</name>
</country>
</group>
<group name="I" cumulative-size="5">
<country index="4">
<name>India</name>
</country>
<country index="5">
<name>Indonesia</name>
</country>
</group>
</column1>
<column2>
<group name="K" cumulative-size="6">
<country index="6">
<name>Kenya</name>
</country>
</group>
<group name="L" cumulative-size="7">
<country index="7">
<name>Latvia</name>
</country>
</group>
<group name="N" cumulative-size="8">
<country index="8">
<name>New Zeland</name>
</country>
</group>
<group name="S" cumulative-size="9">
<country index="9">
<name>Singapore</name>
</country>
</group>
<group name="T" cumulative-size="10">
<country index="10">
<name>Tunisia</name>
</country>
</group>
</column2>
<column3>
<group name="U" cumulative-size="12">
<country index="11">
<name>UK</name>
</country>
<country index="12">
<name>USA</name>
</country>
</group>
<group name="Z" cumulative-size="13">
<country index="13">
<name>Zambia</name>
</country>
</group>
</column3>
</countries>
当然,在真正的实现中,你会想在这里使用xsl-apply-templates
而不是xsl:copy-of
:
<xsl:copy-of select="$groups/group[$low lt @cumulative-size and @cumulative-size le $high]"/>
删除 "scaffolding" 并根据您的喜好格式化输出。
在上面的场景中,有没有办法在不破坏字母组的情况下使3列尽可能相等。
我建议采用以下方法:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="columns" select="3"/>
<xsl:template match="/countries">
<xsl:variable name="indexed-countries">
<xsl:for-each select="country">
<xsl:sort select="."/>
<country index="{position()}">
<xsl:copy-of select="@*|*"/>
</country>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="groups">
<xsl:for-each-group select="$indexed-countries/country" group-by="substring(name, 1, 1)">
<group name="{current-grouping-key()}" cumulative-size="{current-group()[last()]/@index}">
<xsl:copy-of select="current-group()"/>
</group>
</xsl:for-each-group>
</xsl:variable>
<xsl:variable name="n" select="count(country)" />
<xsl:variable name="col-limit" select="ceiling($n div $columns)" />
<!-- output -->
<xsl:copy>
<xsl:for-each select="1 to $columns">
<xsl:variable name="low" select="(. - 1) * $col-limit" />
<xsl:variable name="high" select=". * $col-limit" />
<xsl:element name="column{.}">
<xsl:copy-of select="$groups/group[$low lt @cumulative-size and @cumulative-size le $high]"/>
</xsl:element>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
根据您的输入示例,结果 将是:
<?xml version="1.0" encoding="UTF-8"?>
<countries>
<column1>
<group name="A" cumulative-size="2">
<country index="1">
<name>Argentina</name>
</country>
<country index="2" x="AU">
<name>Australia</name>
</country>
</group>
<group name="C" cumulative-size="3">
<country index="3">
<name>Chile</name>
</country>
</group>
<group name="I" cumulative-size="5">
<country index="4">
<name>India</name>
</country>
<country index="5">
<name>Indonesia</name>
</country>
</group>
</column1>
<column2>
<group name="K" cumulative-size="6">
<country index="6">
<name>Kenya</name>
</country>
</group>
<group name="L" cumulative-size="7">
<country index="7">
<name>Latvia</name>
</country>
</group>
<group name="N" cumulative-size="8">
<country index="8">
<name>New Zeland</name>
</country>
</group>
<group name="S" cumulative-size="9">
<country index="9">
<name>Singapore</name>
</country>
</group>
<group name="T" cumulative-size="10">
<country index="10">
<name>Tunisia</name>
</country>
</group>
</column2>
<column3>
<group name="U" cumulative-size="12">
<country index="11">
<name>UK</name>
</country>
<country index="12">
<name>USA</name>
</country>
</group>
<group name="Z" cumulative-size="13">
<country index="13">
<name>Zambia</name>
</country>
</group>
</column3>
</countries>
当然,在真正的实现中,你会想在这里使用xsl-apply-templates
而不是xsl:copy-of
:
<xsl:copy-of select="$groups/group[$low lt @cumulative-size and @cumulative-size le $high]"/>
删除 "scaffolding" 并根据您的喜好格式化输出。