XSLT 2 - 从indexize()列表中选择项目

时间:2013-07-14 20:07:42

标签: xslt-2.0 tokenize saxon

我的环境是使用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>.&#xD;&#xA;</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.

1 个答案:

答案 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>.&#10;</xsl:text>
  </xsl:for-each-group>

</xsl:template>

</xsl:stylesheet>

如果您想坚持使用调用模板的方法,请确保使用例如模板存储模板的上下文节点。 <xsl:variable name="this" select="."/>以便您可以在for-each内部对字符串项进行迭代访问。