如何在XSLT中迭代JSON数组并生成期望的JSON输出
XSLT处理JSON:拆分书籍条目并关联对应作者
输入JSON
{ "publishers": [ { "sellers": { "books": [ { "test": { "count": 1 }, "Name": "C", "Type": "String" }, { "test": { "count": 2 }, "Name": "C++", "Type": "String" } ], "Author": "Michel" } }, { "sellers": { "books": [ { "test": { "count": 3 }, "Name": "Python", "Type": "String" }, { "test": { "count": 4 }, "Name": "Java", "Type": "String" } ], "Author": "Robert" } } ] }
原XSLT样式表
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="4.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="#all"> <xsl:output method="json" indent="yes"/> <xsl:template match="." name="xsl:initial-template"> <xsl:sequence select="array { ?publishers?* ! map { 'resourceType' : 'Asset', 'indentifier' : map {'name' : array{?sellers?books?*?Name}}, 'author' : map{'name' : ?sellers?Author} } }"/> </xsl:template> </xsl:stylesheet>
当前输出
[ { "resourceType": "Asset", "author": { "name":"Michel" }, "indentifier": { "name":[ "C", "C++" ] } }, { "resourceType": "Asset", "author": { "name":"Robert" }, "indentifier": { "name":[ "Python", "Java" ] } } ]
期望输出
[ { "resourceType": "Asset", "author": { "name":"Michel" }, "indentifier": { "name":"C" } }, { "resourceType": "Asset", "author": { "name":"Michel" }, "indentifier": { "name":"C++" } }, { "resourceType": "Asset", "author": { "name":"Robert" }, "indentifier": { "name":"Python" } }, { "resourceType": "Asset", "author": { "name":"Robert" }, "indentifier": { "name":"Java" } } ]
问题分析
原代码逻辑是遍历每个publisher并生成单个Asset对象,将该publisher下所有书籍名称打包为数组。但需求是每本书对应一个独立的Asset对象,同时关联所属作者信息。之前尝试用for-each构造报错,是因为XPath不支持XQuery的节点构造语法,需改用XPath的映射运算符!实现嵌套遍历。
修正后的XSLT代码
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="4.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="#all"> <xsl:output method="json" indent="yes"/> <xsl:template match="." name="xsl:initial-template"> <xsl:sequence select="array { ?publishers?* ! ?sellers ! let $author := ?Author return ?books?* ! map { 'resourceType' : 'Asset', 'indentifier' : map {'name' : ?Name}, 'author' : map{'name' : $author} } }"/> </xsl:template> </xsl:stylesheet>
代码解释
嵌套遍历逻辑:
- 先遍历所有
publisher:?publishers?* - 进入每个
publisher的sellers节点:! ?sellers - 用
let $author := ?Author保存当前sellers下的作者信息,供后续每本书复用 - 遍历当前
sellers下的所有books:! ?books?* - 为每本书生成独立的
Asset对象,直接引用当前书籍的Name和预先保存的$author值
- 先遍历所有
取消数组打包:
原代码用array{?sellers?books?*?Name}将多本书名打包为数组,现在直接取单本书的?Name,确保每个Asset只对应一个书名。
内容的提问来源于stack exchange,提问作者Sujit Kumar
相关产品推荐
相关产品推荐

