【问题标题】:Use XSLT to extract information from JSON and output format as JSON使用 XSLT 从 JSON 中提取信息并将格式输出为 JSON
【发布时间】:2019-06-05 05:25:10
【问题描述】:

在一些帮助下,我编写了以下脚本,该脚本将 JSON 文件作为参数并将其输出为 XML。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">
    <xsl:param name="json" as="xs:string">
    [
       {
          "ID":"DWL",
          "profiles":[
             {
                "firstName":"Contact",
                "lastName":"Sample",
                "emailAddresses":[
                   {
                      "emailAddress":"inactive@mailinator.com"
                   }
                ]
             }
          ]
       },
       {
          "ID":"DWLK",
          "profiles":[
             {
                "firstName":"Contact",
                "lastName":"Sample",
                "emailAddresses":[
                   {
                      "emailAddress":"sampltest@mailinator.com",
                      "primary":true
                   }
                ]
             }
          ]
       }
    ] 
  </xsl:param>
    <xsl:template match="/" name="xsl:initial-template">
        <xsl:sequence select="json-to-xml($json)"/>
    </xsl:template>
</xsl:stylesheet>

我需要修改脚本以提取 ID、profiles.FirstNameprofiles.emailAddresses,并添加一个额外的静态字段 origin。最终输出应该如下:

[  
   {  
      "ID":"DWL",
      "origin":"static",
      "profiles":[  
         {  
            "firstName":"Contact",
            "emailAddresses":[  
               {  
                  "emailAddress":"sample@mailinator.com"
               }
            ]
         }
      ]
   },
   {  
      "ID":"DWLK",
      "origin":"static",
      "profiles":[  
         {  
            "firstName":"Contact",
            "emailAddresses":[  
               {  
                  "emailAddress":"sampltest@mailinator.com",
                  "primary":true
               }
            ]
         }
      ]
   }
]

【问题讨论】:

    标签: json xml xslt xquery


    【解决方案1】:

    基本上有两种使用 XSLT 3.0 处理 JSON 的方法:您可以将其作为映射和数组处理,或者您可以将其转换为 XML(然后再转换回来)。在 XML 布拉格 2016 的一篇论文(可在 http://www.saxonica.com/papers/xmlprague-2016mhk.pdf 获取)中,我探讨了比较这两种技术的几个用例,我通常发现转换为 XML 并返回更容易,主要原因是 XML 结构的模式匹配机制是比映射和数组的模式匹配灵活得多(这反过来是因为 XML 树允许您向上导航以检查上下文,而映射和数组则不能)。

    使用这种方法,您可以转换为 XML,然后对 XML 进行标准转换,如下所示:

    <xsl:mode name="add-origin" on-no-match="shallow-copy"/>
    
    <xsl:template match="fn:map[*[@key='ID']]" mode="add-origin">
      <xsl:copy>
        <xsl:copy-of select="@*"/>  
        <fn:string key="origin">static</fn:string>
        <xsl:copy-of select="node()"/>
      </xsl:copy>
    </xsl:template>
    
    <xsl:template match="/" name="xsl:initial-template">
      <xsl:variable name="converted">  
        <xsl:apply-templates select="json-to-xml($json)" mode="add-origin"/>
      </xsl:variable>
      <xsl:sequence select="xml-to-json($converted)"/>
    </xsl:template>
    

    您提到从输入中“提取”一些信息;我不确定我是否理解这个要求,但是从 parse-json() 提供的 maps-and-arrays 表示中可以很容易地从 JSON 中提取信息,使用查找运算符“?”。例如,您可以使用 $json?*?ID 获取所有 ID 值,或者您可以使用 $json?*[?ID='JWL']?profiles?1?firstName 获取 ID 为 JWL 的人的名字。

    【讨论】:

    【解决方案2】:

    &lt;xsl:sequence select="json-to-xml($json)"/&gt; 的第一次转换显示在 https://xsltfiddle.liberty-development.net/bnnZWD/5 并给出 XML

    <array xmlns="http://www.w3.org/2005/xpath-functions">
       <map>
          <string key="ID">DWL</string>
          <array key="profiles">
             <map>
                <string key="firstName">Contact</string>
                <string key="lastName">Sample</string>
                <array key="emailAddresses">
                   <map>
                      <string key="emailAddress">inactive@mailinator.com</string>
                   </map>
                </array>
             </map>
          </array>
       </map>
       <map>
          <string key="ID">DWLK</string>
          <array key="profiles">
             <map>
                <string key="firstName">Contact</string>
                <string key="lastName">Sample</string>
                <array key="emailAddresses">
                   <map>
                      <string key="emailAddress">sampltest@mailinator.com</string>
                      <boolean key="primary">true</boolean>
                   </map>
                </array>
             </map>
          </array>
       </map>
    </array>
    

    如果您将其用作中间结果并通过一些模板推送它 (https://xsltfiddle.liberty-development.net/bnnZWD/6)

      <xsl:template match="/" name="xsl:initial-template">
          <xsl:variable name="json-xml" select="json-to-xml($json)"/>
          <xsl:apply-templates select="$json-xml/node()"/>
      </xsl:template>
    
      <xsl:mode on-no-match="shallow-copy"/>
    
      <xsl:template match="string[@key = 'ID']">
          <xsl:next-match/>
          <string key="origin">static</string>
      </xsl:template>
    
      <xsl:template match="string[@key = 'lastName']"/>
    

    为了你想要的改变:

    <array xmlns="http://www.w3.org/2005/xpath-functions">
       <map>
          <string key="ID">DWL</string>
          <string key="origin">static</string>
          <array key="profiles">
             <map>
                <string key="firstName">Contact</string>
                <array key="emailAddresses">
                   <map>
                      <string key="emailAddress">inactive@mailinator.com</string>
                   </map>
                </array>
             </map>
          </array>
       </map>
       <map>
          <string key="ID">DWLK</string>
          <string key="origin">static</string>
          <array key="profiles">
             <map>
                <string key="firstName">Contact</string>
                <array key="emailAddresses">
                   <map>
                      <string key="emailAddress">sampltest@mailinator.com</string>
                      <boolean key="primary">true</boolean>
                   </map>
                </array>
             </map>
          </array>
       </map>
    </array>
    

    然后您可以使用 xml-to-json 将转换后的 XML 转换回 JSON : (https://xsltfiddle.liberty-development.net/bnnZWD/7)

      <xsl:output method="text"/>
    
      <xsl:template match="/" name="xsl:initial-template">
          <xsl:variable name="json-xml" select="json-to-xml($json)"/>
          <xsl:variable name="transformed-json-xml">
                <xsl:apply-templates select="$json-xml/node()"/>
          </xsl:variable>
          <xsl:value-of select="xml-to-json($transformed-json-xml, map { 'indent' : true() })"/>
      </xsl:template>
    
      <xsl:mode on-no-match="shallow-copy"/>
    
      <xsl:template match="string[@key = 'ID']">
          <xsl:next-match/>
          <string key="origin">static</string>
      </xsl:template>
    
      <xsl:template match="string[@key = 'lastName']"/>
    

    并使用 Saxon 9.8 获得输出

      [ 
        { "ID" : "DWL",
          "origin" : "static",
          "profiles" : 
          [ 
            { "firstName" : "Contact",
              "emailAddresses" : 
              [ 
                { "emailAddress" : "inactive@mailinator.com" } ] } ] },
    
        { "ID" : "DWLK",
          "origin" : "static",
          "profiles" : 
          [ 
            { "firstName" : "Contact",
              "emailAddresses" : 
              [ 
                { "emailAddress" : "sampltest@mailinator.com",
                  "primary" : true } ] } ] } ]
    

    清理中间步骤,代码可以缩短为

      <xsl:output method="text"/>
    
      <xsl:template match="/" name="xsl:initial-template">
          <xsl:variable name="transformed-json-xml">
                <xsl:apply-templates select="json-to-xml($json)/node()"/>
          </xsl:variable>
          <xsl:value-of select="xml-to-json($transformed-json-xml, map { 'indent' : true() })"/>
      </xsl:template>
    
      <xsl:mode on-no-match="shallow-copy"/>
    
      <xsl:template match="string[@key = 'ID']">
          <xsl:next-match/>
          <string key="origin">static</string>
      </xsl:template>
    
      <xsl:template match="string[@key = 'lastName']"/>
    

    https://xsltfiddle.liberty-development.net/bnnZWD/9

    当然,您可以使用 unparsed-text 从 JSON 文件加载,而不是使用带有 JSON 字符串内容的参数,例如&lt;xsl:param name="json" select="unparsed-text('file.json')"/&gt;.

    【讨论】:

    • 这个解释太好了,非常感谢你的努力!
    猜你喜欢
    • 2012-08-24
    • 1970-01-01
    • 2018-11-21
    • 2021-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多