XSLT将XML转换为JSON,JSON可能有多个重复节点

ubof19bj  于 2023-01-03  发布在  其他
关注(0)|答案(1)|浏览(133)

我想用XSLT把XML转换成JSON,但是我遇到了一些问题。

    • 输入XML**
<notifications xmlns="http://soap.sforce.com/2005/09/outbound">
  <OrganizationId>123</OrganizationId>
  <ActionId>123</ActionId>
  <SessionId xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
  <EnterpriseUrl>qwe</EnterpriseUrl>
  <PartnerUrl>qwe</PartnerUrl>
  <Notification>
    <Id>123</Id>
    <sObject xsi:type="sf:Opportunity" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:sf="urn:sobject.enterprise.soap.sforce.com">
      <sf:Id>ao123</sf:Id>
      <sf:Amount>60000.0</sf:Amount>
      <sf:CreatedDate>2014-11-26T14:45:52.000Z</sf:CreatedDate>
      <sf:IsClosed>false</sf:IsClosed>
    </sObject>
  </Notification>
</notifications>
    • 预期输出JSON**
{
  "notifications": {
    "OrganizationId": "123",
    "ActionId": "123",
    "SessionId": {
      "@nil": "true"
    },
    "EnterpriseUrl": "qwe",
    "PartnerUrl": "qwe",
    "Notification": [
      {
        "Id": "ao123",
        "sObject": {
          "@type": "sf:Opportunity",
          "Id": "ao123",
          "Amount": "60000.0",
          "CreatedDate": "2014-11-26T14:45:52.000Z",
          "IsClosed": "false"
        }
      }
    ]
  }
}

从这个answer我得到了XSLT,我已经试过了。这是我试过的XSLT代码。Fiddle link

<?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"
    xmlns="http://www.w3.org/2005/xpath-functions"
    expand-text="yes"
    version="3.0">

  <xsl:output method="text"/>

  <xsl:template match="/">
      <xsl:variable name="json-xml">
          <xsl:apply-templates/>
      </xsl:variable>
      <xsl:value-of select="xml-to-json($json-xml, map { 'indent' : true() })"/>
  </xsl:template>
  
  <xsl:template match="*[not(*)]">
    <string key="{local-name()}">{.}</string>
  </xsl:template>
  

  
  <xsl:template match="*[*]">
    <xsl:param name="key" as="xs:boolean" select="false()"/>
    <map>
      <xsl:if test="$key">
        <xsl:attribute name="key" select="local-name()"/>
      </xsl:if>
      <xsl:for-each-group select="*" group-by="node-name()">
          <xsl:choose>
              <xsl:when test="current-group()[2]">
                  <array key="{local-name()}">
                      <xsl:apply-templates select="current-group()">
                        <xsl:with-param name="key" select="false()"/>
                      </xsl:apply-templates>
                  </array>
              </xsl:when>
              <xsl:otherwise>
                  <xsl:apply-templates select="current-group()">
                    <xsl:with-param name="key" select="true()"/>
                  </xsl:apply-templates>
              </xsl:otherwise>
          </xsl:choose>
      </xsl:for-each-group>
    </map>
  </xsl:template>

</xsl:stylesheet>

以下是我面临的几个问题

  • json输出中缺少notifications节点,它是xml中的根节点。
  • Notification应该是一个json数组,即使我收到一个XML格式的项

请注意,我不想在XSLT代码中硬编码notificationsNotification以外的节点名称,因为我可能会在节点Notification下收到不同的节点。
我正在寻找可以处理我的需求的XSLT

wqnecbli

wqnecbli1#

当然,通过修改链接到的内容,可以将一些需求(外部Map/JSON对象,始终使Notification成为数组)插入XSLT代码中(请确保下次在问题中也显示XSLT):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    xmlns="http://www.w3.org/2005/xpath-functions"
    expand-text="yes"
    version="3.0">

  <xsl:output method="text"/>

  <xsl:template match="/">
      <xsl:variable name="json-xml">
        <map>
          <xsl:apply-templates/>
        </map>
      </xsl:variable>
      <xsl:value-of select="xml-to-json($json-xml, map { 'indent' : true() })"/>
  </xsl:template>
  
  <xsl:template match="*[not(*)]">
    <string key="{local-name()}">{.}</string>
  </xsl:template>
  
  <xsl:template match="*[*]">
    <xsl:param name="key" as="xs:boolean" select="true()"/>
    <map>
      <xsl:if test="$key">
        <xsl:attribute name="key" select="local-name()"/>
      </xsl:if>
      <xsl:for-each-group select="*" group-by="node-name()">
          <xsl:choose>
              <xsl:when test="current-group()[2] or current-grouping-key() = QName('http://soap.sforce.com/2005/09/outbound', 'Notification')">
                  <array key="{local-name()}">
                      <xsl:apply-templates select="current-group()">
                        <xsl:with-param name="key" select="false()"/>
                      </xsl:apply-templates>
                  </array>
              </xsl:when>
              <xsl:otherwise>
                  <xsl:apply-templates select="current-group()">
                    <xsl:with-param name="key" select="true()"/>
                  </xsl:apply-templates>
              </xsl:otherwise>
          </xsl:choose>
      </xsl:for-each-group>
    </map>
  </xsl:template>

</xsl:stylesheet>

我认为您从另一个问题/答案中获得的代码不是用XML编写的,其中的元素没有考虑到属性;我试着在下面用

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    xmlns="http://www.w3.org/2005/xpath-functions"
    expand-text="yes"
    version="3.0">

  <xsl:output method="text"/>

  <xsl:template match="/">
      <xsl:variable name="json-xml">
        <map>
          <xsl:apply-templates/>
        </map>
      </xsl:variable>
      <xsl:value-of select="xml-to-json($json-xml, map { 'indent' : true() })"/>
  </xsl:template>
  
  <xsl:template match="*[not(*)]">
    <string key="{local-name()}">{.}</string>
  </xsl:template>
  
  <xsl:template match="@*">
    <string key="@{local-name()}">{.}</string>
  </xsl:template>
  
  <xsl:template match="*[* or @*]">
    <xsl:param name="key" as="xs:boolean" select="true()"/>
    <map>
      <xsl:if test="$key">
        <xsl:attribute name="key" select="local-name()"/>
      </xsl:if>
      <xsl:apply-templates select="@*"/>
      <xsl:for-each-group select="*" group-by="node-name()">
          <xsl:choose>
              <xsl:when test="current-group()[2] or current-grouping-key() = QName('http://soap.sforce.com/2005/09/outbound', 'Notification')">
                  <array key="{local-name()}">
                      <xsl:apply-templates select="current-group()">
                        <xsl:with-param name="key" select="false()"/>
                      </xsl:apply-templates>
                  </array>
              </xsl:when>
              <xsl:otherwise>
                  <xsl:apply-templates select="current-group()">
                    <xsl:with-param name="key" select="true()"/>
                  </xsl:apply-templates>
              </xsl:otherwise>
          </xsl:choose>
      </xsl:for-each-group>
    </map>
  </xsl:template>

</xsl:stylesheet>

这似乎给予了所需的属性,如示例的JSON对象/Map的@name属性;我不能保证它会工作一般。

相关问题