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

如何使用Circe公共API实现JSON到XML的递归格式转换?

如何使用Circe公共API实现JSON到XML的转换

你之前的方案确实踩了Circe的一个小坑——直接依赖了包私有的JBoolean、JObject等内部类型,导致代码只能在io.circe包下运行。不过别担心,Circe提供了完整的公共API来遍历和操作JSON结构,完全不需要碰这些私有类型。下面我就给你演示怎么用公共API重写你的转换逻辑:

优化后的实现(使用公共API)

我们可以用Circe Json类型提供的fold方法,它是专门为这种类型分支处理设计的公共方法,完美替代原来的模式匹配:

import io.circe.Json
import io.circe.parser.parse

object JsonToXmlConverter extends App {
  def transformToXMLString(js: Json): String = {
    js.fold(
      // 处理Null类型
      "",
      // 处理布尔值
      booleanValue => booleanValue.toString,
      // 处理数字
      numberValue => numberValue.toString,
      // 处理字符串
      stringValue => stringValue.toString,
      // 处理数组:递归转换每个元素后拼接
      array => array.map(transformToXMLString).mkString(""),
      // 处理对象:遍历键值对,生成XML标签后拼接
      obj => obj.toIterable.map { case (key, value) =>
        s"<${key}>${transformToXMLString(value)}</${key}>"
      }.mkString("")
    )
  }

  // 测试用的JSON字符串
  val jsonInput = """{
    | "root": {
    | "sampleboolean": true,
    | "sampleobj": {
    | "anInt": 1,
    | "aString": "string"
    | },
    | "objarray": [
    | {"v1": 1},
    | {"v2": 2}
    | ]
    | }
    |}""".stripMargin

  // 解析JSON并处理结果(增加错误处理,避免直接get抛出异常)
  parse(jsonInput) match {
    case Right(validJson) => println(transformToXMLString(validJson))
    case Left(parseError) => println(s"JSON解析失败: ${parseError.getMessage}")
  }
}

代码说明

  • fold方法的作用:它会根据当前Json实例的实际类型,自动调用对应的处理函数,覆盖了所有可能的JSON类型(Null、布尔、数字、字符串、数组、对象),完全替代了对私有J*类型的模式匹配。
  • 对象和数组的处理:对于JSON对象,我们用公共方法toIterable遍历键值对;对于数组,直接用map递归处理每个元素,和你原来的逻辑一致,但完全基于公共API。
  • 错误处理优化:把原来的right.get换成了模式匹配,避免了JSON解析失败时抛出未捕获的异常,代码更健壮。

输出结果

运行这段代码,你会得到和原来完全一样的XML字符串:

<root><sampleboolean>true</sampleboolean><sampleobj><anInt>1</anInt><aString>string</aString></sampleobj><objarray><v1>1</v1><v2>2</v2></objarray></root>

另一种实现方式(类型判断+获取值)

如果你更喜欢用条件判断的风格,也可以用Circe提供的isXxx和asXxx系列公共方法:

def transformToXMLStringAlternative(js: Json): String = {
  js match {
    case _ if js.isNull => ""
    case _ if js.isBoolean => js.asBoolean.get.toString
    case _ if js.isNumber => js.asNumber.get.toString
    case _ if js.isString => js.asString.get.toString
    case _ if js.isArray => js.asArray.get.map(transformToXMLStringAlternative).mkString("")
    case _ if js.isObject => js.asObject.get.toIterable.map { case (k, v) =>
      s"<${k}>${transformToXMLStringAlternative(v)}</${k}>"
    }.mkString("")
    case _ => "" // 理论上不会触发,因为JSON只有上述6种类型
  }
}

不过这种方式需要注意:asXxx.get会在类型不匹配时抛出异常,而fold方法是类型安全的,强制你处理所有情况,所以更推荐用fold的实现方式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:20:37