C#怎么将XML转成JSON_C#如何实现两种数据格式的互转【技巧】

2次阅读

最稳组合是xmlSerializer反序列化为强类型对象再用jsonConvert序列化;遇无根/重复元素等不规则XML时改用XDocument转字典或匿名对象;避免直接用SerializeXNode()。

XmlSerializer + JsonConvert 是最稳的组合

直接上结论:c# 里 xml 转 json 不推荐手写解析,也不该依赖 dataset.readxml 这类间接路径。核心链路是先反序列化为强类型对象,再序列化为 json —— 这样语义清晰、可控性强、能自然处理命名冲突和空值。

常见错误是试图用 XDocument.ToString() 拼接 JSON 字符串,结果属性名大小写错、嵌套层级崩、NULL 变成字符串 "null",调试时连原始结构都对不上。

  • 必须定义与 XML 结构严格匹配的 C# 类,字段名默认要跟 XML 元素名一致(或用 [XmlElement("xxx")] 显式标注)
  • XmlSerializer 不支持直接读取带命名空间的 XML,遇到 xmlns="http://..." 必须传入 XmlRootAttribute 指定 Namespace
  • 如果 XML 有混合内容(文本+子元素),别用 [XmlText][XmlElement] 混用,容易抛 InvalidOperationException

处理无根节点或不规则 XML 时用 XDocument + JObject.FromObject()

有些 XML 来自第三方接口,没有统一根节点,或者包含重复同名元素(如多个 <item>),这时强类型反序列化会失败。得退一步,用 XDocument 加载后转成字典或匿名对象再进 JSON 流程。

典型场景:解析 RSS、SOAP 响应体、或配置片段;这类 XML 往往没预定义 schema,靠运行时推导结构更实际。

  • XDocument.Load()XDocument.Parse() 加载后,调用 Root?.Elements().ToDictionary(...) 构建键值映射,注意重复 key 要转成 List<JToken>
  • 别直接把 XElement 丢给 JsonConvert.SerializeXNode() —— 它会把属性转成 @attr,文本内容变成 #text,前端根本没法消费
  • 若需保留原始顺序,别用 Dictionary,改用 List<KeyValuePair<string, object>>,再用 JObject.FromObject()

JsonConvert.SerializeXNode() 的坑比想象中多

这个方法看着省事,但实际生产环境出问题频率很高。它不是“XML → JSON”的通用翻译器,而是按固定规则做节点投影,很多隐含行为会破坏数据语义。

典型错误现象:<price>19.99</price> 变成 {"price": {"#text": "19.99"}},而不是预期的 {"price": "19.99"};或者空元素 <desc /> 输出 {"desc": null},而前端期望的是 {"desc": ""}

  • 必须传 writeArrayAttribute: false,否则会把 <items count="2"> 的属性也塞进 JSON,污染结构
  • omitRootObject: true 很关键 —— 否则顶层会多包一层对象,比如 {"root": {...}},而你只需要内部内容
  • 它不处理 CDATA、注释、处理指令,遇到就静默跳过,日志里还不会报错

性能敏感场景下避免两次序列化

高频转换(如 API 网关层)里,走 XmlSerializer → object → JsonConvert 会有明显 GC 压力和 CPU 开销。这时候要绕过中间对象,用流式处理。

适用条件:XML 结构相对固定、不需要复杂校验、能接受 JSON 字段名硬编码。

  • XmlReader 逐节点读取,同时用 JsonTextWriter 写入,手动控制字段名和嵌套层级
  • 注意 XmlReader.Read() 返回 XmlNodeType.Element 后,要立刻调用 ReadStartElement(),否则后续 ReadContentAsString() 会跳过文本
  • 空元素(<tag/>)在 XmlReader 中是 EmptyElement 类型,需单独判断并输出 ""null,不能等它自动推进到下一个节点

真正难的不是语法怎么写,而是搞清 XML 的实际结构有没有混合内容、属性是否承载语义、空值要不要透传。这些细节不提前确认,代码写完一半才发现 XmlSerializer 拒绝反序列化,或者 JSON 里突然冒出一 @# 开头的字段。

text=ZqhQzanResources