我正在尝试使用XSLT转换文档,方法是使用整数ID标记一组XML节点,从0开始,并为组中的每个节点增加1。传入样式表的XML应该被回显,但是要增加以包含这些额外的信息。
为了清楚我所说的内容,以下是使用DOM表达这种转换的方式:
states = document.getElementsByTagName("state");
for( i = 0; i < states.length; i++){
states.stateNum = i;
}
使用DOM非常简单,但是使用XSLT时我遇到了更多麻烦。我设计的当前策略是从身份转换开始,然后创建一个全局变量,选择并存储我想要编号的所有节点。然后我创建一个匹配那种节点的模板。那么,我的想法是,在模板中,我会在全局变量nodelist中查找匹配节点的位置,这将给出一个我可以设置为属性的唯一编号。
这种方法的问题是位置函数只能与上下文节点一起使用,所以类似下面的内容是非法的:
<template match="state">
<variable name="stateId" select="@id"/>
<variable name="uniqueStateNum" select="$globalVariable[@id = $stateId]/position()"/>
</template>
以下情况也是如此:
<template match="state">
<variable name="stateId" select="@id"
<variable name="stateNum" select="position($globalVariable[@id = $stateId])/"/>
</template>
为了使用position()在$ globalVariable中查找元素的位置,必须更改上下文节点。
我找到了一个解决方案,但它非常不理想。基本上,在模板中,我使用for-each迭代遍历全局变量。 For-each更改了上下文节点,因此这允许我以我描述的方式使用position()。问题在于,这通常将O(n)操作转换为O(n ^ 2)操作,其中n是节点列表的长度,因为这需要在模板匹配时遍历整个列表。我认为必须有一个更优雅的解决方案。
总而言之,这是我目前的(略微简化的)xslt样式表:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:s="http://www.w3.org/2005/07/scxml"
xmlns="http://www.w3.org/2005/07/scxml"
xmlns:c="http://msdl.cs.mcgill.ca/"
version="1.0">
<xsl:output method="xml"/>
<!-- we copy them, so that we can use their positions as identifiers -->
<xsl:variable name="states" select="//s:state" />
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="s:state">
<xsl:variable name="stateId">
<xsl:value-of select="@id"/>
</xsl:variable>
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:for-each select="$states">
<xsl:if test="@id = $stateId">
<xsl:attribute name="stateNum" namespace="http://msdl.cs.mcgill.ca/">
<xsl:value-of select="position()"/>
</xsl:attribute>
</xsl:if>
</xsl:for-each>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
我很感激任何人都能提供的建议。感谢。
答案 0 :(得分:3)
此转化:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:s="http://www.w3.org/2005/07/scxml"
>
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="s:state">
<xsl:variable name="vNum">
<xsl:number level="any" count="s:state"/>
</xsl:variable>
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:attribute name="stateId">
<xsl:value-of select="@id"/>
</xsl:attribute>
<xsl:attribute name="id">
<xsl:value-of select="$vNum -1"/>
</xsl:attribute>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
应用于提供的XML文档:
<scxml xmlns="http://www.w3.org/2005/07/scxml">
<state id="Compound1">
<state id="Basic1"/>
<state id="Basic2"/>
<state id="Basic3"/>
</state>
</scxml>
生成所需的正确输出:
<scxml xmlns="http://www.w3.org/2005/07/scxml">
<state stateId="Compound1" id="0">
<state stateId="Basic1" id="1"/>
<state stateId="Basic2" id="2"/>
<state stateId="Basic3" id="3"/>
</state>
</scxml>
答案 1 :(得分:0)
最简单的方法:
<xsl:template match="s:state">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:attribute name="stateNum" namespace="http://msdl.cs.mcgill.ca/">
<xsl:value-of select="count(preceding::s:state)" />
</xsl:attribute>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
不确定您的XSLT处理器如何处理preceding
轴,因此无论如何都需要进行基准测试。