【问题标题】:Dictionary<string, List<ClassObj>> LINQ To XML QueryDictionary<string, List<ClassObj>> LINQ To XML 查询
【发布时间】:2016-03-03 23:35:15
【问题描述】:

我尝试将我的 XML 文件放入带有通用列表的字典中。如何使用正确的键将正确的查询列表合并到我的字典中?代替.ToList() .ToDictionary 不行吗?

<?xml version="1.0"?>
<customers>
  <cust ID="1" DeviceID="1" Name="Bob" Latitude="10" Longitude="58" Device="HW1.0"> </cust>
  <cust ID="2" DeviceID="2" Name="Jack" Latitude="28" Longitude="20" Device="HW2.2"> </cust>
</customers>

//XML attribute Name is Dict Key

public class Customers
{
    public int Longitude { get; set; }
    public int Latitude { get; set; }
    public int DeviceID { get; set; }
    public string Device { get; set; }
}

class Program
{

    private static Dictionary<string, List<Customers>> ReadXmlToDict(string filename)
    {
        // Should be Key = Xml Attribute Name Value, List of class 
        Dictionary<string, List<Customers>> dict = new Dictionary<string, List<Customers>>();

        XDocument xdoc = XDocument.Load(filename);
        var querylist = (from row in xdoc.Descendants("cust")
                         select new Customers()
                         {
                             //Name = (string)row.Attribute("Name"),  // Wrong here should be the Dic key
                             DeviceID = (int)row.Attribute("DeviceID"), // list value
                             Longitude = (int)row.Attribute("Longitude"),  // list value
                             Latitude = (int)row.Attribute("Latitude"), // list value
                             Device = (string)row.Attribute("Device")  // list value
                         }).ToList();

        return null; // null for test To.List and not Dict
    }

【问题讨论】:

  • 可能是这样的(from row in xdoc.Descendants("cust")).ToDictionary(k =&gt; (string)row.Attribute("ID"), (v =&gt; select new Customers() { }).ToList());
  • 谢谢,但我仍然有问题要使 linq 查询对 Dictionary,List> 正确。语法仍然是错误的,但你的帮助给了我一个想法。我会试试的。

标签: c# xml


【解决方案1】:

这就是我将如何实现它,我认为它可以实现您正在寻找的东西。你有一个名为Customers 的类,然后想用一个键存储这些客户的列表……我不遵循这个逻辑。

我创建了一个名为Customer 的类,其中包含单个客户的信息。由于您要返回 Dictionary&lt;string, Customer&gt;,其中字符串是 xml 中的唯一属性 Name,因此您的字典的值不会是 List&lt;Customer&gt;。也许如果您有多个同名客户,您会使用它,但为什么不将密钥设置为(我假设)真正唯一的标识符,DeviceID

namespace TestConsole
{
    class Customer
    {
        public int DeviceID;
        public int Longitude;
        public int Latitude;
        public string Device;
    }
    class Program
    {

        private static Dictionary<string, Customer> ReadXmlToDictionary(string filename)
        {
            var dict = new Dictionary<string, Customer>();

            var doc = XDocument.Load(@"C:\test.xml");

            dict = doc.Descendants("cust")
                .ToDictionary(
                    row => (string)row.Attribute("Name"),
                    row => new Customer {
                        Device = (string)row.Attribute("Device"),
                        DeviceID = (int)row.Attribute("DeviceID"),
                        Latitude = (int)row.Attribute("Latitude"),
                        Longitude = (int)row.Attribute("Longitude")
                });

            return dict;
        }

        static void Main(string[] args)
        {
            ReadXmlToDictionary(null);
        }
    }
}

编辑:认为与性能相关的答案很有趣,因此决定对这个单级 xml 进行尝试(使用 ID 作为唯一标识符)。结果如下:

1019 Descendants took 0.0030257 seconds.
1019 Elements took 0.0028348 seconds.
10000 Descendants took 0.0098942 seconds.
10000 Elements took 0.0101478 seconds.
100000 Descendants took 0.0873025 seconds.
100000 Elements took 0.1223577 seconds.

编辑: 创建 xsd 并从中生成一个类后,您可以这样使用它:

var parsed = XDocument.Parse(doc.ToString());

var serializer = new XmlSerializer(typeof(Xsds.customers));

var typedPayload = serializer.Deserialize(doc.Root.CreateReader());

var xmlAsClass = (TestConsole.Xsds.customers)typedPayload;

dict = xmlAsClass.cust
    .ToDictionary(
        row => (int)row.ID,
        row => new Customer {
            Device = row.Device,
            DeviceID = row.DeviceID,
            Latitude = row.Latitude,
            Longitude = row.Longitude,
            Name = row.Name
        });

【讨论】:

  • 你说得对,我不需要列表,因为每个客户的名字都应该是唯一的。我不仅对正确的语法有误解。非常感谢!
  • 关于我的话题我还有一个问题。我真的不喜欢硬编码值,例如客户的班级。复用率很低,一个基于Attributes的类就好了,包括通用的xml属性名。
  • 您可以而且应该创建一个 xsd。如果您不想手动创建 xsd,可以使用它:freeformatter.com/xsd-generator.html#ad-output。由于其中一些是可以为空的,我认为你不能使用xsd.exe,原因如下:stackoverflow.com/questions/32610770/…,所以使用 xsd2code 或 wscfblue 或其他一些工具来生成类。
  • 不错的基准测试! XML Schema 是可以理解的,我已经为我的 xml 文件提供了一个模式,基于新的教学和学习功能,我将尝试基于 xml 模式的最新版本。我认为更多的努力有助于以后在其他项目中更好地重用我的类和方法。
  • 嘿@Shazter 记得标记答案,如果它回答了你的问题,这样未来的读者就会有可能解决他们的类似问题。
【解决方案2】:

您可以使用ToDictionary() 扩展方法轻松完成。但在性能方面,使用Elements() 方法比使用Descendants() 好得多;如需进一步阅读,请阅读此博客文章: WHY (OR WHEN) YOU SHOULD/SHOULDN’T USE DESCENDANTS() METHOD

您的查询将如下所示:

var customersDictionary = 
    xDoc.Root
        .Elements("cust")
        .ToDictionary(xe => 
                        xe.Attribute("Name").Value, xe => 
                        new Customers
                        {
                            DeviceID = (int)xe.Attribute("DeviceID"), 
                            Longitude = (int)xe.Attribute("Longitude"),  
                            Latitude = (int)xe.Attribute("Latitude"),
                            Device = (string)xe.Attribute("Device")
                        });

【讨论】:

  • 这个链接很有趣也很有帮助。
  • @Shazter,请考虑将最有用的答案标记为已接受的答案,以便对其他人也有用。
猜你喜欢
  • 1970-01-01
  • 2019-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多