【问题标题】:What is the best way to manually parse an XElement into custom objects?将 XElement 手动解析为自定义对象的最佳方法是什么?
【发布时间】:2009-06-04 09:51:21
【问题描述】:

我有一个名为 content 的 XElement 变量,它由以下 XML 组成:

<content>
    <title>Contact Data</title>
    <p>This is a paragraph this will be displayed in front of the first form.</p>
    <form idCode="contactData" query="limit 10; category=internal"/>
    <form idCode="contactDataDetail" query="limit 10; category=internal">
        <title>Contact Data Detail</title>
        <description>This is the detail information</description>
    </form>
</content>

我现在只想遍历每个 1 级节点并将它们解析为对象。回到 C# 2.0,我使用 XmlReader 来执行此操作,检查节点的类型,并相应地解析它。

但是用 LINQ 解析 XML 节点的最佳方法是什么,我希望是这样的:

var contentItems = from contentItem in pageItem.content.DescendantNodes()
                   select new ContentItem
                   {
                       Type = contentItem.Element()
                   };

foreach (var contentItem in contentItems)
{
    switch (contentItem.Type)
    {
        case "title":
            ...(parse title)...
        case "p":
            ...(parse p)...
        case "form":
            ...(parse form)...
    }
}

地点:

public class ContentItem
{
    public string Type { get; set; }
    public string IdCode { get; set; }
    public XElement Content { get; set; }
}

【问题讨论】:

  • 你到底要解析到哪里?例如,当您解析标题时......您希望值“Contact Data”去哪里?
  • 当我解析标题节点时,“联系人数据”将作为 TextBlock 添加到 UserControl 中。当我解析表单节点时,将从数据库中加载 idCode="contactData" 的表单并显示等。

标签: c# xml parsing


【解决方案1】:

必须是XElement吗?我会(手动或通过 xsd.exe)创建映射到元素/属性名称的类 - 并使用 XmlSerializer - 特别是通过 StringReader

        Content content;
        using(StringReader sr = new StringReader(xml))
        using(XmlReader xr = XmlReader.Create(sr)) {
            XmlSerializer ser = new XmlSerializer(typeof(Content));
            content = (Content)ser.Deserialize(xr);
        }

(编辑)

实体类:

[XmlRoot("content")]
public class Content {
    [XmlElement("title")]
    public string Title { get; set; }
    [XmlElement("p")]
    public string Description { get; set; }
    [XmlElement("form")]
    public List<ContentForm> Forms { get; set; }
}    
public class ContentForm {
    [XmlAttribute("idCode")]
    public string Id { get; set; }
    [XmlAttribute("query")]
    public string Query { get; set; }
    [XmlElement("title")]
    public string Title { get; set; }
    [XmlElement("description")]
    public string Description { get; set; }
}

【讨论】:

    【解决方案2】:

    我建议继承 XElement,并为你想要的东西实现属性。 这些属性不应使用支持字段,而应直接与底层 XML 元素一起使用。这样,您将保持对象与 XML 同步。

    【讨论】:

      【解决方案3】:

      使用 XML to LINQ 可以从 XML 中提取特定的数据项,而不是遍历 XML 来寻找找到的内容。

      var results = from node in XmlDocument.SomeContext(...)
                    select new MyType {
                      Prop1 = node.Element("One").Value,
                      Prop2 = node.Element("One").Attributes().Where(
                            a => A.Value.Contains("Foo").Value
                  };
      

      如果需要条件,则可以使用(扩展)方法和任意表达式(null-coalescing operator, ??, 对默认非常有帮助)。

      【讨论】:

      • 那么这是否意味着如果顺序很重要,那么 LINQ 真的不能用于解析 XML 吗?例如,在上面的示例中,重要的是在“p”之前解析“title”,因为这是在 UserControl 中作为 TextBlocks 插入时它们的显示方式。
      • @Edward:可以使用更复杂的 LINQ 表达式或 XPath 检查任意节点关系。但是需要更详细的信息来举例(例如,如果 p 不跟随标题会发生什么?)
      • 这只是一个确定在用户控件上显示什么的 xml,因此 XML 中的项目只是按顺序添加,这意味着例如如果我在解析时无法确定顺序,我将不得不为每个名为的元素添加一个属性,例如displayOrder="1"、displayOrder="2" 等
      • @Edward:LINQ 表达式中的节点将按顺序排列(即,将在 tuen 中为迄今为止匹配的每个节点调用 select 子句),这可以在 select 中清楚地利用(或任何其他XNode 序列的消费者,例如一个 foreach 语句)。也就是说,对于基于流的处理,坚持阅读器(尤其是在它已经工作的地方)可能比转向完全不同的 LINQ to XML 范式更好。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-08
      • 1970-01-01
      • 2018-07-15
      • 2020-04-10
      • 1970-01-01
      • 1970-01-01
      • 2015-12-11
      相关资源
      最近更新 更多