Xslt 为字母表中的每个字母循环xsl:的更好方法?
我有一个很长的XML文件,我需要从中提取书名和其他信息,然后按字母顺序排序,每个字母都有一个分隔符。我还需要一个部分的项目,不以字母开头,说一个数字或符号。比如: # 1494-精装版,9.99美元 A 《金沙》之后——平装本,24.95美元 北极精神号-精装,65.00美元 B 平装本,18.95美元 我还需要创建一个单独的作者列表,从相同的数据创建,但显示不同类型的信息 我现在是怎么做的 这是简化的,但我基本上有两次相同的代码,一次用于标题,一次用于作者。模板的作者版本使用不同的元素,并对数据执行不同的操作,因此我不能使用相同的模板Xslt 为字母表中的每个字母循环xsl:的更好方法?,xslt,xslt-1.0,Xslt,Xslt 1.0,我有一个很长的XML文件,我需要从中提取书名和其他信息,然后按字母顺序排序,每个字母都有一个分隔符。我还需要一个部分的项目,不以字母开头,说一个数字或符号。比如: # 1494-精装版,9.99美元 A 《金沙》之后——平装本,24.95美元 北极精神号-精装,65.00美元 B 平装本,18.95美元 我还需要创建一个单独的作者列表,从相同的数据创建,但显示不同类型的信息 我现在是怎么做的 这是简化的,但我基本上有两次相同的代码,一次用于标题,一次用于作者。模板的作者版本使用不同的元素,并对
<xsl:call-template name="BIP-letter">
<xsl:with-param name="letter" select="'#'" />
</xsl:call-template>
<xsl:call-template name="BIP-letter">
<xsl:with-param name="letter" select="'A'" />
</xsl:call-template>
…
<xsl:call-template name="BIP-letter">
<xsl:with-param name="letter" select="'Z'" />
</xsl:call-template>
<xsl:template name="BIP-letter">
<xsl:param name="letter" />
<xsl:choose>
<xsl:when test="$letter = '#'">
<xsl:text>#</xsl:text>
<xsl:for-each select="//Book[
not(substring(Title,1,1) = 'A') and
not(substring(Title,1,1) = 'B') and
…
not(substring(Title/,1,1) = 'Z')
]">
<xsl:sort select="Title" />
<xsl:appy-templates select="Title" />
<!-- Add other relevant data here -->
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$letter" />
<xsl:for-each select="//Book[substring(Title,1,1) = $letter]">
<xsl:sort select="Title" />
<xsl:appy-templates select="Title" />
<!-- Add other relevant data here -->
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
…
#
我的问题
上面的代码工作正常,但是:
的东西,我可以在调用模板时使用它来设置参数//Book[not(substring(Title,1,1)=[A-Z])
此解决方案回答了所有问题:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vLowercase" select="'abcdefghijklmnopqrstuvuxyz'"/>
<xsl:variable name="vUppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
<xsl:variable name="vDigits" select="'0123456789'"/>
<xsl:key name="kBookBy1stChar" match="Book"
use="translate(substring(Title, 1, 1),
'abcdefghijklmnopqrstuvuxyz0123456789',
'ABCDEFGHIJKLMNOPQRSTUVWXYZ##########'
)"/>
<xsl:template match="/*">
<xsl:apply-templates mode="firstInGroup" select=
"Book[generate-id()
= generate-id(key('kBookBy1stChar',
translate(substring(Title, 1, 1),
concat($vLowercase, $vDigits),
concat($vUppercase, '##########')
)
)[1]
)
]">
<xsl:sort select="translate(substring(Title, 1, 1),
concat($vLowercase, $vDigits),
concat($vUppercase, '##########')
)"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="Book" mode="firstInGroup">
<xsl:value-of select="'
'"/>
<xsl:value-of select="translate(substring(Title, 1, 1),
concat($vLowercase, $vDigits),
concat($vUppercase, '##########')
)"/>
<xsl:apply-templates select=
"key('kBookBy1stChar',
translate(substring(Title, 1, 1),
concat($vLowercase, $vDigits),
concat($vUppercase, '##########')
)
)">
<xsl:sort select="Title"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="Book">
<xsl:value-of select="'
'"/>
<xsl:value-of select="concat(Title, ' - ', Binding, ', $', price)"/>
</xsl:template>
</xsl:stylesheet>
说明:
#
1494 - hardcover, $9.99
A
After the Sands - paperback, $24.95
Arctic Spirit - hardcover, $65.00
B
Back to the Front - paperback, $18.95
C
Cats Galore: A Compendium of Cultured Cats - hardcover, $5.00
最有问题的部分是: 我还需要一个部分的项目,不以字母开头,说一个数字或符号 如果您有一个项目可以开始的所有可能符号的列表,那么您可以简单地使用
translate()
将它们全部转换为
字符。否则它会变得更复杂。我会尝试以下方法:
XSLT1.0(+EXSLT node-set())
#
-
,
但是,这仍然存在以变音字母开头的项目的问题,例如“Österreich”或希腊字母。在这种方法下,它们也将聚集在
#
下
不幸的是,解决这个问题的唯一好办法是使用XSLT2.0
演示:这太棒了,谢谢!我对XSLT不是非常熟悉,所以我不知道Muenchian方法或
模式
。但这非常有效,并将帮助我简化代码的其他方面。@ShedSimas欢迎您。为了了解XSLT和XPath,我推荐现有的PluralsightXSLT1.0/2.0/3.0教程,以及XPath3.0教程。
#
1494 - hardcover, $9.99
A
After the Sands - paperback, $24.95
Arctic Spirit - hardcover, $65.00
B
Back to the Front - paperback, $18.95
C
Cats Galore: A Compendium of Cultured Cats - hardcover, $5.00
<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="text" encoding="UTF-8"/>
<xsl:key name="book" match="Book" use="index" />
<xsl:template match="/Books">
<!-- first-pass: add index char -->
<xsl:variable name="books-rtf">
<xsl:for-each select="Book">
<xsl:copy>
<xsl:copy-of select="*"/>
<index>
<xsl:variable name="index" select="translate(substring(Title, 1, 1), 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')" />
<xsl:choose>
<xsl:when test="contains('ABCDEFGHIJKLMNOPQRSTUVWXYZ', $index)">
<xsl:value-of select="$index"/>
</xsl:when>
<xsl:otherwise>#</xsl:otherwise>
</xsl:choose>
</index>
</xsl:copy>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="books" select="exsl:node-set($books-rtf)/Book" />
<!-- group by index char -->
<xsl:for-each select="$books[count(. | key('book', index)[1]) = 1]">
<xsl:sort select="index"/>
<xsl:value-of select="index"/>
<xsl:text> </xsl:text>
<!-- list books -->
<xsl:for-each select="key('book', index)">
<xsl:sort select="Title"/>
<xsl:value-of select="Title"/>
<xsl:text> - </xsl:text>
<xsl:value-of select="Binding"/>
<xsl:text>, </xsl:text>
<xsl:value-of select="Price"/>
<xsl:text> </xsl:text>
</xsl:for-each>
<xsl:text> </xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>