Linq to Xml 值对

Linq to Xml Value Pair

我有 Xml 看起来像...

    <root>
        <extension>
            <Obj>
                <Id>12345</Id>
                <NameValuePair>
                    <Name>Prop1</Name>
                    <Value>Value1</Value>
                </NameValuePair>
                <NameValuePair>
                    <Name>Prop2</Name>
                    <Value>Value2</Value>
                </NameValuePair>
                <NameValuePair>
                    <Name>Prop3</Name>
                    <Value>Value3</Value>
                </NameValuePair>
            </Obj>
<Obj>
                <Id>67890</Id>
                <NameValuePair>
                    <Name>Prop4</Name>
                    <Value>Value5</Value>
                </NameValuePair>
                <NameValuePair>
                    <Name>Prop5</Name>
                    <Value>Value5</Value>
                </NameValuePair>
                <NameValuePair>
                    <Name>Prop6</Name>
                    <Value>Value6</Value>
                </NameValuePair>
            </Obj>
        </extension>
    </root>

我正在尝试使用 XDocument / Linq 来 XML 来实现..

Id: 12345
Prop1: Value1
Prop2: Value2
Prop3: Value3

Id: 67890
Prop1: Value1
Prop2: Value2
Prop3: Value3

我已经知道需要查找的 ID,在此处的代码中,我已按照示例将其硬编码为“12345”...这就是我目前所拥有的...

    var val = xmlDoc.Element("extension").Elements("Obj")
                                                 .Where(i => (string)i.Element("Id") == "12345" &&
                                                             (string)i.Element("NameValuePair").Element("Name") == "Prop2")
                                                 .Select(i => (string)i.Element("NameValuePair").Element("Value")).FirstOrDefault();

似乎正在发生的事情是每次我 "try" 得到一个值...它只是 returns NULL..

最终,我试图将它放入一个对象中,例如...

internal class MyClass
{
    public string Id { get; internal set; }
    public string Prop1 { get; internal set; }
    public string Prop2 { get; internal set; }
    public string Prop3 { get; internal set; }
}   

有什么建议吗?

在 class 中使用字典而不是属性。我用 xml linq :

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

namespace ConsoleApplication74
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XDocument doc = XDocument.Load(FILENAME);

            List<MyClass> myClasses = doc.Descendants("Obj").Select(x => new MyClass() {
                Id = (int)x.Element("Id"),
                dict1 = x.Elements("NameValuePair").GroupBy(y => (string)y.Element("Name"), z => (string)z.Element("Value"))
                        .ToDictionary(y => y.Key, z => z.FirstOrDefault()),
                dict2 = x.Elements("NameValuePair").GroupBy(y => (string)y.Element("Name"), z => (string)z.Element("Value"))
                        .ToDictionary(y => y.Key, z => z.ToList())
            }).ToList();

        }
    }
    internal class MyClass
    {
        public int Id { get; internal set; }
        public Dictionary<string,string> dict1 { get; set; }
        public Dictionary<string, List<string>> dict2 { get; set; }
    } 
}

如果对于同一个 Prop 你有多个 Value

,你可以将你的值转换为 Lookup
        // use temporary variable to increase performance of item.Element, I'm not sure that all 'Obj' element contains 'Id'
        XElement idElement = null;
        var values = doc.Descendants("Obj")
            .Where(item => (idElement = item.Element("Id")) != null && idElement.Value == "12345")
            .Descendants("NameValuePair")
            .ToLookup(o => o.Element("Name").Value, o => new { Id = idElement.Value, Value = o.Element("Value").Value });

        foreach (var valuesByProp in values)
        {
            foreach (var prop in valuesByProp)
            {
                Console.WriteLine($"{prop.Id}, {valuesByProp.Key}, {prop.Value}");
            }
        }

或者您可以直接将所有 NameValuePairId 分组,然后按 Prop

分组
        var values = doc.Descendants("Obj")
            .ToLookup(o => o.Element("Id").Value, 
                o => o.Descendants("NameValuePair").ToLookup(p => p.Element("Name").Value, p => p.Element("Value").Value));

        foreach (var groupById in values)
        {
            foreach (var groupByProp in groupById)
            {
                foreach (var valuesByProp in groupByProp)
                {
                    foreach (var value in valuesByProp)
                    {
                        Console.WriteLine($"{groupById.Key}, {valuesByProp.Key}, {value}");
                    }
                }
            }
        }