C#实现XML到JSON动态映射,解决自定义对象数组递归映射问题
嵌套对象数组的XML到JSON动态递归映射解决方案(C#)
针对你对接Actionstep API时遇到的自定义对象数组递归映射问题,以下是可落地的实现方案:
一、扩展数据库映射规则表
首先需要调整映射规则的存储结构,让它能描述嵌套对象的层级关系:
- 新增
ParentMappingId字段:关联父级对象的映射ID,标记当前字段属于哪个嵌套对象 - 新增
IsArray字段:标记当前是否为数组类型,结合FieldType区分是原始数组还是自定义对象数组
示例规则(针对friends数组):
| ID | SourceXPath | TargetJsonPath | FieldType | ParentMappingId | IsArray |
|---|---|---|---|---|---|
| 1 | /root/friends | $.friends | Object | NULL | 1 |
| 2 | /root/friends/*/name | $.friends[*].name | String | 1 | 0 |
| 3 | /root/friends/*/age | $.friends[*].age | Int | 1 | 0 |
二、递归映射核心逻辑实现
通过递归方法处理嵌套对象数组,核心流程是:识别数组规则→遍历XML子节点→创建对应JSON对象→递归填充子字段→组装数组并赋值到目标路径。
代码示例
using System; using System.Collections.Generic; using System.Linq; using System.Xml; using Newtonsoft.Json.Linq; public class XmlToJsonDynamicMapper { // 映射规则模型(与数据库表结构对应) public class MappingRule { public int Id { get; set; } public string SourceXPath { get; set; } public string TargetJsonPath { get; set; } public string FieldType { get; set; } public int? ParentMappingId { get; set; } public bool IsArray { get; set; } } private readonly List<MappingRule> _mappingRules; public XmlToJsonDynamicMapper(List<MappingRule> rules) { _mappingRules = rules; } public JObject Map(XmlDocument inputXml, JObject actionstepJsonTemplate) { // 先处理顶级无父级的映射规则 var topLevelRules = _mappingRules.Where(r => !r.ParentMappingId.HasValue).ToList(); ProcessNodeMapping(inputXml.DocumentElement, actionstepJsonTemplate, topLevelRules); return actionstepJsonTemplate; } private void ProcessNodeMapping(XmlNode currentXmlNode, JToken currentJsonNode, List<MappingRule> rules) { foreach (var rule in rules) { if (rule.IsArray) { // 处理自定义对象数组 var xmlArrayNodes = currentXmlNode.SelectNodes(rule.SourceXPath); if (xmlArrayNodes == null || xmlArrayNodes.Count == 0) continue; var childRules = _mappingRules.Where(r => r.ParentMappingId == rule.Id).ToList(); var jsonArray = new JArray(); foreach (XmlNode itemXmlNode in xmlArrayNodes) { var itemJsonObject = new JObject(); // 递归处理数组内每个对象的字段映射 ProcessNodeMapping(itemXmlNode, itemJsonObject, childRules); jsonArray.Add(itemJsonObject); } // 将组装好的数组赋值到JSON模板对应路径 SetJsonValue(currentJsonNode, rule.TargetJsonPath, jsonArray); } else { // 处理基础类型字段 var xmlValue = currentXmlNode.SelectSingleNode(rule.SourceXPath)?.InnerText; if (string.IsNullOrWhiteSpace(xmlValue)) continue; var jsonValue = ConvertToJToken(xmlValue, rule.FieldType); SetJsonValue(currentJsonNode, rule.TargetJsonPath, jsonValue); } } } // 类型转换:将XML文本值转为对应JSON类型 private JToken ConvertToJToken(string value, string fieldType) { return fieldType switch { "Int" => JToken.Parse(value), "Boolean" => JToken.Parse(value.ToLower()), "DateTime" => JToken.Parse(DateTime.Parse(value).ToString("yyyy-MM-ddTHH:mm:ssZ")), "Decimal" => JToken.Parse(value), _ => JToken.FromObject(value) // 默认转为字符串 }; } // 按JSON路径赋值,支持数组路径标识 private void SetJsonValue(JToken rootNode, string jsonPath, JToken value) { var pathSegments = jsonPath.Replace("$.", "").Split('.'); var currentNode = rootNode; for (int i = 0; i < pathSegments.Length; i++) { var segment = pathSegments[i]; if (segment.EndsWith("[*]")) { // 数组节点直接赋值 segment = segment.Replace("[*]", ""); currentNode[segment] = value; break; } if (i == pathSegments.Length - 1) { currentNode[segment] = value; } else { // 不存在则创建嵌套对象 currentNode[segment] ??= new JObject(); currentNode = currentNode[segment]; } } } }
三、对接Actionstep API的整合流程
- 获取JSON模板:通过GET请求调用Actionstep API的创建Action接口,获取模板JSON
- 加载映射规则:从数据库读取包含嵌套数组规则的完整映射列表
- 解析输入XML:将外部传入的XML数据解析为
XmlDocument对象 - 执行映射:实例化
XmlToJsonDynamicMapper,调用Map方法填充JSON模板 - 提交数据:将填充完成的JSON通过POST请求提交到Actionstep API
四、关键注意事项
- XPath路径要精准:数组子项需用
/*匹配所有子节点(如/root/friends/*/name) - JSON路径兼容:支持
$.friends[*].name这种数组元素的路径写法 - 空值容错:XML节点不存在时跳过赋值,避免覆盖JSON模板的默认配置
- 类型校验:严格按
FieldType做类型转换,防止JSON格式不符合API要求
内容的提问来源于stack exchange,提问作者Hardipsinh Jadeja
相关产品推荐
相关产品推荐

