XSLT 3.0 - 在 XSLT 3.0 xml-to-json() 中出现错误“重复键值”

Posted

技术标签:

【中文标题】XSLT 3.0 - 在 XSLT 3.0 xml-to-json() 中出现错误“重复键值”【英文标题】:XSLT 3.0 - Getting Error "duplicate key value" in XSLT 3.0 xml-to-json() 【发布时间】:2021-10-17 13:51:34 【问题描述】:

我正在尝试使用 XSLT 3.0 将给定的 json 数据从一种形式转换为另一种形式。我正在使用 XSLT 3.0 提供的 json-to-xml 和 xml-to-json 函数将数据从 .to json 转换为 xml。

我有以下 json 数据。


 "serviceCode":"ATOM",
 "action":"SCHEDULE",
"customerId":864,
"instance":"DWHPRD",
"serviceParameters":[
  
     "parameterName":"team",
     "parameterValue":"EBS"
  
],
"arguments":[
  
     "argumentKey":"rfc",
     "argumentValue":"3-BW9R3UA"
  ,
  
     "argumentKey":"sid",
     "argumentValue":"DWHPRD"
  ,
  
     "argumentKey":"schedule_at",
     "argumentValue":"2023-07-02 15:10:00"
  ,
  
     "argumentKey":"update_rfc",
     "argumentValue":false
  ,
  
     "argumentKey":"dynamic_args",
     "argumentValue":[
        
           "argumentKey":"task_name",
           "argumentValue":"Exa CPU Bursting Task"
        ,
        
           "argumentKey":"arg_name",
           "argumentValue":"$CPU Count",
           "parent":
              "argumentKey":"task_name",
              "argumentValue":"Exa CPU Bursting Task"
           
        ,
        
           "argumentKey":"arg_value",
           "argumentValue":"2",
           "parent":
              "argumentKey":"task_name",
              "argumentValue":"Exa CPU Bursting Task"
           
        ,
        
           "argumentKey":"task_name",
           "argumentValue":"Exa CPU Bursting DB Task"
        ,
        
           "argumentKey":"arg_name",
           "argumentValue":"$Target DB CPU Count",
           "parent":
              "argumentKey":"task_name",
              "argumentValue":"Exa CPU Bursting DB Task"
           
        ,
        
           "argumentKey":"arg_value",
           "argumentValue":"3",
           "parent":
              "argumentKey":"task_name",
              "argumentValue":"Exa CPU Bursting DB Task"
           
        
     ]
    
   ]
  

我正在尝试使用 XSLT 3.0 将其转换为以下形式


"rfc":"3-BW9R3UA",
"sid":"DWHPRD",
"job_id":972,
"schedule_at":"2023-07-02 15:10:00",
"update_rfc":false,
"dynamic_args":[
  
     "task_name":"Exa CPU Bursting Task",
     "arg_name":"$CPU Count",
     "arg_value":"2"
  ,
  
     "task_name":"Exa CPU Bursting DB Task",
     "arg_name":"$Target DB CPU Count",
     "arg_value":"3"
   
  ]

我想出了下面的 XSLT(不完整,因为我在 1 级遇到错误)

 <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
 version="3.0"
 xmlns="http://www.w3.org/2005/xpath-functions"
 xpath-default-namespace="http://www.w3.org/2005/xpath-functions"
 expand-text="yes">
 <xsl:param name="jsonText"/>

 <xsl:output method="text"/>

 <xsl:template name="init">
 <xsl:variable name="input-as-xml" select="json-to-xml($jsonText)"/>
 <xsl:variable name="transformed-xml">

 <map>
 <xsl:for-each select="$input-as-xml//array[@key='arguments']//map">
 <string key="string[@key='argumentKey']"> <xsl:value-of 
select="string[@key='argumentValue']"/></string>
 </xsl:for-each>
</map>
</xsl:variable>
 <xsl:value-of select="xml-to-json($transformed-xml)"/>
 </xsl:template>
</xsl:stylesheet>

任何人都可以帮助我如何获得所需的输出 json。

【问题讨论】:

【参考方案1】:

您似乎想跳过一些内容,但要对嵌套数组内容进行分组:

<?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"
  xmlns="http://www.w3.org/2005/xpath-functions"
  xpath-default-namespace="http://www.w3.org/2005/xpath-functions"
  exclude-result-prefixes="#all"
  expand-text="yes">
  
  <xsl:param name="json" as="xs:string" expand-text="no">
 "serviceCode":"ATOM",
 "action":"SCHEDULE",
"customerId":864,
"instance":"DWHPRD",
"serviceParameters":[
  
     "parameterName":"team",
     "parameterValue":"EBS"
  
],
"arguments":[
  
     "argumentKey":"rfc",
     "argumentValue":"3-BW9R3UA"
  ,
  
     "argumentKey":"sid",
     "argumentValue":"DWHPRD"
  ,
  
     "argumentKey":"schedule_at",
     "argumentValue":"2023-07-02 15:10:00"
  ,
  
     "argumentKey":"update_rfc",
     "argumentValue":false
  ,
  
     "argumentKey":"dynamic_args",
     "argumentValue":[
        
           "argumentKey":"task_name",
           "argumentValue":"Exa CPU Bursting Task"
        ,
        
           "argumentKey":"arg_name",
           "argumentValue":"$CPU Count",
           "parent":
              "argumentKey":"task_name",
              "argumentValue":"Exa CPU Bursting Task"
           
        ,
        
           "argumentKey":"arg_value",
           "argumentValue":"2",
           "parent":
              "argumentKey":"task_name",
              "argumentValue":"Exa CPU Bursting Task"
           
        ,
        
           "argumentKey":"task_name",
           "argumentValue":"Exa CPU Bursting DB Task"
        ,
        
           "argumentKey":"arg_name",
           "argumentValue":"$Target DB CPU Count",
           "parent":
              "argumentKey":"task_name",
              "argumentValue":"Exa CPU Bursting DB Task"
           
        ,
        
           "argumentKey":"arg_value",
           "argumentValue":"3",
           "parent":
              "argumentKey":"task_name",
              "argumentValue":"Exa CPU Bursting DB Task"
           
        
     ]
    
   ]
  </xsl:param>

  <xsl:output method="text"/>
  
  <xsl:mode on-no-match="shallow-skip"/>

  <xsl:template match="/" name="xsl:initial-template">
    <xsl:variable name="json-xml" select="json-to-xml($json)"/>
    <xsl:variable name="transformed-json-xml">
      <map>
        <xsl:apply-templates select="$json-xml//array[@key = 'arguments']/map"/>
      </map>
    </xsl:variable>
    <xsl:value-of select="xml-to-json($transformed-json-xml, map  'indent' : true() )"/>
  </xsl:template>
  
  <xsl:template match="map[string[@key = 'argumentKey'] and string[@key = 'argumentValue']]">
    <string key="string[@key = 'argumentKey']">string[@key = 'argumentValue']</string>
  </xsl:template>
  
  <xsl:template match="map[string[@key = 'argumentKey'] and string[@key = 'argumentValue']][string[@key = 'argumentValue'] castable as xs:double]">
    <number key="string[@key = 'argumentKey']">string[@key = 'argumentValue']</number>
  </xsl:template>
  
  <xsl:template match="map[string[@key = 'argumentKey'] and boolean[@key = 'argumentValue']]">
    <boolean key="string[@key = 'argumentKey']">boolean[@key = 'argumentValue']</boolean>
  </xsl:template>
  
  <xsl:template match="map[string[@key = 'argumentKey'] and array[@key = 'argumentValue']]">
    <array key="string[@key = 'argumentKey']">
      <xsl:for-each-group select="array/map" group-starting-with="map[not(map[@key = 'parent'])]">
        <map>
          <xsl:apply-templates select="current-group()"/>
        </map>
      </xsl:for-each-group>
    </array>
  </xsl:template>

</xsl:stylesheet>

我不明白"job_id":972 的来源以及输出中的数字何时应该是数字或字符串。

【讨论】:

感谢您的解决方案。它工作得很好。 job_id 来自将传递给 xslt 的 java 代码。

以上是关于XSLT 3.0 - 在 XSLT 3.0 xml-to-json() 中出现错误“重复键值”的主要内容,如果未能解决你的问题,请参考以下文章

Marklogic xml 转换中的 XSLT 3.0 支持

使用 XSLT 3.0 的 JSON 到 XML - 如何加载 JSON 源并调用 json-to-xml 函数?

xslt 3.0 json-to-xml 和 xml-to-json 转换

XSLT(2.0 或 3.0)方法将存储在 xml 中的每个逗号分隔值的整个 xml 复制到单独的 xml 文件中

如何判断我编写的 XSLT 3.0 是不是实际上是流式传输 XML?

如何在 Java 应用程序中使用 XSLT 3.0?