如何在流式传输XML文档时返回强类型对象而不是XElements

时间:2016-10-14 09:32:24

标签: c# xml linq xsd linq-to-xml

我希望能够从流式传输XML文档的代码返回强类型对象而不是XElements。说有问题的XML文档是:

<?xml version="1.0" encoding="utf-8" ?>
<People>
  <Person>
    <FirstName>John</FirstName>
    <LastName>Smith</LastName>
  </Person>
  <Person>
    <FirstName>Adam</FirstName>
    <LastName>Smith</LastName>
  </Person>
  <Person>
    <FirstName>Jane</FirstName>
    <LastName>Smith</LastName>
  </Person>
</People>

目前,我的读者代码如下所示:

public class PeopleReader
{
    public static IEnumerable<XElement> StreamPerson(string path)
    {
        using (XmlReader rdr = XmlReader.Create(path))
        {
            rdr.MoveToContent();

            while (rdr.Read())
            {
                if (rdr.NodeType == XmlNodeType.Element && rdr.Name == "Person")
                {
                    XElement item = XElement.ReadFrom(rdr) as XElement;

                    if (item != null)
                        yield return item;
                }
            }                  
        }
    }
}

当前的调用代码是:

// Current implementation
foreach (var person in PeopleReader.StreamPerson(@"...\People.xml"))
{
    MessageBox.Show(person.Element("LastName").Value);
}

我必须致电.Element.Value

我希望调用代码的是:

// Required implementation where person is returned as a strongly typed obj.
foreach (var person in PeopleReader.StreamPerson(@"...\People.xml"))
{
    MessageBox.Show(person.LastName);
}

据我所知,我可以使用xsd.exe生成.XSD文件,然后生成.cs文件,但我不清楚实际步骤。另外,我不确定如何更改我的阅读器代码以返回生成的类,以便调用代码接收强类型对象进行枚举?也就是说,我如何从XElements转到强类型类 - Casting似乎不是一个选项?

我正在使用VS2015,如果可能的话,更愿意不必使用第三方工具。

非常感谢提前。

2 个答案:

答案 0 :(得分:1)

而不是返回IEnumerable<XElement>创建类型Person并返回IEnumerable<Person>

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

然后返回一个新实例:

public static IEnumerable<XElement> StreamPerson(string path)
{
    using (XmlReader rdr = XmlReader.Create(path))
    {
        rdr.MoveToContent();

        while (rdr.Read())
        {
            XElement item = XElement.ReadFrom(rdr) as XElement;
            if (item != null)
            {
                yield return new Person
                {
                    FirstName = item.Element("FirstName")?.Value,
                    LastName = item.Element("LastName")?.Value
                };
            }
        }
    }
}

更新 - 在了解到这些xml代表较大类的“轻量级”版本之后,我建议将这些类的源代码引用到当前项目中:

为包含轻量级属性的较大类创建基类。这样你就没有代码重复,可以从一个代码转换为另一个代码。

public class PersonBase
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class Person : PersonBase
{
    public string OtherProperty { get; set; }
}

然后使用我上面的方法或Charles

建议的方法来实例化对象

答案 1 :(得分:1)

我建议您使用XmlSerializer

var serializer = new XmlSerializer(typeof(Person));

using (var rdr = XmlReader.Create(path))
{
    rdr.MoveToContent();

    while (rdr.Read())
    {
        if (rdr.NodeType == XmlNodeType.Element && rdr.Name == "Person")
        {
            yield return (Person) serializer.Deserialize(rdr);
        }
    }
}

您的课程定义如下:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

有关正常工作的演示,请参阅this fiddle

要为XML生成类,可以使用xsd.exe(对于XML或XML Schema,如果有的话),或者可以使用{将XML样本复制并粘贴到Visual Studio中{1}}。请参阅this related question