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

C#实现XML内容树形结构的名称与索引混合访问问题

把XML转成可通过名称+索引访问的树形结构(C#实现)

嘿,我完全懂这种被问题缠得睡不着的感觉——要把XML的层级结构转成能像xmlContent["employee"][0]["e-mail"][1]这样直接访问的格式,确实得琢磨一下结构设计。我之前做过类似的需求,给你整理了一个完整的实现方案,应该能完美解决你的问题。

核心实现思路

我们需要一个既能作为列表(存储所有子节点)又能通过节点名称快速查找同名子节点集合的类。这里我用XmlDynamicNode类来实现,它继承自List<XmlDynamicNode>,同时内部维护一个字典来映射节点名称到对应的子节点列表,再加上文本属性保存节点内容。

完整代码实现

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

public class XmlDynamicNode : List<XmlDynamicNode>
{
    // 存储当前节点的文本内容
    public string Text { get; set; }

    // 映射节点名称到同名子节点的列表(支持忽略大小写查找)
    private readonly Dictionary<string, List<XmlDynamicNode>> _nodeNameMap = new Dictionary<string, List<XmlDynamicNode>>(StringComparer.OrdinalIgnoreCase);

    // 通过节点名称获取同名子节点的列表
    public List<XmlDynamicNode> this[string nodeName]
    {
        get
        {
            _nodeNameMap.TryGetValue(nodeName, out var targetNodes);
            return targetNodes ?? new List<XmlDynamicNode>(); // 找不到返回空列表,避免空引用异常
        }
    }

    // 私有构造函数,只能通过Parse方法创建实例
    private XmlDynamicNode() { }

    // 从XElement解析生成XmlDynamicNode树形结构
    public static XmlDynamicNode Parse(XElement xmlElement)
    {
        var node = new XmlDynamicNode();
        // 提取节点的文本内容(自动去除首尾空白)
        node.Text = xmlElement.Value.Trim();

        // 递归解析所有子节点
        foreach (var childElement in xmlElement.Elements())
        {
            var childNode = Parse(childElement);
            node.Add(childNode);

            // 更新节点名称映射字典
            var childNodeName = childElement.Name.LocalName;
            if (!_nodeNameMap.ContainsKey(childNodeName))
            {
                node._nodeNameMap[childNodeName] = new List<XmlDynamicNode>();
            }
            node._nodeNameMap[childNodeName].Add(childNode);
        }

        return node;
    }

    // 重载ToString,直接输出节点文本内容
    public override string ToString()
    {
        return Text;
    }
}

使用示例

假设我们有这样一个XML文件(employees.xml):

<company>
    <employee>
        <name>John Doe</name>
        <e-mail>john.doe@example.com</e-mail>
        <e-mail>john.work@example.com</e-mail>
    </employee>
    <employee>
        <name>Jane Smith</name>
        <e-mail>jane.smith@example.com</e-mail>
    </employee>
</company>

解析并访问数据的代码如下:

// 加载XML文件
var xmlDoc = XDocument.Load("employees.xml");
// 从根节点开始解析成我们的动态节点结构
var xmlContent = XmlDynamicNode.Parse(xmlDoc.Root);

// 访问第一个员工的第二个邮箱地址
Console.WriteLine(xmlContent["employee"][0]["e-mail"][1]); 
// 输出结果: john.work@example.com

// 访问第二个员工的姓名
Console.WriteLine(xmlContent["employee"][1]["name"][0]);
// 输出结果: Jane Smith

// 也可以通过列表索引直接访问所有子节点(比如取第一个子节点,也就是第一个employee)
Console.WriteLine(xmlContent[0]["name"][0]);
// 输出结果: John Doe

额外说明

  • 大小写不敏感:字典用了StringComparer.OrdinalIgnoreCase,所以xmlContent["Employee"]和xmlContent["employee"]会返回同一个列表,不需要严格匹配大小写。如果不需要这个特性,去掉这个参数即可。
  • 属性支持:如果你的XML包含节点属性,只需在XmlDynamicNode中添加一个Dictionary<string, string> Attributes,然后在Parse方法中遍历xmlElement.Attributes()并添加到字典里即可。
  • 空安全处理:访问不存在的节点名称时会返回空列表,而非抛出空引用异常。如果需要更严格的检查,可以修改索引器逻辑,比如返回null或者抛出自定义异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:34:04