将包含多个元素的XML反序列化为单个C#对象

将包含多个元素的XML反序列化为单个C#对象,c#,xml,serialization,C#,Xml,Serialization,我需要反序列化如下所示的XML文档: <Root> <Items> <Item> <ItemHeader Attr1="A" Attr2="B" Attr3="C" /> <ItemDetails Attr4="D" Attr5="E" /> </Item> ... </Items> </Root> [Serializable, XmlRoot

我需要反序列化如下所示的XML文档:

<Root>
  <Items>
    <Item>
      <ItemHeader Attr1="A" Attr2="B" Attr3="C" />
      <ItemDetails Attr4="D" Attr5="E" />
    </Item>
    ...
  </Items>
</Root>
[Serializable, XmlRoot("Item")]
Public class MyItem
{
  [XmlAttribute("Attr1")]
  public string Attr1 { get; set; }
  [XmlAttribute("Attr5")]
  public string Attr5 { get; set; }
}
我使用以下代码执行反序列化:

XDocument doc;
XElement rootElem = doc.Element("Root");

foreach (XElement xe in rootElem.Descendants("Item"))
{
  MyItem item = new MyItem();
  XmlSerializer xmlSerializer = new XmlSerializer(typeof(MyItem));
  XmlReader xRdr = xe.CreateReader();
  item = (MyItem)xmlSerializer.Deserialize(xRdr);
}
但是,所有元素都不会复制到对象实例中

这可行吗?我需要反序列化每个子元素吗


谢谢

问题是您接收的xml数据与
MyItem
的序列化属性不匹配,架构不同。有多种方法可以解决这个问题,但我想最快、最肮脏的解决方案是提取你感兴趣的部分:

  XDocument doc = XDocument.Load (@"Your.xml"); 
  XElement rootElem = doc.Element("Root");
  XElement itemsElem = rootElem.Element("Items");
  foreach (XElement xe in itemsElem.Elements("Item"))
  {
    MyItem item = new MyItem()
    {
      Attr1 = xe.Element("ItemHeader").Attribute("Attr1").Value,
      Attr5 = xe.Element("ItemDetails").Attribute("Attr5").Value
    }; 
  }

我不确定是否有一种方法可以通过属性使用默认的XML序列化程序,而不使用整个类结构来匹配您的XML—因此
ItemHeader
ItemDetails
将需要它们自己的类

但是,您可以实现
IXmlSerializable
接口,这样您就可以完全定制—如果您必须保持MyItem的结构不变的话

static void Main(string[] args)
{
    XmlSerializer myItemSerializer = new XmlSerializer(typeof(MyItem));

    var xmlDoc = XDocument.Parse(@"<Item>
                                <ItemHeader Attr1=""A"" Attr2=""B"" Attr3=""C"" />
                                <ItemDetails Attr4=""D"" Attr5=""E"" />
                            </Item>");

    using (var reader = xmlDoc.CreateReader())
    {
        MyItem myItem = (MyItem)myItemSerializer.Deserialize(reader);
    }


    Console.Read();
}

[Serializable, XmlRoot("Item")]
public class MyItem : IXmlSerializable
{
    [XmlAttribute("Attr1")]
    public string Attr1 { get; set; }
    [XmlAttribute("Attr5")]
    public string Attr5 { get; set; }

    public System.Xml.Schema.XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(System.Xml.XmlReader reader)
    {
        reader.ReadStartElement("Item");

        do
        {
            switch (reader.Name)
            {
                case "ItemHeader":
                    Attr1 = reader.GetAttribute("Attr1");
                    reader.Read();
                    break;
                case "ItemDetails":
                    Attr5 = reader.GetAttribute("Attr5");
                    reader.Read();
                    break;
                default:
                    throw new XmlException(String.Format("{0} was not expected", reader.Name));
            }
        } while (reader.Name != "Item");


        reader.ReadEndElement();
    }

    public void WriteXml(System.Xml.XmlWriter writer)
    {
        writer.WriteStartElement("ItemHeader");
        writer.WriteAttributeString("Attr1", Attr1);
        writer.WriteEndElement();
        writer.WriteStartElement("ItemDetails");
        writer.WriteAttributeString("Attr5", Attr5);
        writer.WriteEndElement();
    }
}
static void Main(字符串[]args)
{
XmlSerializer myItemSerializer=新的XmlSerializer(typeof(MyItem));
var xmlDoc=XDocument.Parse(@)
");
使用(var reader=xmlDoc.CreateReader())
{
MyItem MyItem=(MyItem)myItemSerializer.Deserialize(reader);
}
Console.Read();
}
[可序列化,XmlRoot(“项”)]
公共类MyItem:IXmlSerializable
{
[XmlAttribute(“Attr1”)]
公共字符串Attr1{get;set;}
[XmlAttribute(“Attr5”)]
公共字符串Attr5{get;set;}
public System.Xml.Schema.XmlSchema GetSchema()
{
返回null;
}
public void ReadXml(System.Xml.XmlReader)
{
reader.ReadStartElement(“项目”);
做
{
开关(reader.Name)
{
案例“ItemHeader”:
Attr1=reader.GetAttribute(“Attr1”);
reader.Read();
打破
案例“项目详情”:
Attr5=reader.GetAttribute(“Attr5”);
reader.Read();
打破
违约:
抛出新的XmlException(String.Format(“{0}不应出现”,reader.Name));
}
}while(reader.Name!=“Item”);
reader.ReadEndElement();
}
public void WriteXml(System.Xml.XmlWriter)
{
writer.writeStarElement(“ItemHeader”);
WriteAttributeString(“Attr1”,Attr1);
writer.writeedelement();
writer.writeStarElement(“项目详细信息”);
WriteAttributeString(“Attr5”,Attr5);
writer.writeedelement();
}
}

奇怪的是,我发现Attr1设置正确,仍然在Main中,但不是Attr5。通过调试,正在读取和设置Attr5,但没有将其值保留在MyItem类作用域之外。上述注释不完全正确:)我的实际示例稍微复杂一些,就是来自次要元素的属性在读取时没有“粘滞”的示例。抱歉,我无法用您发布的原始XML或上面的内容复制这些内容。注意:如果找不到GetAttribute,它不会失败,它只会返回null——它也是区分大小写的。如果不是这样的话,我需要你的XML。谜团解决了。我在ItemDetails中嵌套了另一个元素,显然,当读者点击ItemDetails的关闭按钮时,读者只是将其视为ItemDetails,因为没有附加到关闭按钮的属性,所以这些属性被分配为空值。啊。我想reader.ReadOuterXml()而不是reader.Read()可能是避免这种情况的更好/更安全的选择。感谢您的回答,尽管这是一种可能的解决方案,但我还是使用上面Steve的解决方案,因为我可以将类和属性的内部知识与处理代码分开。