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

系统。NullReferenceException:对象引用未设置为对象的实例。系统。Xml。林克。XContainer。Elelement()返回null

  •  0
  • MatthewD  · 技术社区  · 1 年前

    我正在阅读从谷歌地球专业版保存的.kml文件。

    这是我从SO上的一篇帖子中获得的代码。当xDoc运行时,它运行得很好。后代具有一致的元素。

        XDocument xDoc = XDocument.Load(openFileDialog1.FileName);
        XNamespace ns = "http://www.opengis.net/kml/2.2";
    
        var placemarks = xDoc.Descendants(ns + "Placemark").Select(p => new
            {
                 Name = (string)p.Element(ns + "name").Value.ToString(),
                 Coords = p.Element(ns + "Point").Element(ns + "coordinates").Value,
            })
            .ToArray();
    

    这将产生以下公里数数据

    image of form displaying the read KML elements enter image description here

    <?xml version="1.0" encoding="UTF-8"?>
    <kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom">
    <Document id="1Y-yAHoHb_KrjsRT70KM5qLdZQjN_xcKW">
        <name>Test kml</name>
        <Placemark id="0B2FCD3E802CFEB8E9AD">
            <name>0+00 cabinet location 12’ BOC</name>
            <LookAt>
                <longitude>-93.28687708665021</longitude>
                <latitude>44.84264135896755</latitude>
                <altitude>255.3402528075096</altitude>
                <heading>0</heading>
                <tilt>0</tilt>
                <range>36.48488765818456</range>
                <altitudeMode>absolute</altitudeMode>
                <gx:fovy>35</gx:fovy>
            </LookAt>
            <styleUrl>#msn_parking_lot</styleUrl>
            <Point>
                <coordinates>-93.28687708665021,44.84264135896755,255.3402528075096</coordinates>
            </Point>
        </Placemark>
        <Placemark>
            <name>Place HH</name>
            <LookAt>
                <longitude>-93.28692035131073</longitude>
                <latitude>44.84255178413457</latitude>
                <altitude>0</altitude>
                <heading>1.868100177527735e-05</heading>
                <tilt>15.19185305855737</tilt>
                <range>106.8343470069538</range>
                <gx:altitudeMode>relativeToSeaFloor</gx:altitudeMode>
            </LookAt>
            <styleUrl>#msn_square0</styleUrl>
            <Point>
                <gx:drawOrder>1</gx:drawOrder>
                <coordinates>-93.28690200178055,44.84263978936539,0</coordinates>
            </Point>
        </Placemark>
        <Placemark id="0C6BEBC5352CFEBCA94D">
            <name>0+45 sewer</name>
            <LookAt>
                <longitude>-93.28845935397412</longitude>
                <latitude>44.84257694352023</latitude>
                <altitude>251.8505380949421</altitude>
                <heading>0</heading>
                <tilt>0</tilt>
                <range>63.54447705992244</range>
                <altitudeMode>absolute</altitudeMode>
                <gx:fovy>35</gx:fovy>
            </LookAt>
            <styleUrl>#__managed_style_397C1C0EAA2D00EDBB6D</styleUrl>
            <Point>
                <coordinates>-93.28845935397412,44.84257694352023,251.8505380949421</coordinates>
            </Point>
        </Placemark>
    </Document>
    </kml>
    
    

    但是当KML xDoc。后代有不一致的元素,如下面的KML,我得到了系统。Xml。林克。XContainer。Elelement()返回null错误,因为第一个位置标记没有point元素。

    image of error in visual studio enter image description here

    <?xml version="1.0" encoding="UTF-8"?>
    <kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom">
    <Document id="1Y-yAHoHb_KrjsRT70KM5qLdZQjN_xcKW">
        <name>Test KML</name>
        <Placemark>
            <name>Running line</name>
            <styleUrl>#m_ylw-pushpin</styleUrl>
            <LineString>
                <tessellate>1</tessellate>
                <coordinates>
                    -93.28762387862635,44.84811886228031,0 -93.28753369589279,44.84814969351044,0 -93.28751831971846,44.84825957026099,0 -93.28749752003094,44.84895772192719,0 
                </coordinates>
            </LineString>
        </Placemark>
        <Placemark>
            <name>Place HH</name>
            <LookAt>
                <longitude>-93.28692035131073</longitude>
                <latitude>44.84255178413457</latitude>
                <altitude>0</altitude>
                <heading>1.868100177527735e-05</heading>
                <tilt>15.19185305855737</tilt>
                <range>106.8343470069538</range>
                <gx:altitudeMode>relativeToSeaFloor</gx:altitudeMode>
            </LookAt>
            <styleUrl>#msn_square0</styleUrl>
            <Point>
                <gx:drawOrder>1</gx:drawOrder>
                <coordinates>-93.28690200178055,44.84263978936539,0</coordinates>
            </Point>
        </Placemark>
        <Placemark id="0C6BEBC5352CFEBCA94D">
            <name>0+45 sewer</name>
            <LookAt>
                <longitude>-93.28845935397412</longitude>
                <latitude>44.84257694352023</latitude>
                <altitude>251.8505380949421</altitude>
                <heading>0</heading>
                <tilt>0</tilt>
                <range>63.54447705992244</range>
                <altitudeMode>absolute</altitudeMode>
                <gx:fovy>35</gx:fovy>
            </LookAt>
            <styleUrl>#__managed_style_397C1C0EAA2D00EDBB6D</styleUrl>
            <Point>
                <coordinates>-93.28845935397412,44.84257694352023,251.8505380949421</coordinates>
            </Point>
        </Placemark>
    </Document>
    </kml>
    
    

    有没有办法使用这种linq-select风格来处理不一致的元素?

    最终,我希望当位置标记有坐标时,它能将坐标从linestring/coordinate元素中取出,当坐标在Point/coordination元素中时,它也能将坐标取出。我可以使用基于“子”元素的值或null填充多个数组值,而不会出现null错误吗?然后,我可以处理空值与值的关系。 如果点或线串中没有坐标,则两者都将为null,我将处理这个问题。

    1 回复  |  直到 1 年前
        1
  •  2
  •   Jon Skeet    1 年前

    有没有办法使用这种linq-select风格来处理不一致的元素?

    当然,你只需要停止无条件地去引用可能为null的东西。使用 null-conditional operator 以及 null-coalescing operator ,这很简单:

    var placemarks = xDoc
        .Descendants(ns + "Placemark")
        .Select(p => new
    {
        Name = p.Element(ns + "name").Value,
        Coords = (p.Element(ns + "LineString")?.Element(ns + "coordinates").Value)
           ?? (p.Element(ns + "Point")?.Element(ns + "coordinates").Value)
    });
    

    括号并不是绝对必要的,但我认为它们可以更容易地看到发生了什么。请注意,如果有 LineString Point 元素没有a coordinates 孩子。您可以使用更多空条件运算符(之前 Value )为了避免这种情况:

    var placemarks = xDoc
        .Descendants(ns + "Placemark")
        .Select(p => new
    {
        Name = p.Element(ns + "name").Value,
        Coords = (p.Element(ns + "LineString")?.Element(ns + "coordinates")?.Value)
           ?? (p.Element(ns + "Point")?.Element(ns + "coordinates")?.Value)
    });
    

    (我已经删除了演员和 ToString 需要 Name ,因为它们不是必需的- XElement.Value 已经返回了一个字符串。)