2012-12-15 91 views
2

我是新來的linq to Xml。
我有一個遞歸的方法,作爲參數XElement root應該保持XML數據的方式,它將代表給定遞歸深度的相關子樹根。通過遞歸動態構建Xml

void recursiveMethod(XElement root);
更具體地講,也看看這個XML例子:

<start> 
     <Class> 
      <Worker> 
       <Name> Dan </Name> 
       <Phone> 123 </Phone> 
       <Class> 
         <Address> 
          <Street> yellow brick road </Street> 
          <Zip Code> 123456 </Zip Code> 
         </Address> 
       </Class> 
      </Worker> 
     </Class> 
... 
</start>  

你可以想像,Name是值類型,而Address是一類參考。
Xml信息應該通過反射動態添加(從上到下的方法)。

爲了使長話短說想象,我在調查Worker類的中間,達到Address類,並希望「鑽」,所以我想打電話給我遞歸方法與子節點的正確的參考當前的Worker類作爲新的XElement根,因此我將能夠通過下面的Address類遞歸深度中的反射找到它。

請注意,此引用應該是XElement類型。

我該怎麼做?

編輯:如果你有做這一切的東西的另一個想法,但不與XElement我會很高興聽到還有,雖然我與XElement參數更喜歡它。

另一個問題
我已經開始實施它在一個簡單的方式想通過各個領域的迭代(字段信息[]的變量),如果我有encounterd值類型(IsValueType)我在做類似

root.Add(new XElement("Field", 
         new XElement("Type", ...), 
         new XElement("Variable Name", ...), 
         new XElement("Value", ...)));  

所以,只是一般知識:
1.是否有一種方式來獲得它的decendants節點的只是參考,以便在更低的遞歸級別我就可以做另外root.Add (...)如上所述,但是這個根將是對前一個根的孩子的引用? (這意味着在不使用Linq語法的情況下執行整個操作)

2.我設法通過反射獲得私有字段值,而無需使用屬性,是否有問題?我是否應該總是通過反思中的屬性來獲取價值?

回答

5

這個擴展方法所要求的格式建立的XElement:

public static class Extensions 
{ 
    public static XElement ToXml<T>(this T obj) 
    { 
     Type type = typeof(T); 

     return new XElement("Class", 
        new XElement(type.Name, 
         from pi in type.GetProperties() 
         where !pi.GetIndexParameters().Any() 
         let value = (dynamic)pi.GetValue(obj, null) 
         select pi.PropertyType.IsPrimitive || 
           pi.PropertyType == typeof(string) ? 
           new XElement(pi.Name, value) : 
           Extensions.ToXml(value) 
         ) 
        ); 
    } 
} 

這裏會發生什麼:

  • 我們得到傳遞的對象的公共屬性(可以添加的BindingFlags過濾性能)。
  • 接下來我驗證屬性是否有索引參數並跳過這些屬性。
  • 接下來我得到屬性值爲dynamic對象。這很重要,否則在遞歸調用ToXml<T>方法期間,屬性值類型將被推斷爲object
  • 我檢查屬性類型是原始類型(int,byte,long,single,double等)還是字符串
  • 對於原始類型,我們使用屬性值編寫元素。對於其他類型的(複雜),我們遞歸地開始建設的XElement

用法:

Worker worker = new Worker() 
{ 
    Name = "Serge", 
    Phone = "911", 
    Address = new Address() { Street = "Elm street", ZipCode = 666 } 
}; 

XElement xml = worker.ToXml(); 

結果:

<Class> 
    <Worker> 
    <Name>Serge</Name> 
    <Phone>911</Phone> 
    <Class> 
     <Address> 
     <Street>Elm street</Street> 
     <ZipCode>666</ZipCode> 
     </Address> 
    </Class> 
    </Worker> 
</Class> 

你應該小心的情況下,當兩個對象是指每個其他(在這種情況下會發生無限遞歸)

在這種情況下,你可以使用類似字典或HashSet的存儲已經存在在你的XML中的所有對象:

Type type = obj.GetType(); 
if (set.Contains(obj)) 
    return new XElement("Class", new XAttribute("name", type.Name)); 
set.Add(obj); 
return new XElement("Class", ...); 
+0

好,謝謝,你將如何解決這樣的問題,當兩個物體相互引用,而遞歸? – JavaSa

+0

@JavaSa好吧,我認爲在Dictionary中存儲所有對象可以幫助解決這個問題 - 在插入class元素之前,只需驗證您是否已經處理了該對象 –

+0

太棒了!因爲我想保存一張地圖,非常感謝你! 我想學習這個新的SQL,就像你寫的語法(Linq)。 如果我需要更多的說明,我會寫在這裏 – JavaSa