在 XSLT 2.0 中创建具有固定列数的字母索引
Creating alphabetical index with fixed number of columns in XSLT 2.0
我有一个 XML 这样的:
<xml version="1.0" encoding="UTF-8"?>
<countries>
<country>
<name>Latvia</name>
</country>
<country>
<name>USA</name>
</country>
<country>
<name>Australia</name>
</country>
<country>
<name>Indonesia</name>
</country>
<country>
<name>UK</name>
</country>
<country>
<name>India</name>
</country>
<country>
<name>Argentina</name>
</country>
<country>
<name>Chile</name>
</country>
<country>
<name>Singapore</name>
</country>
<country>
<name>New Zeland</name>
</country>
<country>
<name>Kenya</name>
</country>
<country>
<name>Zambia</name>
</country>
<country>
<name>Tunisia</name>
</country>
</countries>
现在我想在 3 列中创建按字母顺序排列的国家/地区索引。每列将包含 alpha 的数量,作为出现的起始字母的三分之一及其对应的国家/地区。
如果出现的起始字母数恰好不能被 3 整除,最后一列可以有其余的。
例如,这里有以 L、C、U、A、I、S、N、K、Z 和 T 开头的国家/地区名称。
排列后:A C I K L N S T U Z
现在,我的索引将有:
Column1: A, C and I countries
Column2: K, L and N countries
Column3: S, T, U and Z countries
因此所需的输出是:
<countries>
<column1>
<A>
<country>
<name>Argentina</name>
</country>
<country>
<name>Australia</name>
</country>
</A>
<C>
<country>
<name>Chile</name>
</country>
</C>
<I>
<country>
<name>India</name>
</country>
<country>
<name>Indonesia</name>
</country>
</I>
</column1>
<column2>
<K>
<country>
<name>Kenya</name>
</country>
</K>
<L>
<country>
<name>Latvia</name>
</country>
</L>
<N>
<country>
<name>New Zeland</name>
</country>
</N>
</column2>
<column3>
<S>
<country>
<name>Singapore</name>
</country>
</S>
<T>
<country>
<name>Tunisia</name>
</country>
</T>
<U>
<country>
<name>UK</name>
</country>
<country>
<name>USA</name>
</country>
</U>
<Z>
<country>
<name>Zambia</name>
</country>
</Z>
</column3>
</countries>
请帮忙。我正在使用 xslt 2.0.
我会考虑分两次执行此操作,首先按字母排序和分组,给出 A
- Z
元素的序列,然后将此序列划分为列。
<xsl:variable name="groups" as="element()*">
<xsl:for-each-group select="/countries/country" group-by="substring(name, 1, 1)">
<!-- sort groups alphabetically -->
<xsl:sort select="current-grouping-key()" />
<xsl:element name="{current-grouping-key()}">
<xsl:perform-sort select="current-group()">
<!-- sort names within each group -->
<xsl:sort select="name" />
</xsl:perform-sort>
</xsl:element>
</xsl:for-each-group>
</xsl:variable>
<xsl:variable name="numPerCol" select="count($groups) div 3" />
<column1>
<xsl:sequence select="$groups[position() le $numPerCol]"/>
</column1>
<column2>
<xsl:sequence select="$groups[position() gt $numPerCol and position() le (2*$numPerCol)]" />
</column2>
<column3>
<xsl:sequence select="$groups[position() gt (2*$numPerCol)]" />
</column3>
我想到了
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output indent="yes"/>
<xsl:param name="size" select="3"/>
<xsl:template match="countries">
<xsl:copy>
<xsl:variable name="groups">
<xsl:for-each-group select="country" group-by="substring(name, 1, 1)">
<xsl:sort select="current-grouping-key()"/>
<xsl:element name="{current-grouping-key()}">
<xsl:copy-of select="current-group()"/>
</xsl:element>
</xsl:for-each-group>
</xsl:variable>
<xsl:for-each select="$groups/*[position() mod $size eq 1]">
<xsl:if test="position() le $size">
<xsl:variable name="pos" select="position()"/>
<xsl:element name="column{position()}">
<xsl:copy-of select="., following-sibling::*[if ($pos eq $size) then true() else (position() lt $size)]"/>
</xsl:element>
</xsl:if>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:transform>
我有一个 XML 这样的:
<xml version="1.0" encoding="UTF-8"?>
<countries>
<country>
<name>Latvia</name>
</country>
<country>
<name>USA</name>
</country>
<country>
<name>Australia</name>
</country>
<country>
<name>Indonesia</name>
</country>
<country>
<name>UK</name>
</country>
<country>
<name>India</name>
</country>
<country>
<name>Argentina</name>
</country>
<country>
<name>Chile</name>
</country>
<country>
<name>Singapore</name>
</country>
<country>
<name>New Zeland</name>
</country>
<country>
<name>Kenya</name>
</country>
<country>
<name>Zambia</name>
</country>
<country>
<name>Tunisia</name>
</country>
</countries>
现在我想在 3 列中创建按字母顺序排列的国家/地区索引。每列将包含 alpha 的数量,作为出现的起始字母的三分之一及其对应的国家/地区。
如果出现的起始字母数恰好不能被 3 整除,最后一列可以有其余的。
例如,这里有以 L、C、U、A、I、S、N、K、Z 和 T 开头的国家/地区名称。
排列后:A C I K L N S T U Z
现在,我的索引将有:
Column1: A, C and I countries
Column2: K, L and N countries
Column3: S, T, U and Z countries
因此所需的输出是:
<countries>
<column1>
<A>
<country>
<name>Argentina</name>
</country>
<country>
<name>Australia</name>
</country>
</A>
<C>
<country>
<name>Chile</name>
</country>
</C>
<I>
<country>
<name>India</name>
</country>
<country>
<name>Indonesia</name>
</country>
</I>
</column1>
<column2>
<K>
<country>
<name>Kenya</name>
</country>
</K>
<L>
<country>
<name>Latvia</name>
</country>
</L>
<N>
<country>
<name>New Zeland</name>
</country>
</N>
</column2>
<column3>
<S>
<country>
<name>Singapore</name>
</country>
</S>
<T>
<country>
<name>Tunisia</name>
</country>
</T>
<U>
<country>
<name>UK</name>
</country>
<country>
<name>USA</name>
</country>
</U>
<Z>
<country>
<name>Zambia</name>
</country>
</Z>
</column3>
</countries>
请帮忙。我正在使用 xslt 2.0.
我会考虑分两次执行此操作,首先按字母排序和分组,给出 A
- Z
元素的序列,然后将此序列划分为列。
<xsl:variable name="groups" as="element()*">
<xsl:for-each-group select="/countries/country" group-by="substring(name, 1, 1)">
<!-- sort groups alphabetically -->
<xsl:sort select="current-grouping-key()" />
<xsl:element name="{current-grouping-key()}">
<xsl:perform-sort select="current-group()">
<!-- sort names within each group -->
<xsl:sort select="name" />
</xsl:perform-sort>
</xsl:element>
</xsl:for-each-group>
</xsl:variable>
<xsl:variable name="numPerCol" select="count($groups) div 3" />
<column1>
<xsl:sequence select="$groups[position() le $numPerCol]"/>
</column1>
<column2>
<xsl:sequence select="$groups[position() gt $numPerCol and position() le (2*$numPerCol)]" />
</column2>
<column3>
<xsl:sequence select="$groups[position() gt (2*$numPerCol)]" />
</column3>
我想到了
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output indent="yes"/>
<xsl:param name="size" select="3"/>
<xsl:template match="countries">
<xsl:copy>
<xsl:variable name="groups">
<xsl:for-each-group select="country" group-by="substring(name, 1, 1)">
<xsl:sort select="current-grouping-key()"/>
<xsl:element name="{current-grouping-key()}">
<xsl:copy-of select="current-group()"/>
</xsl:element>
</xsl:for-each-group>
</xsl:variable>
<xsl:for-each select="$groups/*[position() mod $size eq 1]">
<xsl:if test="position() le $size">
<xsl:variable name="pos" select="position()"/>
<xsl:element name="column{position()}">
<xsl:copy-of select="., following-sibling::*[if ($pos eq $size) then true() else (position() lt $size)]"/>
</xsl:element>
</xsl:if>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:transform>