[英]XmlNode.SelectSingleNode syntax to search within a node in C#
[英]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.