2014-02-28 74 views
3

所以,如果我有3个不同的文件,其中包含非常长和复杂的xml(我在这里缩写),但只是根元素名称是不同的(不是真的随机,但我宁愿不重复类同一XML):将部分xml反序列化为类

文件1

<?xml version="1.0"?> 
<somerootname1> 
    <car> 
    <make>honda</make> 
    <model>civic</model> 
    </car> 
</somerootname1> 

文件2

<?xml version="1.0"?> 
<somerootname2> 
    <car> 
    <make>honda</make> 
    <model>civic</model> 
    </car> 
</somerootname2> 

文件3

<?xml version="1.0"?> 
<somerootname3> 
    <car> 
    <make>honda</make> 
    <model>civic</model> 
    </car> 
</somerootname3> 

因为XmlRootAttributeAllowMultiple=false我不能创建一个类来表示以前的xml。

重复“XmlRootAttribute”属性

[XmlRoot(ElementName="somerootname1")] 
[XmlRoot(ElementName="somerootname2")] 
public class Root 
{ 
    public Automobile Car { get; set; } 

} 

public class Automobile 
{ 
    public string Make { get; set; } 
    public string Model { get; set; } 
} 

我想我也许能偷偷摸摸抢正是我需要的元素和反序列化:

var xDoc = XDocument.Parse("myfile.xml"); 

var xCar = xDoc.Root.Descendants() 
    .FirstOrDefault(d => d.Name.LocalName.Equals("car")) 

var serializer = new XmlSerializer(typeof(Automobile)) 
using (var reader = xml.CreateReader()) 
{ 
    result = (Automobile)serializer.Deserialize(reader); 
} 

不过的结果在InvalidOperationException

XML文档中存在错误(0,0)。

随着的InnerException:

<车>是没有预料到。

这似乎很不好意思;重命名根元素,然后反序列化取元素并以<?xml>为标签前缀。还有其他建议吗?

回答

1

你已提取的<car>节点,但你还是从文档的根节点的反序列化。这就是为什么这个例外表明它期望<car>节点。对我来说,以下工作:

[XmlRoot("car")] 
public class Automobile 
{ 
    [XmlElement("make")] 
    public string Make { get; set; } 
    [XmlElement("model")] 
    public string Model { get; set; } 
} 

序列化从<car>

var xCar = xDoc.Root.Descendants() 
    .FirstOrDefault(d => d.Name.LocalName.Equals("car")); 

var serializer = new XmlSerializer(typeof(Automobile)); 
using (var reader = xCar.CreateReader()) 
{ 
    var result = (Automobile)serializer.Deserialize(reader); 
    Console.WriteLine(result.Make); 
    Console.WriteLine(result.Model); 
} 
+1

由于缺乏关于XML名称空间的知识,我发现这是名称空间也导致了一个额外的错误与相同的描述:(。 –

1

我没有想出这只是调整了它的一些,原来是:Deserialize XML To Object using Dynamic

不知道这是否是你所需要的东西,但它可以让你抢从XML的价值和把它们放进你的班级。如果在一个xml文档中有多个汽车,它也可以针对数组或集合进行调整。

您需要添加:

using System.Dynamic; 
using System.Xml.Linq; 


    protected Car ParseXml(Car NewCar) {   
     string xml = "<?xml version=\"1.0\"?><somerootname1> <car> <make>honda</make> <model>civic</model> </car></somerootname1>";    
     dynamic car = DynamicXml.Parse(xml);    
     NewCar.Make = car.car.make; 
     NewCar.Model = car.car.model; 
     return NewCar; 
    } 

[Serializable] 
public partial class Car 
{ 
    public Car() { } 

    public string Make { get; set; } 

    public string Model { get; set; } 
} 


public class DynamicXml : DynamicObject 
{ 
    XElement _root; 
    private DynamicXml(XElement root) 
    { 
     _root = root; 
    } 

    public static DynamicXml Parse(string xmlString) 
    { 
     return new DynamicXml(XDocument.Parse(xmlString).Root); 
    } 

    public static DynamicXml Load(string filename) 
    { 
     return new DynamicXml(XDocument.Load(filename).Root); 
    } 

    public override bool TryGetMember(GetMemberBinder binder, out object result) 
    { 
     result = null; 

     var att = _root.Attribute(binder.Name); 
     if (att != null) 
     { 
      result = att.Value; 
      return true; 
     } 

     var nodes = _root.Elements(binder.Name); 
     if (nodes.Count() > 1) 
     { 
      result = nodes.Select(n => new DynamicXml(n)).ToList(); 
      return true; 
     } 

     var node = _root.Element(binder.Name); 
     if (node != null) 
     { 
      if (node.HasElements) 
      { 
       result = new DynamicXml(node); 
      } 
      else 
      { 
       result = node.Value; 
      } 
      return true; 
     } 

     return true; 
    } 
} 
+0

因为XML具有数百个节点,它会更容易做到这一点与Linq2Xml然后更新ParseXml方法(这对我来说似乎更令人费解)。 –

+0

@ErikPhilips这是有道理的,如果你正在处理与许多不同的节点名称的巨大的XML消息。我解析了很多xml,但是已经从xsds构建了类,所以xml可以很好地反序列化到我的对象中。如果我在我的xml中获得额外的元素,他们会在deserilization期间被忽略。无论如何,就像我说的,我不确定它是否适合你。 – Popo