使用 XSLT 分析未包装的 json

Using XSLT to parse non-wrapped json

提问人:ssdev 提问时间:10/21/2023 更新时间:10/21/2023 访问量:99

问:

在我见过的所有将 json 转换为 xml 的 xslt 示例中,json 在使用 json-to-xml() 函数进行处理之前总是包装在 xml 标记中。我很好奇是否可以在不包装 json 的情况下进行转换。我一直在玩这个 xslt 小提琴无济于事,但是如果我把它包装起来,然后将输入类型更改为 xml,它就可以了。有没有人对如何让小提琴中的 xslt 与裸 json 一起工作有任何指导?<data></data>

<?xml version="1.0" encoding="utf-8"?>
<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:template match="/">
      <xsl:copy-of select="json-to-xml(.)"/>
  </xsl:template>
  
</xsl:stylesheet>
xml xpath xslt

评论


答:

4赞 Michael Kay 10/21/2023 #1

我不知道 Fiddle 是如何调用 Saxon 的,但我怀疑当您选择输入类型作为 JSON 时,它实际上会解析 JSON 并提供映射和数组的结果结构作为初始上下文项。不幸的是,json-to-xml() 函数需要未解析的词法 JSON 作为输入,因此我唯一可以做到这一点的方法是重新序列化 JSON,如下所示:

<xsl:template match=".">
      <xsl:copy-of select="serialize(., 
         map{'method':'json'}) => json-to-xml()"/>
</xsl:template>

请注意 而不是 ,因为 “/” 将仅匹配 XML 文档的根,而 “.” 将匹配任何内容。match="."match="/"

如果不受 Fiddle 实现方式的限制,则可以将 JSON 内容作为字符串或文件的 URI 提供给样式表,可以使用 .unparsed-text()

评论

0赞 ssdev 10/21/2023
谢谢迈克尔,效果很好!我一直在使用小提琴来试验 json-to-xml,但我将在节点应用程序中使用 SaxonJs。我是否理解当我在代码中使用它时,我可以只使用?当我尝试这样做时,我收到一个错误“函数 unparsed-text() 的参数错误 arity 0”<xsl:copy-of select="json-to-xml(unparsed-text())"/>
0赞 Martin Honnen 10/21/2023
@ssdev,您是否使用命名模板启动 SaxonJS XSLT 样式表并将 JSON 文件名作为参数传入?然后将 file name 参数用于 .xsl:initial-templateunparsed-text($fileName)
0赞 ssdev 10/23/2023
@MartinHonnen 这是一个代码沙箱,我正在尝试解析 Saxon 中的 json。我已经注释了一些东西,因为不同的东西不断失败。codesandbox.io/p/sandbox/......我尝试遵循 saxonica.com/saxon-js/documentation2/index.html#!api/transform/...来传递参数,但感觉我误解了文档。
0赞 Martin Honnen 10/23/2023
@ssdev,我不确定目前有一种可行的方法可以让您的 JavaScript 或 Typescript 代码即时编译 XSLT 到 SEF,因为您似乎正在尝试,让我们看看 Michael Kay 或 Saxonica 的其他人是否认为 SaxonJS 2 支持它,我认为您可能需要等待 SaxonJS 3 得到支持。其他问题只是您将JavaScript或Typescript对象作为映射传入,但是由于我不明白的原因,请尝试使用它。无论如何,对象中的JavaScript数组(值)都会转换为XDM序列。unparsed-textcontent
1赞 Martin Honnen 10/23/2023
我试图输出一些转换为 XML 的对象是 codesandbox.io/p/sandbox/...。非常确定您不想将数组包装在数组中,但我不确定是否有另一种方法,使用 JSON 序列化并使用 XSLT/XPath 可能更安全。json-to-xml($jsonString)
2赞 Martin Honnen 10/21/2023 #2

如果您选择输入类型JSON,则小提琴确实会将输入编辑器中的JSON解析为XPath 3.1 XDM映射或数组。所以我想说它适用于原始 JSON,在 XSLT 3/XPath 3.1 使用的表示中。但是,您的XSLT必须考虑到这一点,尝试匹配XML文档节点,它永远不会匹配表示JSON的XDM映射或数组;您可以使用它来匹配任何项目,因此标识“原始”JSON 到 JSON 将在这个小提琴上,例如parse-jsonmatch="/"match="."

<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=".">
    <xsl:sequence select="."/>
  </xsl:template>
  
</xsl:stylesheet>

从“原始”JSON 到 JSON 的转换,递增 id 是在这个小提琴上,例如

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="3.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:map="http://www.w3.org/2005/xpath-functions/map"
  exclude-result-prefixes="#all">
  
  <xsl:output method="json" indent="yes"/>
  
  <xsl:template match=".">
      <xsl:sequence select="map:put(., 'contents', array { ?contents?* ! map:put(., 'id', ?id + 1) })"/>
  </xsl:template>
  
</xsl:stylesheet>

至于应用的意图,Michael已经解释过,由于该函数不适用于JSON的XDM表示形式,如地图或数组,而是适用于JSON的字符串输入,因此您需要序列化为JSON,然后应用,如接受的答案所示。json-to-xmljson-to-xml

我的小提琴和 SaxonJS 都没有选择直接使用文本文件的字符串内容作为上下文项,但是 BaseX 小提琴可以做到这一点,因此,使用正确的上下文类型文本,您可以使用.json-to-xml(.)

我还更新了 XSLT 3、SaxonJS 2 驱动的小提琴以允许纯文本输入,因此如果您使用 JSON 输入数据但将其视为纯文本,就像在这个小提琴中一样,您确实可以使用.json-to-xml(.)