跳到主要内容

将 JSON 转换为 XML

XML (可扩展标记语言) 是一种广泛采用的标准,用于表示和组织结构化数据。凭借其灵活性和人类可读的语法,XML 为跨各种系统和平台的数据交换和存储提供了一种通用的解决方案。它也被 SOAP 协议用作其消息格式。

本指南将向你展示如何使用 body-transformer 插件在 JSON 和 XML SOAP 之间进行转换,这允许客户端在与 SOAP 服务交互时发送和接收 JSON 数据。


JSON 到 XML 图解

前置条件

  • 安装 Docker
  • 安装 cURL 以向 APISIX 发送请求进行验证。
  • 安装 Java 17 用于示例 SOAP 服务器。
  • 按照 快速入门教程 在 Docker 或 Kubernetes 中启动一个新的 APISIX 实例。

部署示例 SOAP 服务器

启动一个 示例 SOAP 服务器,该服务器公开来自各个欧洲国家的数据:

cd /tmp
git clone https://github.com/spring-guides/gs-soap-service.git
cd gs-soap-service/complete
./mvnw spring-boot:run

创建转换模板

转换模板主要使用 lua-resty-template 语法。有关更多信息,请参阅 模板语法

此外,你可以在模板中使用一些辅助函数:

  • _escape_json()_escape_xml() - 用于转义特殊字符,例如双引号
  • _body - 用于访问请求正文
  • _ctx - 用于访问上下文变量

创建请求和响应转换模板,这些模板是自定义的,并在 body-transformer 插件中配置,以指示如何在 XML 和 JSON 之间进行转码:

req_template=$(cat <<EOF | awk '{gsub(/"/,"\\\"");};1' | awk '{$1=$1};1' | tr -d '\r\n'
<?xml version="1.0"?>
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
<soap-env:Body>
<ns0:getCountryRequest xmlns:ns0="http://spring.io/guides/gs-producing-web-service">
<ns0:name>{{_escape_xml(name)}}</ns0:name>
</ns0:getCountryRequest>
</soap-env:Body>
</soap-env:Envelope>
EOF
)

rsp_template=$(cat <<EOF | awk '{gsub(/"/,"\\\"");};1' | awk '{$1=$1};1' | tr -d '\r\n'
{% if Envelope.Body.Fault == nil then %}
{
"status":"{{_ctx.var.status}}",
"currency":"{{Envelope.Body.getCountryResponse.country.currency}}",
"population":{{Envelope.Body.getCountryResponse.country.population}},
"capital":"{{Envelope.Body.getCountryResponse.country.capital}}",
"name":"{{Envelope.Body.getCountryResponse.country.name}}"
}
{% else %}
{
"message":{*_escape_json(Envelope.Body.Fault.faultstring[1])*},
"code":"{{Envelope.Body.Fault.faultcode}}"
{% if Envelope.Body.Fault.faultactor ~= nil then %}
, "actor":"{{Envelope.Body.Fault.faultactor}}"
{% end %}
}
{% end %}
EOF
)

配置 APISIX

创建一个路由,使用 body-transformer 引用之前创建的转换模板:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "body-transformer-route",
"methods": ["POST"],
"uri": "/ws",
"plugins": {
"body-transformer": {
"request": {
"template": "'"$req_template"'",
// Annotate 1
"input_format": "json"
},
"response": {
"template": "'"$rsp_template"'",
// Annotate 2
"input_format": "xml"
}
},
"proxy-rewrite": {
"headers": {
"set": {
// Annotate 3
"Content-Type": "text/xml"
}
}
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
// Annotate 4
"localhost:8080": 1
}
}
}'

❶ 将请求输入格式设置为 JSON,以便插件在内部应用 JSON 解码器。

❷ 将响应输入格式设置为 XML,以便插件在内部应用 XML 解码器。

❸ 将 Content-Type 标头设置为 text/xml,以便上游服务正确响应。

❹ 更新你的 SOAP 服务的连接地址。

提示

如果调整复杂的文本文件以使其成为有效的转换模板很麻烦,你可以使用 base64 实用程序对文件进行编码,例如:

"body-transformer": {
"request": {
"template": "'"$(base64 -w0 /path/to/request_template_file)"'"
},
"response": {
"template": "'"$(base64 -w0 /path/to/response_template_file)"'"
}
}

验证

向路由发送带有有效 JSON 正文的请求:

curl "http://127.0.0.1:9080/ws" -X POST -d '{"name": "Spain"}'

你应该看到类似以下的响应:

{
"status": "200",
"currency": "EUR",
"population": 46704314,
"capital": "Madrid",
"name": "Spain"
}

这表明请求中发送的 JSON 正文已转换为 XML 并转发到上游 SOAP 服务,响应正文已从 XML 转换回 JSON。

下一步

body-transformer 插件还可以用于 YAML 和 JSON 之间的转换,或修改请求正文。有关更多信息,请参阅 插件文档