2016-03-03 61 views
0

我尝试将我的XML文件放入具有通用列表的字典中。我如何使用正确的键将正确的查询列表合并到我的字典中?而不是.ToList().ToDictionary是不可能的?字典<字符串,列表<ClassObj>> LINQ到XML查询

<?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 
    } 
+0

也许是这样的'(从xdoc.Descendants行(“卡斯特”))ToDictionary( k =>(string)row.Attribute(“ID”),(v => select new Customers(){})。ToList());'? – Tim

+0

谢谢,但我仍然有问题,使linq查询正确的字典,名单>。语法仍然是错误的,但你的帮助给了我一个想法。我会尝试。 – Shazter

回答

2

这是我将如何实现它,我觉得它实现你在找什么。你有一个名为Customers的课程,然后希望用一个键存储这些用户的列表......我不遵循这个逻辑。

我创建了一个名为Customer的类,其中包含单个客户的信息。由于您要返回Dictionary<string, Customer>,其中字符串是xml中的唯一属性Name,因此您的字典的值为List<Customer>没有用例。也许如果你有多个同名的客户,你可以使用这个,但为什么不把这个密钥(我认为)真正的唯一标识符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); 
     } 
    } 
} 

Image of results

编辑:原以为与性能相关的回答很有趣,于是决定(使用ID作为唯一标识符)尝试一下这种单级XML。下面是结果:

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 
     }); 
+0

你是完全正确的,我不需要名单,因为每个客户应该是唯一的名称。我不仅误解了正确的语法。非常感谢! – Shazter

+0

与我的主题相关我还有一个问题。我真的不喜欢硬编码值,例如该类为客户。重用非常低,基于Attributes的类将会很不错,包括通用的xml属性名称。 – Shazter

+0

您可以并且应该创建一个xsd。如果您不想手动创建xsd,可以使用它:http://www.freeformatter.com/xsd-generator.html#ad-output。由于其中一些是可以空的,我不认为你可以在这里使用'xsd.exe':http://stackoverflow.com/questions/32610770/deserialization-of-nullable-value-with -xsd-exe-generated-class,所以使用xsd2code或wscfblue或其他工具来生成类。 –

1

您可以轻松地做到这一点使用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") 
         }); 
+1

该链接非常有帮助。 – Shazter

+0

@Shazter,请考虑将最有用的答案标记为可接受的答案,以便对其他人有用。 –

相关问题