繁体   English   中英

C#无法在XMLNode中找到节点

[英]c# not able to find a node within the XMLNode

这是我的kml文件:

<?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>
  <name>Test.kml</name>
  <Folder>
    <name>Test</name>
    <open>1</open>
    <Placemark>
      <name>Placemark 1</name>
      <LookAt>
        <longitude>-150</longitude>
        <latitude>72</latitude>
        <altitude>0</altitude>
        <heading>-13.26929942603143</heading>
        <tilt>0</tilt>
        <range>33665.16192218825</range>
        <gx:altitudeMode>relativeToSeaFloor</gx:altitudeMode>
      </LookAt>
      <styleUrl>#m_ylw-pushpin</styleUrl>
      <Point>
        <gx:drawOrder>1</gx:drawOrder>
        <coordinates>-110.7484519621821,52.7616508182995,0</coordinates>
      </Point>
    </Placemark>
    <Placemark>
      <name>Polygon</name>
      <styleUrl>#msn_ylw-pushpin551</styleUrl>
      <Polygon>
        <tessellate>1</tessellate>
        <outerBoundaryIs>
          <LinearRing>
          <coordinates>
            -114.1205573145593,51.36318071429854,0 -114.1205787952745,51.36318006995027,0 -114.1205971712767,51.36317242116965,0 -114.1206026671322,51.36316989077702,0 -114.1206102089206,51.36316966453516,0 -114.1206306254288,51.36316432159048,0 -114.1206380046647,51.36316173522451,0 -114.1206530868876,51.36316128267593,0 -114.1206700591908,51.36316077215199,0 -114.1207186777935,51.36315339774478,0 -114.1207317114146,51.36315064137735,0 -114.1206014395037,51.36248218454789,0 -114.120595868448,51.36248353455266,0 -114.1205319409001,51.36248782272818,0 -114.1204591504232,51.36250065739123,0 -114.1203422144068,51.3624758047018,0 -114.1205573145593,51.36318071429854,0
          </coordinates>
          </LinearRing>
        </outerBoundaryIs>
      </Polygon>
    </Placemark>
  </Folder>
  <Placemark>
    <name>Placemark 1</name>
    <LookAt>
      <longitude>-150</longitude>
      <latitude>72</latitude>
      <altitude>0</altitude>
      <heading>-13.26929942603143</heading>
      <tilt>0</tilt>
      <range>33665.16192218825</range>
      <gx:altitudeMode>relativeToSeaFloor</gx:altitudeMode>
    </LookAt>
    <styleUrl>#m_ylw-pushpin</styleUrl>
    <Point>
      <gx:drawOrder>1</gx:drawOrder>
      <coordinates>-110.7484519621821,52.7616508182995,0</coordinates>
    </Point>
  </Placemark>
  <Placemark>
    <name>Polygon</name>
    <styleUrl>#msn_ylw-pushpin551</styleUrl>
    <Polygon>
      <tessellate>1</tessellate>
      <outerBoundaryIs>
        <LinearRing>
          <coordinates>
            -114.1205573145593,51.36318071429854,0 -114.1205787952745,51.36318006995027,0 -114.1205971712767,51.36317242116965,0 -114.1206026671322,51.36316989077702,0 -114.1206102089206,51.36316966453516,0 -114.1206306254288,51.36316432159048,0 -114.1206380046647,51.36316173522451,0 -114.1206530868876,51.36316128267593,0 -114.1206700591908,51.36316077215199,0 -114.1207186777935,51.36315339774478,0 -114.1207317114146,51.36315064137735,0 -114.1206014395037,51.36248218454789,0 -114.120595868448,51.36248353455266,0 -114.1205319409001,51.36248782272818,0 -114.1204591504232,51.36250065739123,0 -114.1203422144068,51.3624758047018,0 -114.1205573145593,51.36318071429854,0
          </coordinates>
        </LinearRing>
      </outerBoundaryIs>
    </Polygon>
  </Placemark>
 </Document>
</kml>

我想查找名称和坐标,并检查坐标是否重复,然后将其删除。 以下是我到目前为止编写的代码:

    XmlDocument xmldoc = new XmlDocument();
    XmlReaderSettings settings = new XmlReaderSettings { NameTable = new NameTable() };
    XmlNamespaceManager xmlns = new XmlNamespaceManager(settings.NameTable);
    xmlns.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
    XmlParserContext context = new XmlParserContext(null, xmlns, "", XmlSpace.Default);
    XmlReader reader = XmlReader.Create(fileName, settings, context);
    xmldoc.Load(reader);

    // Setup default namespace manager for searching through nodes
    XmlNamespaceManager manager = new XmlNamespaceManager(xmldoc.NameTable);
    string defaultns = xmldoc.DocumentElement.GetNamespaceOfPrefix("");
    manager.AddNamespace("ns", defaultns);

    var values = new HashSet<string>();

    // get a list of all <Placemark> nodes
    XmlNodeList listOfPlacemark = xmldoc.SelectNodes("//ns:Placemark", manager);

    int totalRecordsRemoved = 0;

    // iterate over the <Placemark> nodes
    foreach (XmlNode singlePlaceMark in listOfPlacemark)
    {
        StringBuilder sb = new StringBuilder();
        // Get the name subnode
        XmlNode nameNode = singlePlaceMark.SelectSingleNode("ns:name", manager);

        if (nameNode != null)
        {
            // get a coordinate nodes
            //XmlNodeList coordinatesNode = singlePlaceMark.SelectNodes("//coordinates", manager);

            XmlNode coordinatesNode = singlePlaceMark.SelectSingleNode("ns:coordinates", manager);

            sb.Append(coordinatesNode.InnerXml.ToString());

            if (sb.ToString() != "")
            {
                if (values.Contains(sb.ToString()))
                {                                    
                    singlePlaceMark.RemoveAll();                                    
                }
                else
                {
                    values.Add(sb.ToString());
                }
            }
        }
    }

我找不到坐标节点,无论地标节点内的层次如何,如何获取<coordinates>节点中的值? 是否有使用Linq或任何其他方法执行此操作的简单方法?

编辑:

我不使用XDocument的两个原因

1.在所有处理之后保存的kml变得很大,因为所有节点都将kml作为前缀,这是因为“ xmlns:kml =“ http://www.opengis.net/kml/2.2”“标签。 我不知道如何使用XDocument删除此标签,所以我使用了XmlDocument,该文件在保存时显示不带前缀的xml标签。 2.我的kml文件没有“ http://www.w3.org/2001/XMLSchema-instance ”命名空间,因此当我使用XDocument时,它给我错误-'xsi'是未声明的前缀。 但是当我使用XmlDocument时,不会出现此错误。

编辑2:

您能否建议我如何在此行获得坐标节点XmlNodeordinateNode = singlePlaceMark.SelectSingleNode(“ ns:coordinates”,manager);?

kml文件可能很大,并且导致内存不足异常。 我建议使用XmlReader。 参见下面的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        const string FILENAME = @"c:\temp\test.xml";
        static void Main(string[] args)
        {
            XmlReader reader = XmlReader.Create(FILENAME);
            reader.MoveToContent();
            while (!reader.EOF)
            {
                if (reader.Name != "Placemark")
                {
                    reader.ReadToFollowing("Placemark");
                }
                if (!reader.EOF)
                {
                    XElement placemark = (XElement)XElement.ReadFrom(reader);
                    Location location = new Location();
                    Location.locations.Add(location);
                    XElement name = placemark.Elements().Where(x => x.Name.LocalName == "name").FirstOrDefault();
                    location.name = (string)name;
                    XElement longitude = placemark.Descendants().Where(x => x.Name.LocalName == "longitude").FirstOrDefault();
                    location.longitude = (int?)longitude;
                    XElement latitude = placemark.Descendants().Where(x => x.Name.LocalName == "latitude").FirstOrDefault();
                    location.latitude = (int?)latitude;
                    XElement altitude = placemark.Descendants().Where(x => x.Name.LocalName == "altitude").FirstOrDefault();
                    location.alt = (int?)altitude;
                    XElement tilt = placemark.Descendants().Where(x => x.Name.LocalName == "tilt").FirstOrDefault();
                    location.tilt = (int?)tilt;
                    XElement heading = placemark.Descendants().Where(x => x.Name.LocalName == "heading").FirstOrDefault();
                    location.heading = (double?)heading;
                    XElement range = placemark.Descendants().Where(x => x.Name.LocalName == "range").FirstOrDefault();
                    location.range = (double?)range;
                    XElement coordinates = placemark.Descendants().Where(x => x.Name.LocalName == "coordinates").FirstOrDefault();
                    if (coordinates != null)
                    {
                        List<string> coordinatesArray = ((string)coordinates).Split(new char[] { ' ', '\n' }, StringSplitOptions.RemoveEmptyEntries).ToList();
                        foreach(string coordinate in coordinatesArray)
                        {
                            string[] coordinateArray = coordinate.Split(new char[] { ',' });
                            Coordinate newCoordinate = new Coordinate();
                            if (location.coordinates == null) location.coordinates = new List<Coordinate>();
                            location.coordinates.Add(newCoordinate);

                            newCoordinate.longitude = double.Parse(coordinateArray[0]);
                            newCoordinate.latitude = double.Parse(coordinateArray[1]);
                            newCoordinate.alt = double.Parse(coordinateArray[2]);

                        }

                    }
                }
            }
        }
    }
    public class Location
    {
        public static List<Location> locations = new List<Location>();
        public string name { get; set; }
        public int? longitude { get; set; }
        public int? latitude { get; set; }
        public int? alt { get; set; }
        public int? tilt { get; set; }
        public double? heading { get; set; }
        public double? range { get; set; }
        public List<Coordinate> coordinates { get; set; }
    }
    public class Coordinate
    {
        public double longitude { get; set; }
        public double latitude { get; set; }
        public double alt { get; set; }
    }
}

如果您使用的是XDocument和LINQ magic,则以下代码将删除坐标重复的那些实例的所有其他Placemark元素。

var xdoc = XDocument.Parse(xml); // XDocument.Load(stream or file);

var kml = (XNamespace) "http://www.opengis.net/kml/2.2";

var coordinates = xdoc
   .Descendants(kml + "Placemark")              // find Placemark elements
   .Where(pm => pm.Element(kml+"name") != null) // which have a name element
   .Descendants(kml + "coordinates")            // find its coordinates 
   .GroupBy(c => c.Value)                       // group by its value
   .Where(c => c.Count() > 1)                   // if we found more then one value
   .Select(c=> c);                              // project the item for removal

int totalRecordsRemoved = 0;
// loop over each key    
foreach(var coord in coordinates)
{
  // loop over the double coordinates, skipping the first item
  foreach(var item in coord.Skip(1))
  {
     totalRecordsRemoved++;
     // remove the Placemark node, 
     // assuming there ALWAYS will be a Placemark up the hierachy
     // if not First will bark
     item.Ancestors(kml + "Placemark").First().Remove();
  }
}

现在, xdoc将包含您清除的XML,您可以按自己喜欢的任何其他方式保存或处理该XML。

XDocument可能需要内存,因此请测试并验证其内存消耗是否满足您的要求。

如果需要使用XDocument.Load读取损坏的XML文件,请使用XMLReader及其自己的ParserContext和namespacemanager,如下所示:

NameTable nt = new NameTable();
XmlNamespaceManager nsmgr = new XmlNamespaceManager(nt);
// this adds the missing namespace
nsmgr.AddNamespace("xsi", "https://www.w3.org/2001/XMLSchema-instance");

// Create the XmlParserContext.
XmlParserContext context = new XmlParserContext(null, nsmgr, null, XmlSpace.None);

// Create the reader. 
XmlReaderSettings settings = new XmlReaderSettings();
settings.ConformanceLevel = ConformanceLevel.Fragment;
XmlReader reader = XmlReader.Create(fileOrStream, settings, context);

var xdoc = XDocument.Load(reader);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM