2012-09-02 17 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

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