2013-03-28 65 views
0

我在編寫正確的代碼或提出問題時可能會出錯,但我正在尋求下面的幫助。xml多對多使用linq加入

我有很多的XML文件一對多的關係如下:

<ShowRoom> 
    <Cars> 
    <Car id="1" number="001" name="MyCar" > 
     <Parts> 
     <Part id="1" /> 
     <Part id="2" /> 
     </Parts> 
    </Car> 
    <Car id="2" number="002" name="YourCar" > 
     <Parts> 
     <Part id="2" /> 
     <Part id="3" /> 
     <Part id="4" /> 
     </Parts> 
    </Car> 
    </Cars> 
    <Parts> 
    <Part id="1" name="Tyre" active="true"/> 
    <Part id="2" name="Window" active="true"/> 
    </Parts> 
</ShowRoom> 

對應於物體遵循

public class Car 
{ 
    private int _id; 
    public int Id 
    { 
     get { return _id; } 
     set { _id = value; } 
    } 

    private string _number; 
    public string Number 
    { 
     get { return _number; } 
     set { _number = value; } 
    } 

    private string _name; 
    public string Name 
    { 
     get { return _name; } 
     set { _name = value; } 
    } 

    private List<Parts> _listParts; 
    public List<Parts> ListParts 
    { 
     get { return _listParts; } 
     set { _listParts = value; } 
    } 
} 

什麼我想是讀取XML和汽車之間的連接部件,所以我會得到車對象及其所有部件詳細

IEnumerable<XElement> xCar = xdoc.Element("ShowRoom").Element("Cars").Elements("Car"); 
       IEnumerable<XElement> xPart = xdoc.Element("ShowRoom").Element("Parts").Elements("Part"); 
       IEnumerable<Car> car = xCar.Join(
        xPart, 
        c => c.Element("Parts").Element("Part").Attribute("id").Value, 
        p => p.Attribute("id").Value, 
        (c, p) => 
        new Cars 
        { 
         Id = int.Parse(c.Attribute("id").Value), 
         Number = (string)c.Attribute("number").Value, 
         Name = (string)c.Attribute("name").Value, 

         ListParts = 
         { 
           new Parts 
            { 
             Id = int.Parse(p.Attribute("id").Value), 
             Name = (string)p.Attribute("name").Value, 
             Active = bool.Parse(p.Attribute("active").Value) 
            } 
         } 
        }); 

這裏的問題是,我不知道怎麼去針對汽車的所有部件,如在上面的代碼中這顯然是錯誤

     ListParts = 
         { 
           new Parts 
            { 
             Id = int.Parse(p.Attribute("id").Value), 
             Name = (string)p.Attribute("name").Value, 
             Active = bool.Parse(p.Attribute("active").Value) 
            } 

因此,如何把它做使用相同的上面的代碼,或是否有這樣做的其他的好辦法,與我分享。

謝謝。

+0

只是在這裏,爲什麼設置私有屬性,當你創建的公共方法,允許調用者無論如何獲取和設置這些proprties,你應該讓他們公開,如果你的意圖是讓打電話給執行get&set 。 – Derek

+0

@JonSkeet道歉,如果我混淆的東西。 – Derek

回答

2

我強烈建議建立零部件的字典,然後建立汽車名單:​​

Dictionary<int, Part> partsById = doc.Root 
    .Element("Parts") 
    .Elements("Part") 
    .Select(p => new Parts 
      { 
       Id = (int) p.Attribute("id"), 
       Name = (string) p.Attribute("name"), 
       Active = (bool) p.Attribute("active") 
      }) 
    .ToDictionary(part => part.Id); 

請注意,我已經改名PartsPart,因爲每個僅代表單個零件對象 - 我已經刪除了所有解析,使用XAttribute上的顯式轉換。

然後,當你建立你的汽車名單,你可以使用:

... 
ListParts = c.Element("Parts") 
      .Elements("Part") 
      .Select(p => partsById[(int) p.Attribute("Id")]) 
      .ToList(); 

你也應該考慮自動實現的屬性,這將減少你的Car類只是幾行代碼:

public class Car 
{ 
    public int Id { get; set; } 
    public string Number { get; set; } 
    public string Name { get; set; } 
    public List<Parts> ListParts { get; set; } 
} 
+0

感謝Jon Skeet,它的奇妙。我不能投票,因爲它需要一些聲譽。謝謝Derek的反饋。 – toughcanny

+0

@JonSkeet道歉,如果我引起了困惑,我建議你的班級應該看起來像約翰如何在他的設置這裏,就這樣。 – Derek

+0

@Derek:值得理解的是,這與*海報的原始代碼完全等價。它仍然有私人領域和公共財產。在這方面沒有什麼改變 - 它只是一個更簡單的源代表。 –