将嵌套的XML元素反序列化为C#类

15

我有以下XML结构(为了简洁而编辑),但我对其没有任何控制权。

<GetVehicles>
    <ApplicationArea>
        <Sender>
            <Blah></Blah>
        </Sender>
    </ApplicationArea>
    <DataArea>
        <Error>
            <Blah></Blah>
        </Error>
        <Vehicles>
            <Vehicle>
                <Colour>Blue</Colour>
                <NumOfDoors>3</NumOfDoors>
                <BodyStyle>Hatchback</BodyStyle>
            <Vehicle>
        </Vehicles>
    </DataArea>
</GetVehicles>

I have the following Class:

[XmlRoot("GetVehicles"), XmlType("Vehicle")]
public class Vehicle
{
    public string Colour { get; set; }
    public string NumOfDoors { get; set; }
    public string BodyStyle { get; set; }
}

我希望能够将XML反序列化为此Vehicle类的单个实例。99%的情况下,XML只应返回单个“Vehicle”元素。如果它包含在“Vehicles”元素内部的多个“Vehicle”元素,则暂时不予处理。

不幸的是,在调用我的Deserialize方法后,XML数据目前没有被映射到我的类属性中;它们被留空了。

为了完整起见,这是我的Deserialize方法:

private static T Deserialize<T>(string data) where T : class, new()
{
    if (string.IsNullOrEmpty(data))
        return null;

    var ser = new XmlSerializer(typeof(T));

    using (var sr = new StringReader(data))
    {
        return (T)ser.Deserialize(sr);
    }
}

我不关心其他更高层的元素,比如“ApplicationArea”、“Error”等。我只对提取“Vehicle”元素内的数据感兴趣。我该如何让它只从XML中反序列化这些数据?

2个回答

12

在Ilya的回答基础上进行优化:

这可以稍微进行优化,因为已经加载了节点:不需要将xml传递到字符串中(使用vehicle.ToString()),只会导致序列化程序必须重新解析它(使用StringReader)。

相反,我们可以直接使用XNode.CreateReader创建一个读取器:

private static T Deserialize<T>(XNode data) where T : class, new()
{
    if (data == null)
        return null;

    var ser = new XmlSerializer(typeof(T));
    return (T)ser.Deserialize(data.CreateReader());
}

如果数据是一个XmlNode,使用XmlNodeReader
private static T Deserialize<T>(XmlNode data) where T : class, new()
{
    if (data == null)
        return null;

    var ser = new XmlSerializer(typeof(T));
    using (var xmlNodeReader = new XmlNodeReader(data))
    {
        return (T)ser.Deserialize(xmlNodeReader);
    }
}

我们可以使用:

var vehicle = XDocument.Parse(xml)
                       .Descendants("Vehicle")
                       .First();

Vehicle v = Deserialize<Vehicle>(vehicle);

是的,这对我很有效,并且我正在使用XmlNode。然而,代码并没有立即起作用。我需要稍微修改一下using中的代码: xmlNodeReader.ReadStartElement(); return (T)ser.Deserialize(xmlNodeReader.ReadSubtree()); - From Orbonia

9
我不了解您问题的全部背景,所以这个解决方案可能不适用于您的领域。但是有一个解决方案是将您的模型定义为以下内容:
[XmlRoot("Vehicle")] //<-- optional
public class Vehicle
{
    public string Colour { get; set; }
    public string NumOfDoors { get; set; }
    public string BodyStyle { get; set; }
}

使用LINQ to XML将特定节点传递给Deserialize方法:

var vehicle = XDocument.Parse(xml)
                       .Descendants("Vehicle")
                       .First();

Vehicle v = Deserialize<Vehicle>(vehicle.ToString());


//display contents of v 
Console.WriteLine(v.BodyStyle);   //prints Hatchback
Console.WriteLine(v.Colour);      //prints Blue
Console.WriteLine(v.NumOfDoors);  //prints 3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接