代码之家  ›  专栏  ›  技术社区  ›  Tom

XDocument分析错误

  •  2
  • Tom  · 技术社区  · 8 年前

    多年来,我一直通过API访问数据库,今天进行了更改,但我无法联系所有者。这似乎是一个细微的变化,导致我的代码出现了一个空引用异常。 下载了一个文件,然后我尝试使用 XmlReader 并使用以下代码将其加载到字典中:

    Dictionary<decimal, string> dict = new Dictionary<decimal, string>();
    
    using (var file = File.Open(dir + @"\dxcc_matrix.gz", FileMode.Open))
    {
        using (var zip = new GZipStream(file, CompressionMode.Decompress))
        {
            using (var xmlReader = XmlReader.Create(zip))
            {
                var xd = XDocument.Load(xmlReader); 
    
                dict =    //error occurs here
                xd
                    .Document
                    .Root
                    .Element(XName.Get("entities", "http://www.clublog.org/cty/v1.0"))
                    .Elements(XName.Get("entity", "http://www.clublog.org/cty/v1.0"))
                    .ToDictionary(
                        x => (decimal)x.Element(XName.Get("adif", "http://www.clublog.org/cty/v1.0")),
                        x => x.Element(XName.Get("name", "http://www.clublog.org/cty/v1.0")).Value);
            }
        }
    }
    

    部分XML文件如下所示:

    <clublog date="2018-02-13T21:30:11+00:00" 
            xmlns="https://clublog.org/cty/v1.0">
    <entities>
    <entity>
        <adif>1</adif>
        <name>CANADA</name>
        <prefix>VE</prefix>
        <deleted>FALSE</deleted>
        <cqz>5</cqz>
        <cont>NA</cont>
        <long>-80.00</long>
        <lat>45.00</lat>
    </entity>
    <entity>
        <adif>2</adif>
        <name>ABU AIL IS</name>
        <prefix>A1</prefix>
        <deleted>TRUE</deleted>
        <cqz>21</cqz>
        <cont>AS</cont>
        <long>45.00</long>
        <lat>12.80</lat>
        <end>1991-03-30T23:59:59+00:00</end>
    </entity>
    <!--Additional entities omitted-->
    </entities>
    </clublog>
    

    我的代码中是否突然出现了问题,或者XML是否无法与当前代码一起使用?

    2 回复  |  直到 8 年前
        1
  •  1
  •   dbc    8 年前

    您的问题是,在某些版本的XML中 <entity> <entities> 元素位于 "http://www.clublog.org/cty/v1.0" XML名称空间,但在其他名称空间中,它们位于 "https://clublog.org/cty/v1.0" 命名空间。

    为了解析任一XML版本,您需要检查元素是否位于两个可能的命名空间中,例如使用以下方法:

    public static class AdifDictionaryExtensions
    {
        public static Dictionary<decimal, string> ExtractAdifDictionary(TextReader reader)
        {
            Dictionary<decimal, string> dict = new Dictionary<decimal, string>();
    
            using (var xmlReader = XmlReader.Create(reader))
            {
                var xd = XDocument.Load(xmlReader);
                var ns1 = (XNamespace)"http://www.clublog.org/cty/v1.0";
                var ns2 = (XNamespace)"https://clublog.org/cty/v1.0";
    
                dict =
                    xd
                    .Root
                    .Elements("entities", ns1, ns2).Single()
                    .Elements("entity", ns1, ns2)
                    .ToDictionary(
                        x => (decimal)x.Elements("adif", ns1, ns2).Single(),
                        x => x.Elements("name", ns1, ns2).Single().Value);
    
                return dict;
            }
        }
    }
    
    public static class XContainerExtensions
    {
        public static IEnumerable<XElement> Elements(this XContainer container, string localName, XNamespace nameSpace, params XNamespace[] additionalNamespaces)
        {
            if (container == null || localName == null)
                throw new ArgumentNullException();
            var names = new[] { nameSpace }.Concat(additionalNamespaces).Select(ns => ns + localName).ToArray();
            return container.Elements().Where(e => names.Any(n => n == e.Name));
        }
    }
    

    笔记:

    • 您可能会想到XML名称空间 "http://www.clublog.org/cty/v1.0" "https://clublog.org/cty/v1.0" 作为可能解析到或可能不解析到相同地址的实际URL。然而,从XML解析的角度来看,这些名称空间只是字符串,当组合到大型异构XML文档中时,它们有助于提供元素和属性的唯一命名。(参见 XML namespace 更多说明。)

      在LINQ to XML层次结构中按名称搜索元素时,使用 XContainer.Element(XName) XContainer.Elements(XName) ,重要的是 local name namespace 使用序号字符串比较获得所需的本地名称和命名空间。

    • 尽管它的名字, XName.Get() 实际上不执行http get或任何其他网络操作。它是一种工厂方法,将两个字符串组合成 XName 用于性能相等比较的类。

    样品加工 .Net fiddle .

        2
  •  1
  •   user9352417 user9352417    8 年前

    这可能是由于搜索XML中实际不存在的元素造成的。
    在这种情况下,将引发Null引用异常。如果更改是在XML本身中进行的,那么这很可能是错误原因。