2012-09-02 46 views
3

我想嘗試從我編寫的XML閱讀器返回一個對象,以處理將具有部分未知結構的文件。從未知的xml中創建匿名對象

以下是XML的示例。

<xml> 
    <strings> 
    <Home> 
     <Index> 
     <PreWrapper> 
      <Left> 
      <Title>Blah</Title> 
      <Body>Lorem ipsum dolor sit amet, consec tetuer adipiscing elit. Praesent vestibulum molestie lacus. Aenean nonummy hendrerit mauris. Phasellus porta. Fusce suscipit</Body> 
      <LinkText>read more</LinkText> 
      <LinkUrl>#</LinkUrl> 
      </Left> 
      <Center> 
      <Title>Exploit your ideas</Title> 
      <Body>Lorem ipsum dolor sit amet, consec tetuer adipiscing elit. Praesent vestibulum molestie lacus. Aenean nonummy hendrerit mauris. Phasellus porta. Fusce suscipit</Body> 
      <LinkText>read more</LinkText> 
      <LinkUrl>#</LinkUrl> 
      </Center> 
      <Right> 
      <Title>Grow your business</Title> 
      <Body>Lorem ipsum dolor sit amet, consec tetuer adipiscing elit. Praesent vestibulum molestie lacus. Aenean nonummy hendrerit mauris. Phasellus porta. Fusce suscipit</Body> 
      <LinkText>read more</LinkText> 
      <LinkUrl>#</LinkUrl> 
      </Right> 
     </PreWrapper> 
     </Index> 
    </Home> 
    </strings> 
    <config> 
    <Home> 
     <Index> 
     <ShowPreWrapper>True</ShowPreWrapper> 
     </Index> 
    </Home> 
    </config> 
</xml> 

我希望能夠給剛剛與我的讀者

var left = reader.GetObject("xml/strings/Home/Index/PreWrapper/Left"); 

打電話,我希望它返回一個匿名對象(或動態的對象,但我不知道很多關於那些)看起來像

left.Title 
left.Body 
left.LinkText 
left.LinkUrl 

var xml = reader.GetObjcet("xml"); 

,並能正確潛入像

xml.strings.Home.Index.... 

但我只是無法弄清楚如何創建該對象。 這甚至可能嗎?

+1

什麼是未知的XML的結構? – psubsee2003

+0

我可以在名爲'slideshow'的索引下添加另一個節點,或者我可以在每個預包裝器部分 –

+0

中添加一個'pictureUrl'字符串,但是您會獲得這些項目,還是4個標籤(Title,Body,LinkTest, LinkUrl)所有你關心的? – psubsee2003

回答

5

我認爲你可以使用ExpandoObject類逼近這一點,但它很可能有更好的方法來做到這一點(如使用更鬆散類型的語言,使用字典等)

有當然沒有內置.NET BCL來做到這一點。

編輯:我最近發現了這個,它可能適用於這種情況:ElasticObject

+0

ExpandoObject看起來像它可以工作不值得打擾的點,但我認爲它沒有辦法做到這一點的共識。 –

2

你不能這樣做,因爲C#是一種強類型語言。也許它可能以某種方式使用動態C#,但我不太瞭解它。但作爲解決方案,您可以將XML解析爲字典。

0

你可以用LINQ to XML來完成如果你知道某個元素或屬性的名字。對於這個例子,你知道將會有Left元素。

使用這個LINQ聲明

XDocument document = XDocument.Load("c:\\tmp\\test.xml"); 
var left = from i in document.Descendants("Left") 
      select new { Title = i.Element("Title").Value, 
         Body = i.Element("Body").Value, 
         LinkText = i.Element("LinkText").Value, 
         LinkUrl = i.Element("LinkUrl").Value 
         }; 

現在你可以做到這一點,因爲在你的問題描述:

Left.Title 
Left.Body 
Left.LinkText 
Left.LinkUrl 

如果你不知道有多少元素的Left元素的後代,你可以這樣做:

XDocument document = XDocument.Load("c:\\tmp\\test.xml"); 
var left = from i in document.Descendants("Left") 
      select new { values = i.Elements().ToList() }; 

這給出了一個列表c的枚舉alright values。列表中的每個項目都有一個NameValue屬性,因此您可以檢查它是什麼。

在枚舉打印所有值從第一項的例子:

foreach (var s in left.First().values) 
{ 
    Console.WriteLine(string.Format("{0} has a value of {1}", s.Name, s.Value));    
} 
0

構建類似的東西,一些一個月前,一看,告訴我你的想法:

Objects to XML and back to Dynamics

(我希望我添加了所有內容)。

+0

我很抱歉,但我無法編譯它。也許有些失蹤。我們至少需要一個使用的例子。謝謝! – bluish

0

如果您使用C#4.0,則可以使用動態類型來實現此目的。

要實現自己的動態行爲,只寫從DynamicObject繼承一個類並重寫TryGetMember

public sealed class DynamicXml : DynamicObject 
{ 
    private XElement _xml; 

    private DynamicXml(XElement xml) 
    { 
     _xml = xml; 
    } 

    public override bool TryGetMember(GetMemberBinder binder, out object result) 
    { 
     XElement xml = _xml.Element(binder.Name); 
     if (xml == null) 
     { 
      result = null; 
      return false; 
     } 

     result = new DynamicXml(xml); 

     return true; 
    } 

    public static implicit operator XElement(DynamicXml xml) 
    { 
     return xml._xml; 
    } 

    public static explicit operator DynamicXml(XElement xml) 
    { 
     return new DynamicXml(xml); 
    } 
} 

我從加入到DynamicXmlXElement隱式轉換和XElementDynamicXml顯式轉換。這樣,您就可以輕鬆切換動態和靜態:

XElement root = XDocument.Load("Test.xml").Element("xml"); 

dynamic xml = (DynamicXml)root; 
XElement indexElement = xml.strings.Home.Index; 

UPDATE:

如果你想訪問你可以實現這個屬性的索引屬性:

public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) 
{ 
    if (indexes.Length != 1 || !(indexes[0] is string)) 
    { 
     result = null; 
     return false; 
    } 

    result = _xml.Attribute(indexes[0] as string); 

    return result != null; 
} 

var attr = xml.strings.Home.Index["id"]現在返回第一個Index元素的id屬性。你

也可以使用方法調用的語法不帶參數的返回所有的元素,而不是隻有第一個:

public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) 
{ 
    if (args.Length != 0) 
    { 
     result = null; 
     return false; 
    } 

    result = _xml.Elements(binder.Name); 

    return true; 
} 

var indexes = xml.strings.Home.Index()返回IEnumerable<XElement>。由於您不能在LINQ表達式或lambda表達式中使用動態變量,因此返回IEnumerable<DynamicXml>並不合理。

+0

謝謝,生病看看我能否使用它。 –