【问题标题】:Efficient Way to Parse XML解析 XML 的有效方法
【发布时间】:2013-01-26 06:45:59
【问题描述】:

我发现确定解析某些 XML 的最佳方法令人费解。似乎它们有很多可能的方法,但没有一种方法能真正吸引我。

我目前的尝试看起来像这样:

XElement xelement = XElement.Parse(xmlText);
var name = xelement.Element("Employee").Attribute("name").Value;

所以,这行得通。但如果缺少“Employee”元素或“name”属性,则会引发异常。我不想抛出异常。

探索一些examples available online,我看到这样的代码:

XElement xelement = XElement.Load("..\\..\\Employees.xml");
IEnumerable<XElement> employees = xelement.Elements();
Console.WriteLine("List of all Employee Names :");
foreach (var employee in employees)
{
    Console.WriteLine(employee.Element("Name").Value);
}

这似乎会遇到完全相同的问题。如果“Name”元素不存在,Element() 返回null,调用Value 属性时出错。

我需要一些块,比如上面的第一个代码 sn-p。有没有一种简单的方法可以让它工作并且在某些数据丢失时不抛出异常?

【问题讨论】:

  • 你可以使用 XPATH。缺少元素没有问题,我个人认为这是一个巨大的优势。 /Employee/@name/text() 将选择名称,如果未找到则为 null。但这不是 XElement 也不是 Xlinq。

标签: c# .net xml linq-to-xml


【解决方案1】:

您可以结合使用从XAttributestring 的显式字符串转换(如果操作数为null,则返回null)和FirstOrDefault 方法:

var name = xelement.Elements("Employee")
                   .Select(x => (string) x.Attribute("name"))
                   .FirstOrDefault();

如果不存在这样的元素(因为序列将为空,FirstOrDefault() 将返回 null)或者存在没有属性的元素(在这种情况下,您将得到一个带有 null 元素的序列,FirstOrDefault 将返回)。

【讨论】:

    【解决方案2】:

    我经常在这种情况下使用扩展方法,因为即使引用为空,它们也能正常工作。我使用了 Anders Abel 在 2012 年初发表的非常好的博文中的扩展方法的略微修改版本'Null Handling with Extension Methods':

    public static class XElementExtension
    {
        public static string GetValueOrDefault(this XAttribute attribute,
                                               string defaultValue = null)
        {
            return attribute == null ? defaultValue : attribute.Value;
        }
    
        public static string GetAttributeValueOrDefault(this XElement element,
                                                        string attributeName, 
                                                        string defaultValue = null)
        {
            return element == null ? defaultValue : element.Attribut(attributeName)
                                                    .GetValueOrDefault(defaultValue);
        }
    }
    

    如果你想在元素或属性不存在的情况下返回'null':

    var name = xelement.Element("Employee")
                       .GetAttributeValueOrDefault("name" );
    

    如果要在元素或属性不存在的情况下返回默认值:

    var name = xelement.Element("Employee")
                        .GetAttributeValueOrDefault("name","this is the default value");
    

    在你的 for 循环中使用:

    XElement xelement = XElement.Load("..\\..\\Employees.xml");
    IEnumerable<XElement> employees = xelement.Elements();
    Console.WriteLine("List of all Employee Names :");
    foreach (var employee in employees)
    {
        Console.WriteLine(employee.GetAttributeValueOrDefault("Name"));
    }
    

    【讨论】:

      【解决方案3】:

      您总是可以使用 XPath:

      string name = xelement.XPathEvaluate("string(Employee/@name)") as string;
      

      这将是属性的值,如果 Employee@name 不存在,则为 null

      对于迭代示例:

      foreach (XNode item in (IEnumerable)xelement.XPathEvaluate("Employee/Name"))
      {
           Console.WriteLine(item.Value);
      }
      

      XPathEvaluate() 只会在此处选择有效节点,因此您可以放心item 将始终为非空。

      【讨论】:

        【解决方案4】:

        这一切都取决于您从 XML 中提取数据后要如何处理数据。

        您最好查看专为 XML 处理而设计的语言,例如 XSLT 和 XQuery,而不是使用 C# 之类的语言,这些语言不是(尽管 Linq 为您提供了一些混合的东西)。使用 C# 或 Java,您总是需要做很多工作来应对 XML 如此灵活的事实。

        【讨论】:

        • 好吧,如果我所做的只是解析 XML,我可能会考虑您的建议,但请放心,情况并非如此。不太明白为什么这取决于我对数据的处理方式。我只是想获得价值。
        【解决方案5】:

        使用原生 XmlReader。如果您的问题是读取大型 XML 文件而不是允许 XElement 构建对象表示,您可以构建类似 Java SAX 解析器流式传输 XML

        例如: http://www.codeguru.com/csharp/csharp/cs_data/xml/article.php/c4221/Writing-XML-SAX-Parsers-in-C.htm

        【讨论】:

          猜你喜欢
          • 2010-10-11
          • 2013-01-09
          • 2021-01-22
          • 2012-04-22
          • 1970-01-01
          • 2014-04-15
          • 1970-01-01
          • 2013-01-25
          • 2011-08-22
          相关资源
          最近更新 更多