C# Linq to XML 获取父对象和子对象

C# Linq to XML getting of parent and child objects

提问人:Brendan Vogt 提问时间:9/20/2023 更新时间:9/20/2023 访问量:29

问:

我正在尝试读取XML文件,然后将值填充到C#类(父对象和子对象)中。为了简洁起见,我省略了很多代码。我正在尝试通过Linq to XML来实现这一点。

我创建了以下类,该类将是父类,该类还将承载子字符串对象的列表:

public class Field
{
    public string Name { get; set; } = string.Empty;
    public List<string> Options { get; set; } = new();
    public FieldType Type { get; set; } = 0;
}

因此,一个字段可以包含以下 2 项内容中的 1 项:

  1. 它可以有一个空的字符串选项列表
  2. 或者它可以有一个字符串选项列表

XML是以一种有趣的方式完成的,我无法更改它,我只需要读入它并填充类和字符串对象(如果有的话),然后将此列表返回到前端进行进一步处理。

简化形式的 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>

字段类由标记表示。要确定字段是否有选项,您需要检查它是否具有 9。如果是 9,那么你必须去寻找,这与标签的标签相关联。FieldPropertiesFieldTypeFieldTypeFieldOptionsFieldNameFieldProperties

我不知道如何编写这样的查询。我目前所拥有的是遍历所有字段属性,然后填充字段属性。但是我不知道如何检查字段类型是否为 9,如果为 9,则去获取子对象列表,然后填充 Options 属性。FieldPropertiesFieldOptions

这是我目前拥有的:

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;
C# LINQ-to-XML

评论

1赞 user16606026 9/20/2023
首先以列表形式获取所有内容,然后通过字段获取 foreach,如果字段为 9,则获取所有与之同名的内容,然后设置该字段。FieldOptionsTypeFieldOptionsOptions

答:

0赞 sep7696 9/20/2023 #1
var fields = xDocument.Root
                      .Elements(xNamespace + "FieldProperties")
                      .Select(fp => new Field {
                          Name = (string)fp.Element(xNamespace + "FieldName"),
                          Type = (FieldType)int.Parse(fp.Element(xNamespace + "FieldType")!.Value)
                      })
                      .GroupJoin(
                          xDocument.Root.Elements(xNamespace + "FieldOptions"),
                          f => f.Name,
                          fo => (string)fo.Element(xNamespace + "FieldName"),
                          (f, fo) => new { Field = f, Options = fo })
                      .SelectMany(x => 
                          x.Field.Type == FieldType.Options
                              ? x.Options.Select(o => new { x.Field, Option = (string)o.Element(xNamespace + "Option")! }) 
                              : new { x.Field })
                      .GroupBy(x => x.Field)
                      .Select(g => 
                      {
                          var field = g.Key;
                          if (field.Type == FieldType.Options)
                          {
                              field.Options = g.Select(x => x.Option).ToList();
                          }
                          return field;
                      })
                      .ToList();

1.GroupJoin将字段与其对应的选项匹配

2.选择Many以平展成{Field, Option}对的流

3.GroupBy 字段以合并选项