XSLT - 条件中的变量未分配数组值
XSLT - variable in condition is not assigned with array value
使用 xslt3 (Saxon JS) 且未绑定到特定的 XSLT 版本
鉴于此 sample.xml
<?xml version=”1.0″ encoding=”UTF-8″?>
<tasks>
<task id="id0"/>
<task id="id1" parent="#id0" deps="#id2 #id3 #id0"/>
<task id="id2" parent="#id0"/>
<task id="id3" parent="#id0"/>
</tasks>
和这个sample.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="/tasks/task">
<xsl:variable name="parentTask" select="replace(@parent,'#','')"/>
<xsl:variable name="depTasks">
<xsl:choose>
<xsl:when test="@deps">
<xsl:value-of select="tokenize(replace(@deps,'#',''),'\s')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$parentTask"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<parent id="{@id}">
<xsl:for-each select="/tasks/task[@id=$depTasks]">
<dep>
<xsl:value-of select="@id"/>
</dep>
</xsl:for-each>
</parent>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
我希望 $depTasks
变量包含一个数组(deps
属性中列出的所有 deps)或单个值(dep 列在 parent
属性中),并获得这样的转换:
<?xml version="1.0" encoding="UTF-8"?>
<parent id="id0"/>
<parent id="id1">
<dep>id2</dep>
<dep>id3</dep>
<dep>id0</dep>
</parent>
<parent id="id2">
<dep>id0</dep>
</parent>
<parent id="id3">
<dep>id0</dep>
</parent>
但是我得到了这个结果(似乎只分配了标记化的第一个元素)
<?xml version="1.0" encoding="UTF-8"?>
<parent id="id0"/>
<parent id="id1">
<dep>id2</dep>
<!-- MISSING DEPS -->
</parent>
<parent id="id2">
<dep>id0</dep>
</parent>
<parent id="id3">
<dep>id0</dep>
</parent>
内部条件变量赋值是否存在问题或限制?或者我在这里遗漏了什么?
请注意,如果我稍微更改样式表并在条件之外声明变量,则会按我的预期分配一个数组。
sample2.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="/tasks/task">
<xsl:variable name="parentTask" select="replace(@parent,'#','')"/>
<!-- VARIABLE assignement outside a condition: value is an array -->
<xsl:variable name="depTasks" select="tokenize(replace(@deps,'#',''),'\s')"/>
<parent id="{@id}">
<xsl:for-each select="/tasks/task[@id=$depTasks]">
<dep>
<xsl:value-of select="@id"/>
</dep>
</xsl:for-each>
</parent>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
导致这种转变
<?xml version="1.0" encoding="UTF-8"?>
<parent id="id0"/>
<parent id="id1">
<dep>id0</dep>
<dep>id2</dep>
<dep>id3</dep>
</parent>
<parent id="id2"/>
<parent id="id3"/>
您根本没有在代码中使用任何数组。在
<xsl:variable name="depTasks">
<xsl:choose>
<xsl:when test="@deps">
<xsl:value-of select="tokenize(replace(@deps,'#',''),'\s')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$parentTask"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
您正在创建一个包含文本节点的结果树片段,该文本节点具有 tokenize
调用或 $parentTask
变量的字符串值。
在 <xsl:variable name="depTasks" select="tokenize(replace(@deps,'#',''),'\s')"/>
中,变量的值是 tokenize
调用的结果,它是一个字符串值序列。
如果对于前面的方法,虽然不推荐,但你想要一个字符串序列,你需要使用
<xsl:variable name="depTasks" as="xs:string*">
...
<xsl:sequence select="tokenize(...)"/>
...
</xsl:variable>
对于更复杂的部分,首选方法是 select="if (@deps) then tokenize(...) else $parentTask"
。
除 Martin Honnen 的回答外:
如果您使用的是 XSLT 3.0,请不要将您的样式表声明为 version="1.0"
。这样做会调用向后兼容的行为,这会显着改变您的结果。
例如,xsl:value
指令(您在多个地方使用了该指令)将仅输出所选序列的第一个节点的字符串值,而不是所有节点。
使用 xslt3 (Saxon JS) 且未绑定到特定的 XSLT 版本
鉴于此 sample.xml
<?xml version=”1.0″ encoding=”UTF-8″?>
<tasks>
<task id="id0"/>
<task id="id1" parent="#id0" deps="#id2 #id3 #id0"/>
<task id="id2" parent="#id0"/>
<task id="id3" parent="#id0"/>
</tasks>
和这个sample.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="/tasks/task">
<xsl:variable name="parentTask" select="replace(@parent,'#','')"/>
<xsl:variable name="depTasks">
<xsl:choose>
<xsl:when test="@deps">
<xsl:value-of select="tokenize(replace(@deps,'#',''),'\s')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$parentTask"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<parent id="{@id}">
<xsl:for-each select="/tasks/task[@id=$depTasks]">
<dep>
<xsl:value-of select="@id"/>
</dep>
</xsl:for-each>
</parent>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
我希望 $depTasks
变量包含一个数组(deps
属性中列出的所有 deps)或单个值(dep 列在 parent
属性中),并获得这样的转换:
<?xml version="1.0" encoding="UTF-8"?>
<parent id="id0"/>
<parent id="id1">
<dep>id2</dep>
<dep>id3</dep>
<dep>id0</dep>
</parent>
<parent id="id2">
<dep>id0</dep>
</parent>
<parent id="id3">
<dep>id0</dep>
</parent>
但是我得到了这个结果(似乎只分配了标记化的第一个元素)
<?xml version="1.0" encoding="UTF-8"?>
<parent id="id0"/>
<parent id="id1">
<dep>id2</dep>
<!-- MISSING DEPS -->
</parent>
<parent id="id2">
<dep>id0</dep>
</parent>
<parent id="id3">
<dep>id0</dep>
</parent>
内部条件变量赋值是否存在问题或限制?或者我在这里遗漏了什么?
请注意,如果我稍微更改样式表并在条件之外声明变量,则会按我的预期分配一个数组。
sample2.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:for-each select="/tasks/task">
<xsl:variable name="parentTask" select="replace(@parent,'#','')"/>
<!-- VARIABLE assignement outside a condition: value is an array -->
<xsl:variable name="depTasks" select="tokenize(replace(@deps,'#',''),'\s')"/>
<parent id="{@id}">
<xsl:for-each select="/tasks/task[@id=$depTasks]">
<dep>
<xsl:value-of select="@id"/>
</dep>
</xsl:for-each>
</parent>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
导致这种转变
<?xml version="1.0" encoding="UTF-8"?>
<parent id="id0"/>
<parent id="id1">
<dep>id0</dep>
<dep>id2</dep>
<dep>id3</dep>
</parent>
<parent id="id2"/>
<parent id="id3"/>
您根本没有在代码中使用任何数组。在
<xsl:variable name="depTasks">
<xsl:choose>
<xsl:when test="@deps">
<xsl:value-of select="tokenize(replace(@deps,'#',''),'\s')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$parentTask"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
您正在创建一个包含文本节点的结果树片段,该文本节点具有 tokenize
调用或 $parentTask
变量的字符串值。
在 <xsl:variable name="depTasks" select="tokenize(replace(@deps,'#',''),'\s')"/>
中,变量的值是 tokenize
调用的结果,它是一个字符串值序列。
如果对于前面的方法,虽然不推荐,但你想要一个字符串序列,你需要使用
<xsl:variable name="depTasks" as="xs:string*">
...
<xsl:sequence select="tokenize(...)"/>
...
</xsl:variable>
对于更复杂的部分,首选方法是 select="if (@deps) then tokenize(...) else $parentTask"
。
除 Martin Honnen 的回答外:
如果您使用的是 XSLT 3.0,请不要将您的样式表声明为 version="1.0"
。这样做会调用向后兼容的行为,这会显着改变您的结果。
例如,xsl:value
指令(您在多个地方使用了该指令)将仅输出所选序列的第一个节点的字符串值,而不是所有节点。