You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

XSLT实现XML转JSON:根节点缺失与单节点数组化问题解决

XSLT实现XML转JSON的针对性解决方案

当前在使用XSLT将XML转换为JSON时遇到两个问题:

  • 根节点notifications未出现在JSON输出中
  • 单个Notification节点无法在JSON中以数组形式呈现

要求仅允许硬编码notifications和Notification节点名称,其余节点无需硬编码。


输入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": "123",
        "sObject": {
          "@type": "sf:Opportunity",
          "Id": "ao123",
          "Amount": "60000.0",
          "CreatedDate": "2014-11-26T14:45:52.000Z",
          "IsClosed": "false"
        }
      }
    ]
  }
}

现有尝试的XSLT代码

<?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>

解决方案

针对需求修改后的XSLT代码如下:

<?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"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:sf="urn:sobject.enterprise.soap.sforce.com"
    xmlns:soap="http://soap.sforce.com/2005/09/outbound"
    exclude-result-prefixes="#all"
    xmlns="http://www.w3.org/2005/xpath-functions"
    expand-text="yes"
    version="3.0">

  <xsl:output method="text"/>

  <!-- 处理根节点,确保notifications作为最外层键 -->
  <xsl:template match="/">
    <xsl:variable name="json-xml">
      <map>
        <xsl:apply-templates select="/soap:notifications" mode="root"/>
      </map>
    </xsl:variable>
    <xsl:value-of select="xml-to-json($json-xml, map { 'indent' : true() })"/>
  </xsl:template>

  <!-- 根节点notifications的处理 -->
  <xsl:template match="soap:notifications" mode="root">
    <map key="notifications">
      <xsl:apply-templates select="*"/>
    </map>
  </xsl:template>

  <!-- 强制Notification节点转为数组,无论数量多少 -->
  <xsl:template match="soap:Notification">
    <array key="Notification">
      <xsl:for-each select=".">
        <map>
          <xsl:apply-templates select="*"/>
        </map>
      </xsl:for-each>
    </array>
  </xsl:template>

  <!-- 处理带xsi:nil属性的节点 -->
  <xsl:template match="*[@xsi:nil='true']">
    <map key="{local-name()}">
      <string key="@nil">true</string>
    </map>
  </xsl:template>

  <!-- 处理sObject节点,提取xsi:type属性 -->
  <xsl:template match="soap:sObject">
    <map key="sObject">
      <string key="@type">{@xsi:type}</string>
      <xsl:apply-templates select="sf:*"/>
    </map>
  </xsl:template>

  <!-- 处理sf前缀的子节点,去掉前缀保留本地名称 -->
  <xsl:template match="sf:*">
    <string key="{local-name()}">{.}</string>
  </xsl:template>

  <!-- 处理普通文本节点 -->
  <xsl:template match="*[not(*)]">
    <string key="{local-name()}">{.}</string>
  </xsl:template>

  <!-- 处理包含子节点的普通节点 -->
  <xsl:template match="*[*]">
    <map key="{local-name()}">
      <xsl:apply-templates select="*"/>
    </map>
  </xsl:template>

</xsl:stylesheet>

关键修改说明

  1. 根节点处理:新增根节点模板,将notifications作为最外层JSON对象的键,解决根节点缺失问题。
  2. Notification数组强制转换:针对Notification节点单独编写模板,无论数量多少都包装为数组,满足单个节点也以数组呈现的需求。
  3. 属性处理:
    • 识别xsi:nil属性,生成带@nil键的对象
    • 提取sObject的xsi:type属性,转为@type键
  4. 命名空间处理:声明输入XML中的所有命名空间,确保节点正确匹配,同时自动去除sObject子节点的sf:前缀。

内容的提问来源于stack exchange,提问作者techresearch

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 09:50:31