【问题标题】:XDocument parsing errorXDocument 解析错误
【发布时间】:2018-07-24 12:41:54
【问题描述】:

多年来,我一直通过 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 无法与当前代码一起使用?

【问题讨论】:

  • 哪一行抛出异常?
  • 首先我注意到结束标签&lt;/entities&gt; 丢失了。如果您只是忘记将其粘贴到此处.. 更改的确切位置在哪里?在解析 XML 文件时,如果某些元素找不到,则会抛出 null 异常。
  • http://www.clublog.org/cty/v1.0 给出 404 not found 所以我想这可能是问题的一部分

标签: c# linq-to-xml xmlreader


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    您的问题是,在某些 XML 版本中,&lt;entity&gt;&lt;entities&gt; 元素位于 "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。)

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

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

    工作示例.Net fiddle

    【讨论】:

    • 非常感谢。这似乎是解决我的问题的一种方法。
    • 由于时间紧迫,我通过解压缩文件然后将其加载到数据集和数据表中而采取了不同的方向。
    猜你喜欢
    • 1970-01-01
    • 2013-07-28
    • 1970-01-01
    • 2016-06-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-28
    • 1970-01-01
    相关资源
    最近更新 更多