我的环境是使用XSLT 2.0的SAXON(最后一晚构建)。我的真正的问题是XML文档规范是次优的,在某种程度上,我的问题涉及修复/解决该设计问题。
我有一个节点类型(<weaponmodesdata>
),其中所有直接子节点都是| - 一个或多个元素的分隔字符串列表(相同<weaponmodesdata>
的每个子节点将具有相同的长度) 。我需要查看所表示的各种模式,并将它们“取消固定”以分隔项目列表(以纯文本格式),而不是将它们全部一起粉碎。
不幸的是,现在我变得非常顽固
XPTY0020: Required item type of the context item for the child axis is node(); supplied
value has item type xs:string
在我传递需要拆分成我的小模板的节点的行上出现错误。
目前我有
<xsl:template match="trait" mode="attack">
<xsl:for-each select="tokenize(weaponmodesdata/mode, '\|')">
<xsl:variable name="count" select="position()"/>
<xsl:value-of select="name"/><xsl:text> - </xsl:text>
<xsl:call-template name="split_weaponmode">
<xsl:with-param name="source" select="weaponmodesdata/damage"/>
<xsl:with-param name="item" select="$count"/>
</xsl:call-template>
<xsl:text> </xsl:text>
<xsl:call-template name="split_weaponmode">
<xsl:with-param name="source" select="weaponmodesdata/damtype"/>
<xsl:with-param name="item" select="$count"/>
</xsl:call-template>
<!-- more will go here eventually -->
<xsl:text>.
</xsl:text>
</xsl:for-each>
</xsl:template>
<xsl:template name="split_weaponmode">
<xsl:param name="source"/>
<xsl:param name="item"/>
<xsl:variable name="parts" select="tokenize($source, '\|')"/>
<xsl:for-each select="$parts">
<xsl:if test="position() = $item">
<xsl:value-of select="."/>
</xsl:if>
</xsl:for-each>
</xsl:template>
与我的问题相关的示例XML子树:
<character>
<trait id="1">
<name>Spear</name>
<weaponmodesdata>
<mode>1H Thrust|2H Thrust|Thrown</mode>
<damage>thr+2|thr+3|thr+3</damage>
<damtype>imp|imp|imp</damtype>
</weaponmodesdata>
</trait>
<trait id="2">
<name>Broadsword</name>
<weaponmodesdata>
<mode>1H Thrust|1H Swing</mode>
<damage>thr+1|sw+2</damage>
<damtype>imp|cut</damtype>
</weaponmodesdata>
</trait>
</character>
示例所需输出:
Spear - 1H Thrust; thr+2 imp.
Spear - 2H Thrust; thr+3 imp.
Spear - Thrown; thr+3 imp.
Broadsword - 1H Thrust; thr+1 imp.
Broadsword - 1H Swing; sw+2 cut.
答案 0 :(得分:2)
使用您的代码的一个问题(导致错误消息的问题)是您的for-each
对字符串值序列进行操作(即在for-each
主体内部,上下文项是字符串值),但是你有像weaponmodesdata/damage
这样的相对XPath表达式需要一个上下文节点才有意义。因此,您需要使用for-each
之外的变量来存储您的上下文节点。
但我认为您可以将代码简化为
<xsl:stylesheet
version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="trait">
<xsl:variable name="this" select="."/>
<xsl:variable name="count" select="count(tokenize(weaponmodesdata/*[1], '\|'))"/>
<xsl:for-each-group select="weaponmodesdata/*/tokenize(., '\|')" group-by="position() mod $count">
<xsl:value-of select="$this/name"/>
<xsl:text> - </xsl:text>
<xsl:value-of select="current-group()"/>
<xsl:text>. </xsl:text>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
如果您想坚持使用调用模板的方法,请确保使用例如模板存储模板的上下文节点。 <xsl:variable name="this" select="."/>
以便您可以在for-each
内部对字符串项进行迭代访问。