XSLT遍历现有数组创建新数组问题求助
XSLT 3.0 数组收集问题解决
问题根源
原代码无法正常工作的核心原因:
- XSLT采用不可变变量模型,
for-each内部定义的$myArray是局部变量,不会修改外部同名变量,导致外部的$myArray始终为空数组,后续遍历循环无法执行。 - 代码中
array:append($myArray, personName)存在变量引用错误,personName未加$符号,无法正确引用已定义的变量。 - 未使用给定的map数据源,而是硬编码了输入数组。
修正后的代码
以下是针对给定map数据源,正确收集人员名称到数组的XSLT代码:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:map="http://www.w3.org/2005/xpath-functions/map" xmlns:array="http://www.w3.org/2005/xpath-functions/array" version="3.0"> <xsl:output method="text"/> <xsl:strip-space elements="*" /> <xsl:template name="test" match="/"> <xsl:param name="data" select="map { 'persons': [ map {'name': 'John', 'age': 33, 'residence':'Permanent'}, map {'name': 'Peter', 'age': 36, 'residence':'Temporary'} ] }"/> <!-- 从map中获取persons数组,提取所有name字段生成新数组 --> <xsl:variable name="myArray" select="array:map(map:get($data, 'persons'), function($person) { map:get($person, 'name') })"/> <!-- 遍历输出新数组内容 --> <xsl:for-each select="1 to array:size($myArray)"> <xsl:text>Person name is : </xsl:text> <xsl:value-of select="array:get($myArray, .)"/> <xsl:text> </xsl:text> <!-- 换行 --> </xsl:for-each> </xsl:template> </xsl:stylesheet>
代码说明
- 数据源处理:通过
map:get($data, 'persons')从传入的map参数中获取人员数组。 - 数组转换:使用
array:map函数遍历人员数组的每个元素,提取name字段值,直接生成包含所有名称的新数组,这是XSLT 3.0中处理数组转换最简洁的函数式方式。 - 数组遍历输出:通过
1 to array:size($myArray)遍历新数组,逐个输出人员名称。
如果坚持使用手动循环的方式(不推荐,函数式方式更简洁高效),可以使用递归模板构建数组:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:map="http://www.w3.org/2005/xpath-functions/map" xmlns:array="http://www.w3.org/2005/xpath-functions/array" version="3.0"> <xsl:output method="text"/> <xsl:strip-space elements="*" /> <xsl:template name="test" match="/"> <xsl:param name="data" select="map { 'persons': [ map {'name': 'John', 'age': 33, 'residence':'Permanent'}, map {'name': 'Peter', 'age': 36, 'residence':'Temporary'} ] }"/> <xsl:variable name="personsArray" select="map:get($data, 'persons')"/> <!-- 调用递归模板构建名称数组 --> <xsl:variable name="myArray"> <xsl:call-template name="build-name-array"> <xsl:with-param name="inputArray" select="$personsArray"/> <xsl:with-param name="currentArray" select="array{}"/> </xsl:call-template> </xsl:variable> <!-- 遍历输出 --> <xsl:for-each select="1 to array:size($myArray)"> <xsl:text>Person name is : </xsl:text> <xsl:value-of select="array:get($myArray, .)"/> <xsl:text> </xsl:text> </xsl:for-each> </xsl:template> <!-- 递归模板:遍历输入数组,收集名称到新数组 --> <xsl:template name="build-name-array"> <xsl:param name="inputArray"/> <xsl:param name="currentArray"/> <xsl:if test="array:size($inputArray) > 0"> <!-- 获取第一个元素的name --> <xsl:variable name="firstName" select="map:get(array:get($inputArray, 1), 'name')"/> <!-- 追加到当前数组 --> <xsl:variable name="updatedArray" select="array:append($currentArray, $firstName)"/> <!-- 递归处理剩余元素 --> <xsl:call-template name="build-name-array"> <xsl:with-param name="inputArray" select="array:remove($inputArray, 1)"/> <xsl:with-param name="currentArray" select="$updatedArray"/> </xsl:call-template> </xsl:if> <!-- 递归结束时返回最终数组 --> <xsl:if test="array:size($inputArray) = 0"> <xsl:sequence select="$currentArray"/> </xsl:if> </xsl:template> </xsl:stylesheet>
内容的提问来源于stack exchange,提问作者technocrat
相关产品推荐
相关产品推荐

