【问题标题】:Linq to Xml Value PairLinq to Xml 值对
【发布时间】:2017-08-24 17:07:58
【问题描述】:

我的 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 to 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();

似乎正在发生的事情是,每次我“尝试”获取一个值......它只是返回 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; }
}   

有什么建议吗?

【问题讨论】:

    标签: c# linq-to-xml


    【解决方案1】:

    使用字典而不是类中的属性。我用 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; }
        } 
    }
    

    【讨论】:

    • 我建议对同一个键的多个值使用Lookup
    • @GeorgeAlexandria 你能详细说明一下吗?
    • 也.. 我怎么知道我在看哪个“id”值?你不需要一个地方吗?
    • @m1nkeh Dictionary&lt;string, List&lt;string&gt;&gt; 看起来像 ILookup<string, string>referencesource,其中一个键有多个值。因此,您可以将其转换为ILookup&lt;string, string&gt;,而不是转换为Dictionary&lt;string, List&lt;string&gt;&gt;
    • 我已经用另一个“obj”元素对原始 xml 进行了少量编辑
    【解决方案2】:

    如果对于同一个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}");
                }
            }
    

    或者你可以直接将所有NameValuePair分组Id再分组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}");
                        }
                    }
                }
            }
    

    【讨论】:

    • 噢,我喜欢这个!
    • @m1nkeh 我编辑了答案,因为我丢失了关于 Id 的信息,所以我把它放到了 AnonymousType。请再次检查答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多