是否可以使用 Saxon-JS 将 JSON 文件转换为不同的 JSON 文件而不通过 XML 传输?
Is it possible to use Saxon-JS to convert a JSON file to a different JSON file without transiting through XML?
我正在研究解决从根本上完全基于 JSON 的转换问题,虽然基于命令式代码的解决方案是可能的,但使用像 XSLT 这样的成熟技术并利用其许多功能,而不是尝试从头开始内部所有的东西。我对 XSLT 相当缺乏经验,但我很乐意为此努力提供一个学习它的理由。
我读到 JSON 包含在 XSLT 3.0 和 XPath 3.1 规范中,并且 Saxon-JS 支持这些,而且 Saxon-JS 有一个 node.js 版本。这让我很感兴趣,但我没有找到太多关于如何将 JSON 转换为其他 JSON 的教程;相反,重点似乎是将 JSON 转换为 XML.
这个问题有点宽泛,所以我很乐意知道这是否可行,以及从哪里开始学习,但 Whosebug 喜欢示例。考虑到这一点,将这些 JSON 文档中的第一个转换为第二个的样式表会是什么样子?
来源:
{
"contents" : [
{
"id": 1,
"color": "blue",
"hexcode": "#0000FF"
},
{
"id": 2,
"color": "green",
"hexcode": "#00FF00"
},
{
"id": 3,
"color": "red",
"hexcode": "#FF0000"
}
]
}
输出:
[
{
"id": "contents1",
"color": {
"name": "blue",
"hexcode": "#0000FF"
}
},
{
"id": "contents2",
"color": {
"name": "green",
"hexcode": "#00FF00"
}
},
{
"id": "contents3",
"color": {
"name": "red",
"hexcode": "#FF0000"
}
}
]
如果你使用
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all">
<xsl:output method="json" indent="yes"/>
<xsl:template match=".[. instance of map(*)]">
<xsl:sequence
select="array{ ?contents?*!map { 'id' : 'contents' || ?id, 'color' : map { 'name' : ?color, 'hexcode' : ?hexcode } } }"/>
</xsl:template>
</xsl:stylesheet>
例如at the Saxon-JS fiddle 然后 JSON 被解析为 XPath 3.1 映射并构造一个 XPath 3.1 数组,该数组被序列化回 JSON.
对于 Node.js xslt3
命令行工具,您可以使用 -json:my-input.json
我认为您可以使用 s:my-source.xml
来转换 XML。我认为 -json
选项仅在 Saxon-JS 2.3 中,因此请确保使用最新版本。
对于仅使用 JSON 的 maps/arrays 的 XDM 表示而不是使用 XML 表示的更一般的处理和优缺点的辩论json-to-xml
参见 https://www.saxonica.com/papers/xmlprague-2016mhk.pdf, https://dev.saxonica.com/blog/mike/2017/11/transforming-json.html, https://www.youtube.com/watch?v=hGehtNUrg60。
有关查询 XPath 3.1 映射和数组的语法,请参阅 https://www.altova.com/training/xpath3/xpath-31 或 XPath 3.1 规范或有关 XPath 3.1 的任何其他教程 arrays/maps。
是的,正如马丁所展示的那样,这是可能的。然而,在 JSON-to-JSON 转换工作像 XML-to-XML 一样顺利之前,XSLT 还有一点路要走。我经验的主要限制是:
(a) 为 xsl:template
编写匹配 JSON 树
中的“节点”的匹配模式并不容易
(b) 因为 JSON 没有父轴或祖先轴,JSON 树中特定“节点”的处理无法访问它出现的上下文,这意味着有必要使用模板参数向下传递该上下文(隧道参数对此非常有用。)
在您的示例中,输入数据是完全平坦的,因此不会出现这些问题。
我正在研究解决从根本上完全基于 JSON 的转换问题,虽然基于命令式代码的解决方案是可能的,但使用像 XSLT 这样的成熟技术并利用其许多功能,而不是尝试从头开始内部所有的东西。我对 XSLT 相当缺乏经验,但我很乐意为此努力提供一个学习它的理由。
我读到 JSON 包含在 XSLT 3.0 和 XPath 3.1 规范中,并且 Saxon-JS 支持这些,而且 Saxon-JS 有一个 node.js 版本。这让我很感兴趣,但我没有找到太多关于如何将 JSON 转换为其他 JSON 的教程;相反,重点似乎是将 JSON 转换为 XML.
这个问题有点宽泛,所以我很乐意知道这是否可行,以及从哪里开始学习,但 Whosebug 喜欢示例。考虑到这一点,将这些 JSON 文档中的第一个转换为第二个的样式表会是什么样子?
来源:
{
"contents" : [
{
"id": 1,
"color": "blue",
"hexcode": "#0000FF"
},
{
"id": 2,
"color": "green",
"hexcode": "#00FF00"
},
{
"id": 3,
"color": "red",
"hexcode": "#FF0000"
}
]
}
输出:
[
{
"id": "contents1",
"color": {
"name": "blue",
"hexcode": "#0000FF"
}
},
{
"id": "contents2",
"color": {
"name": "green",
"hexcode": "#00FF00"
}
},
{
"id": "contents3",
"color": {
"name": "red",
"hexcode": "#FF0000"
}
}
]
如果你使用
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all">
<xsl:output method="json" indent="yes"/>
<xsl:template match=".[. instance of map(*)]">
<xsl:sequence
select="array{ ?contents?*!map { 'id' : 'contents' || ?id, 'color' : map { 'name' : ?color, 'hexcode' : ?hexcode } } }"/>
</xsl:template>
</xsl:stylesheet>
例如at the Saxon-JS fiddle 然后 JSON 被解析为 XPath 3.1 映射并构造一个 XPath 3.1 数组,该数组被序列化回 JSON.
对于 Node.js xslt3
命令行工具,您可以使用 -json:my-input.json
我认为您可以使用 s:my-source.xml
来转换 XML。我认为 -json
选项仅在 Saxon-JS 2.3 中,因此请确保使用最新版本。
对于仅使用 JSON 的 maps/arrays 的 XDM 表示而不是使用 XML 表示的更一般的处理和优缺点的辩论json-to-xml
参见 https://www.saxonica.com/papers/xmlprague-2016mhk.pdf, https://dev.saxonica.com/blog/mike/2017/11/transforming-json.html, https://www.youtube.com/watch?v=hGehtNUrg60。
有关查询 XPath 3.1 映射和数组的语法,请参阅 https://www.altova.com/training/xpath3/xpath-31 或 XPath 3.1 规范或有关 XPath 3.1 的任何其他教程 arrays/maps。
是的,正如马丁所展示的那样,这是可能的。然而,在 JSON-to-JSON 转换工作像 XML-to-XML 一样顺利之前,XSLT 还有一点路要走。我经验的主要限制是:
(a) 为 xsl:template
编写匹配 JSON 树
(b) 因为 JSON 没有父轴或祖先轴,JSON 树中特定“节点”的处理无法访问它出现的上下文,这意味着有必要使用模板参数向下传递该上下文(隧道参数对此非常有用。)
在您的示例中,输入数据是完全平坦的,因此不会出现这些问题。