【问题标题】:How to iterate through an XDocument, getting complete XML structure, object by object?如何遍历 XDocument,逐个对象获取完整的 XML 结构?
【发布时间】:2015-12-16 17:29:00
【问题描述】:

我有一个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 中的人员记录/节点转换为业务实体对象 (POCO)。 因此,我必须一次遍历一个 Person 节点,然后解析各个值。最后一点本身很有趣,但首先我必须获取实际的 Person 记录。我遇到的问题是,如果我按单个节点进行选择(在 XmlDocoment 中使用 XmlList)。

我最终按名称聚合所有字段。我担心如果其中一个人员节点不完整,甚至丢失,然后当我通过并将字段聚合到业务对象时我不知道丢失了哪个。我会尝试验证 - 请参阅问题 2。

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

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

选项 1:

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

这为我提供了 2 个人记录(正确),每个记录都是字符串化的完整 XML 文档 - 格式化为 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 阿德莱德 5000ICPR08 8888 8888041 888 999111111curly@stooge.comE

再说一遍,用处不大。

问题 2

我可以很容易地验证XDocument,MSDN 上有一些很好的例子,但我想知道如何标记错误记录。理想情况下,我希望能够即时将好的记录过滤到新的XDocument 中,而将旧记录留在后面。这可能吗?

【问题讨论】:

    标签: c# linq-to-xml


    【解决方案1】:

    问题在于您只是将元素打印为字符串。您需要编写代码将XElement&lt;Person&gt; 转换为您的业务对象。诚然,我期望改为写出完整的 XML - 你确定你没有打印出 XElement.Value(它连接所有后代文本节点)吗?

    (我不确定您的第二个问题的答案 - 我建议您在这里将其作为一个单独的问题提出,这样我们就不会在一页中得到混合的答案。)

    【讨论】:

    • 道歉 - 是的,我正在使用 Xelement.value - 至少对于第二个示例。 (这里很晚,我很累)。问题是我不想连接后代值 - 我需要单独组织它们,但我确实想最初选择它们,以便我可以轻松地将它们组织为单个对象。然后将它们组织起来并进一步拆分,但我似乎无法在这个级别上一一列举。
    • 我正在使用:foreach(xDoc.Descendants("Person") 中的 XElement 元素){ Console.WriteLn(element.value);这给了我一个连接的字符串。
    • @MtTumbledown:是的,可以。不要使用 Value 属性 - 单独询问子元素。访问 XElement 上的 Value 属性连接后代文本节点,这就是它的本意。
    • 当然 - 我想没有快速的方法 - 在请求每个子元素时有一个硬嫁接的元素 - 可能是节点 ID。我希望有一些 3.5 LINQ 支持可以自动用子元素填充结构。谢谢!
    • 我能做到。它给了我一个相当有用的列表,每个节点描述后跟它的值: IEnumerable nodeList = element.DescendantNodes(); foreach (XNode xn in nodeList) { Console.WriteLine("name:" + xn); }
    【解决方案2】:

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

    有两种方法可以做到这一点。

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

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

    第二种解决方案还可以让您轻松过滤“不良”记录。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-23
      • 1970-01-01
      相关资源
      最近更新 更多