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

Azure APIM XML转JSON单元素未返回JSON数组解决方案

问题描述

调用返回XML格式响应的WCF服务时,在Azure APIM中配置如下策略实现XML到JSON的格式转换:

<xml-to-json kind="direct" apply="always" consider-accept-header="false" />

当Titles节点下包含多个Title子元素时转换逻辑正常,但当单个Titles节点下仅存在1个Title元素时,转换结果不符合预期。
测试用原始XML结构如下:

<TitlesResponse>
    <Titles>
        <Title>
            <Name>BookTitle-1</Name>
            <Author>BookTitle-2</Author>
        </Title>
        <Title>
            <Name>BookTitle-1</Name>
            <Author>BookTitle-2</Author>
        </Title>
    </Titles>
    <Titles>
        <Title>
            <Name>BookTitle-1</Name>
        </Title>
    </Titles>
</TitlesResponse>

默认策略转换输出的JSON如下,单Title场景下该字段返回对象类型,客户端要求Title字段始终返回数组类型:

{
  "TitlesResponse": {
    "Titles": [
      {
        "Title": [
          {
            "Name": "BookTitle-1",
            "Author": "BookTitle-2"
          },
          {
            "Name": "BookTitle-1",
            "Author": "BookTitle-2"
          }
        ]
      },
      {
        "Title": {
          "Name": "BookTitle-1"
        }
      }
    ]
  }
}

此前尝试在出站set-body策略中添加如下C#代码处理,但未生效:

string xmlContent = context.Response.Body.As<string>(preserveContent: true);
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlContent);
return JsonConvert.SerializeObject(doc);

可行解决方案

共两种经过验证的实现方案,优先选择第一种。

方案1:XML预处理添加数组标记(推荐)

APIM内置的xml-to-json策略底层基于Json.NET实现,支持识别特定命名空间的属性强制指定节点序列化为数组。只需要在XML转JSON之前,通过XSLT转换给所有Title节点添加json:Array="true"属性即可,不需要改动原有转换逻辑,性能更优。
完整出站策略配置如下:

<outbound>
    <base />
    <!-- XSLT预处理XML,给目标节点加强制数组标记 -->
    <xsl-transform>
        <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:json="http://james.newtonking.com/projects/json">
            <xsl:output method="xml" indent="yes"/>
            <xsl:template match="@*|node()">
                <xsl:copy>
                    <xsl:apply-templates select="@*|node()"/>
                </xsl:copy>
            </xsl:template>
            <!-- 匹配所有Title节点,添加数组标记 -->
            <xsl:template match="Title">
                <xsl:copy>
                    <xsl:attribute name="json:Array">true</xsl:attribute>
                    <xsl:apply-templates select="@*|node()"/>
                </xsl:copy>
            </xsl:template>
        </xsl:stylesheet>
    </xsl-transform>
    <!-- 原有XML转JSON逻辑保持不变 -->
    <xml-to-json kind="direct" apply="always" consider-accept-header="false" />
</outbound>

配置完成后,无论Title节点下有多少个子元素,转换后都会固定输出为JSON数组类型。

方案2:JSON转换后递归修正结构

如果不想使用XSLT,也可以在XML转JSON完成后,通过C#代码遍历JSON结构,将非数组类型的Title字段包装为数组。
注意:此前C#代码不生效的原因是直接序列化原始XmlDocument,生成的JSON结构和APIM内置转换的输出结构不一致,必须在xml-to-json策略执行完成后再运行修正代码。
出站set-body中使用的C#代码如下:

// 获取已经完成XML转JSON的响应内容
JObject responseContent = context.Response.Body.As<JObject>(preserveContent: true);

void NormalizeToExpectedArray(JToken token)
{
    if (token.Type == JTokenType.Object)
    {
        foreach (var property in token.Children<JProperty>().ToList())
        {
            // 匹配Title字段,非数组则包装为数组
            if (property.Name == "Title" && property.Value.Type != JTokenType.Array)
            {
                property.Value = new JArray(property.Value);
            }
            NormalizeToExpectedArray(property.Value);
        }
    }
    else if (token.Type == JTokenType.Array)
    {
        foreach (var item in token.Children())
        {
            NormalizeToExpectedArray(item);
        }
    }
}

NormalizeToExpectedArray(responseContent);
return responseContent.ToString();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 11:36:19