【发布时间】:2014-06-11 16:14:53
【问题描述】:
我有一个类似的 XML 结构
<Object id="id0000" link="id0010 id0020">
<Data id="id1000">
<DataValue name="Obj0000"/>
</Data>
</Object>
我有几个“对象”节点,其中一些有一个链接,其中一些有两个或多个链接。链接(ID)由空格分隔。我已经使用了 'tokenize()' 函数来获取单个链接 ID
<xsl:variable name="links">
<xsl:value-of select="tokenize(@link, ' ')"/>
</xsl:variable>
每个链接都指向另一个带有一些数据的“对象”。
现在我想将链接的位置(id)用作字符串,所以我的输出应该类似于
<Object>
<hasName>Obj0000</hasName>
<hasStartLink>id0010</hasStartLink>
</Object>
<LinkedObject>
<hasID>id0010</hasID>
<hasDescription>1. link of Obj0000</hasDescription>
<hasNextLink>id0020</hasNextLink>
</LinkedObject>
<LinkedObject>
<hasID>id0020</hasID>
<hasDescription>2. link of Obj0000</hasDescription>
</LinkedObject>
我发现很多页面都说,迭代和保存当前位置是无法以这种方式完成的,必须以某种方式解决。我发现了类似的东西
<!-- inside another template -->
<xsl:call-template name="LinkedObj">
<xsl:with-param name="count" select="1"/>
</xsl:call-template>
<!-- end of another template -->
<xsl:template name="LinkedObj">
<xsl:param name="count"/>
<!-- do some stuff here -->
<!-- use '$count' as position -->
<xsl:call-template name="LinkedObj>
<xsl:with-param name="count" select="$count + 1"/>
</xsl:call-template>
</xsl:template>
但现在我不知道我是否可以使用这样的模板。我宁愿不在模板本身而是在“另一个模板”中再次调用模板。但是在这个(“另一个”)模板中,我没有当前的计数变量,对吧? 在“LinkedObj”模板中,我已经在另一个上下文中,所以我不知道应该调用另一个模板多少次(我没有“链接”)。 目前我正在使用两个参数进行操作,因此我正在检查我的位置是否小于属性(链接)的数量:
<xsl:template match="Object">
<xsl:element name="Object>
<xsl:element name="hasName">
<xsl:value-of select="Data/DataValue/@name"/>
</xsl:element>
<xsl:element name="hasStartLink">
<!-- here I'm also not sure how to get only the first separated id -->
</xsl:element>
</xsl:element>
<xsl:call-template name="LinkedObj">
<xsl:with-param name="position" select="1"/>
<xsl:with-param name="count" select="count(tokenize(@link, ' '))"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="LinkedObj">
<xsl:param name="position"/>
<xsl:param name="count"/>
<!-- do some stuff here -->
<!-- use '$position' as position -->
<xsl:if test="$position < $count">
<xsl:call-template name="LinkedObj>
<xsl:with-param name="position" select="$position + 1"/>
<xsl:with-param name="count" select="$count"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
对此有何建议?
下一步不仅要获取位置并将其用于文本输出,还要使用链接的 id 来调用或应用新模板。正如我在最后一个代码块中评论的那样,我不知道如何将标记化字符串的元素用作节点。我尝试使用 for-each 元素,但我没有那样工作,因为存在一些上下文错误(我必须重现它并在此处发布)。
编辑: 我找到了一种让它工作的方法,这与 Tobias 的想法不同,所以我在这里发布基本代码:
<xsl:template match="Object">
<xsl:element name="Object>
<xsl:element name="hasName">
<xsl:value-of select="Data/DataValue/@name"/>
</xsl:element>
<xsl:element name="hasStartLink">
<!-- here I'm also not sure how to get only the first separated id -->
</xsl:element>
</xsl:element>
<xsl:call-template name="LinkedObj">
<xsl:with-param name="position" select="1"/>
<xsl:with-param name="count" select="count(tokenize(@link, ' '))"/>
<xsl:with-param name="links" select="tokenize(@link, ' ')"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="LinkedObj">
<xsl:param name="position"/>
<xsl:param name="count"/>
<xsl:param name="links"/>
<xsl:element name="hasID">
<xsl:value-of select="$links[$position]"/>
</xsl:element>
<xsl:element name="hasDescription">
<xsl:value-of select="concat($position, '. link of ', Data/DataValue/@name)"/>
</xsl:element>
<xsl:if test="$position < $count">
<xsl:element name="hasNextLink">
<xsl:value-of select="$links[$position + 1]"/>
</xsl:element>
<xsl:call-template name="LinkedObj>
<xsl:with-param name="position" select="$position + 1"/>
<xsl:with-param name="count" select="$count"/>
<xsl:with-param name="links" select="$links"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
在这种情况下,可以在“LinkedObj”模板中获取“Object”的值,因为模板是通过一个节点调用的(“Object”,因为上下文不会改变)。
【问题讨论】:
-
我现在(如上所述)使用“调用模板”而不是“应用模板”,我的上下文没有改变,所以现在我可以在调用模板。在被调用的模板中,我现在可以写
<xsl:apply-templates select="//Object[@id=$links[$position]]" mode="Link"/>。该位置将始终获取当前链接,因为它在此模板中递增。 -
我添加了一个答案,只是作为旁注,不要在变量内使用
<xsl:value-of select="tokenize(@link, ' ')"/>,这只会再次给你相同的字符串,要么使用xsl:sequence,要么使用变量的选择属性。 -
我目前在调用我的“LinkedObj”模板时使用
<xsl:with-param name="links" select="tokenize(@link, ' ')"/>。在此模板中,我使用参数“位置”(将递增)来获取标记化字符串的内容,例如$links[$position]。所以也许我没有理解重点:存储在参数“link”中的标记化字符串基本上只是一个字符串(分成一组子字符串)。每次调用“LinkedObj”模板时,我都想访问不同的子字符串。