如何迭代遍历XDocument,逐个获取完整的XML结构对象?

4

我有一个XmlDocument,可以使用XmlNode遍历它,或将其转换为XDocument并通过LINQ遍历。

<Dataset>
    <Person>
        <PayrollNumber>1234567</PayrollNumber>
        <Surname>Smith-Rodrigez</Surname>
        <Name>John-Jaime-Winston Junior</Name>
        <Skills>
            <Skill>ICP</Skill>
            <Skill>R</Skill>
        </Skills>
        <HomePhone>08 8888 8888</HomePhone> 
        <MobilePhone>041 888 999</MobilePhone>
        <Email>curly@stooge.com</Email>
    </Person>
    <Person>
        <PayrollNumber>12342567</PayrollNumber>
        <Surname>Smith-Rodrigez</Surname>
        <Name>Steve</Name>
        <Skills>
            <Skill>Resus</Skill>
            <Skill>Air</Skill>
        </Skills>
        <HomePhone>08 8888 8888</HomePhone> 
        <MobilePhone>041 888 999</MobilePhone>
        <Email>curly@stooge.com</Email>
    </Person>
</Dataset>

问题1

我想将XML中的Person记录/节点转换为业务实体对象(POCO)。 因此,我必须一次迭代一个Person节点,然后解析单个值。这最后一部分本身就很有趣,但首先我必须获取实际的Person记录。我的问题是,如果我按个别节点选择(例如在XmlDocoment中使用XmlList),则会聚合所有字段名称。我担心这样做,因为如果其中一个人节点不完整,甚至缺失,那么当我通过并将字段聚合到业务对象中时,我就不知道哪个字段缺失了。我将尝试验证-请参见问题2。

我意识到可以通过反射来完成这项工作,但我很感兴趣。

我尝试通过Person对象进行迭代:

选项1:

foreach (XObject o in xDoc.Descendants("Person"))
{
    Console.WriteLine("Name" + o);
    // [...]
}

这里有两个人员记录(正确的),每个记录都是一个完整的XML文档字符串化格式,仅为上述XML文档的子集。现在如何将记录拆分成单独的节点或字段,最好不要让此过程过于痛苦?

选项2:

foreach (XElement element in xDoc.Descendants("Person"))
{
    // [...]
}

这会为我获取每个人的XML节点值,全部组成一个字符串,例如:

1234567Smith-RodrigezJohn-Jaime-Winston JuniorLevel 5, City Central Tower 2, 121 King William StNorth Adelaide 5000ICPR08 8888 8888041 888 999111111curly@stooge.comE

但是,它并没有什么用处。

问题2

我可以很容易地验证一个 XDocument,MSDN上有一些很好的例子,但我想知道如何标记错误记录。理想情况下,我希望能够过滤出好的记录到一个新的 XDocument 中,并在原来的文档中留下不良记录。这可能吗?

2个回答

4
问题在于你只是将元素打印为字符串。你需要编写代码将 <Person>XElement 转换为你的业务对象。诚然,我期望完整的 XML 被输出 - 你确定你没有打印出 XElement.Value(它连接了所有后代文本节点)吗?
(对于你的第二个问题,我不确定答案 - 我建议你在这里提出一个单独的问题,以便我们不会在一个页面上得到混合的答案。)

抱歉 - 是的,我正在使用Xelement.value - 至少是对于第二个示例。 (现在已经很晚了,我非常累)。问题是我不想连接后代值 - 我需要单独组织它们,但我确实想最初选择它们所有,以便我可以轻松地将它们组织为一个单一对象。然后是组织它们并进一步拆分它们,但似乎我无法在这个级别枚举它们。 - MtTumbledown
我正在使用以下代码: foreach (XElement element in xDoc.Descendants("Person")) { Console.WriteLn(element.value); } }这将给我一个连接的字符串。 - MtTumbledown
@MtTumbledown:是的,可以这样做。不要使用Value属性-分别请求子元素。在XElement上访问Value属性将连接后代文本节点,这就是它的作用。 - Jon Skeet
当然 - 我想没有快速的方法可以做到这一点 - 请求每个子元素可能需要一些艰苦努力 - 可能是通过节点ID。我希望有一些3.5 LINQ支持,可以自动填充结构与子元素。谢谢! - MtTumbledown
我可以做到这一点。它会给我一个相当有用的列表,其中每个节点描述都跟随着它的值:IEnumerable<XNode> nodeList = element.DescendantNodes(); foreach (XNode xn in nodeList) { Console.WriteLine("name:" + xn); } - MtTumbledown
你不是通过节点ID来请求它,而是通过元素名称来请求它。如果你真的想要,有XML序列化可以为你完成这个操作 - 但除非你使用它,否则你必须自己完成。说实话,使用LINQ to XML会使这个过程变得相当容易。 - Jon Skeet

1

为什么不使用XML反序列化?

有两种方法可以实现。

  • 第一种方法是修改业务对象Person以匹配给定的XML,通过向Person类及其属性添加适当的属性。 XML非常简单,因此如果对象属性与XML节点之间没有1:1匹配,则可能只需更改名称即可。例如,您必须为Skills集合指定[XmlArray("Skills")][XmlArrayItem("Skill)]

  • 第二种方法是将给定的XML转换为与您的Person对象的默认序列化匹配的XML,然后进行反序列化

第二种解决方案还可以让您非常轻松地过滤“错误”的记录。


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