如何用Linq to XML读取XML并填充C#父子对象?
问题描述
我需要读取XML文件并将数据填充到C#的Field类中(包含父对象和子列表),希望用Linq to XML实现。Field类定义如下:
public class Field { public string Name { get; set; } = string.Empty; public List<string> Options { get; set; } = new(); public FieldType Type { get; set; } = 0; }
每个Field对象有两种情况:
- 包含空的
Options列表 - 包含有值的
Options列表
XML格式无法修改,简化后的内容如下:
<FieldProperties> <FieldName>Question 1</FieldName> <FieldType>1</FieldType> </FieldProperties> <FieldProperties> <FieldName>Dietaries</FieldName> <FieldType>9</FieldType> </FieldProperties> <FieldProperties> <FieldName>Question 2</FieldName> <FieldType>1</FieldType> </FieldProperties> <FieldProperties> <FieldName>Transport</FieldName> <FieldType>9</FieldType> </FieldProperties> <FieldOptions> <FieldName>Dietaries</FieldName> <Option>Dietary option 1</Option> </FieldOptions> <FieldOptions> <FieldName>Dietaries</FieldName> <Option>Dietary option 2</Option> </FieldOptions> <FieldOptions> <FieldName>Dietaries</FieldName> <Option>Dietary option 3</Option> </FieldOptions> <FieldOptions> <FieldName>Transport</FieldName> <Option>Transport option 1</Option> </FieldOptions> <FieldOptions> <FieldName>Transport</FieldName> <Option>Transport option 2</Option> </FieldOptions>
规则说明:
Field类对应<FieldProperties>标签- 当
FieldType为9时,需要通过FieldName关联对应的<FieldOptions>标签,将其中的<Option>值填充到Options列表中
我已经能遍历<FieldProperties>并填充基础属性,但不知道如何判断FieldType是否为9,以及关联获取对应的FieldOptions数据。当前代码如下:
XDocument xDocument = XDocument.Parse(xmlFields); XNamespace xNamespace = "http://tempuri.org/FieldDefinition.xsd"; List<Field> fields = xDocument.Descendants(xNamespace + "FieldProperties") .Select(fieldProperties => new Field { Name = (string)fieldProperties.Element(xNamespace + "FieldName")!.Value, Type = (FieldType)Int32.Parse(fieldProperties.Element(xNamespace + "FieldType")!.Value) }).ToList(); return fields;
解决方案
先将所有FieldOptions按FieldName分组构建映射字典,再处理FieldProperties时快速匹配对应选项,修改后的代码如下:
XDocument xDocument = XDocument.Parse(xmlFields); XNamespace xNamespace = "http://tempuri.org/FieldDefinition.xsd"; // 预构建FieldName到选项列表的映射,提升查询效率 var optionsMap = xDocument.Descendants(xNamespace + "FieldOptions") .GroupBy(opt => (string)opt.Element(xNamespace + "FieldName")!) .ToDictionary( group => group.Key, group => group.Select(opt => (string)opt.Element(xNamespace + "Option")!).ToList() ); List<Field> fields = xDocument.Descendants(xNamespace + "FieldProperties") .Select(fieldProps => { string fieldName = (string)fieldProps.Element(xNamespace + "FieldName")!; FieldType fieldType = (FieldType)int.Parse(fieldProps.Element(xNamespace + "FieldType")!.Value); var field = new Field { Name = fieldName, Type = fieldType }; // 当FieldType为9时,从映射字典中获取对应选项 if (fieldType == (FieldType)9) // 若FieldType枚举中9对应命名值,直接用命名值更清晰 { optionsMap.TryGetValue(fieldName, out var matchedOptions); field.Options = matchedOptions ?? new List<string>(); } return field; }) .ToList(); return fields;
要点说明:
- 预分组映射:通过
GroupBy和ToDictionary提前将FieldOptions按FieldName分组,避免重复遍历XML节点,优化性能。 - 类型判断与赋值:检查
FieldType是否为9,若是则从映射字典中取出对应选项,不存在则赋值空列表,保证逻辑健壮。 - 空值安全:使用
TryGetValue避免因FieldName不存在于映射字典中抛出异常。
内容的提问来源于stack exchange,提问作者Brendan Vogt
相关产品推荐
相关产品推荐

