Linq to XML for KML?

时间:2020-03-06 14:54:16  来源:igfitidea点击:

我是LINQ to XML新手,也是KML新手。所以忍受我

我的目标是从KML文件中提取单个地标。我的KML由此开始:

<?xml version="1.0" encoding="utf-8"?>
<Document xmlns="http://earth.google.com/kml/2.0">
  <name>Concessions</name>
  <visibility>1</visibility>
  <Folder>
    <visibility>1</visibility>
    <Placemark>
      <name>IN920211</name>
      <Style>
        <PolyStyle>
          <color>80000000</color>
        </PolyStyle>
      </Style>
      <Polygon>
        <altitudeMode>relativeToGround</altitudeMode>
        <outerBoundaryIs>
          <LinearRing>
            <coordinates>11.728374,1.976421,0 11.732967,1.965322,0 11.737225,1.953161,0 11.635858,1.940812,0 11.658102,1.976874,0 11.728374,1.976421,0 </coordinates>
          </LinearRing>
        </outerBoundaryIs>
      </Polygon>
    </Placemark>
    <Placemark>
    ...

据我所知:

Dim Kml As XDocument = XDocument.Load(Server.MapPath("../kmlimport/ga.kml"))
    Dim Placemarks = From Placemark In Kml.Descendants("Placemark") _
         Select Name = Placemark.Element("Name").Value

到目前为止,没有好的Kml.Descendants(" Placemark")给我一个空的枚举。该文档已正确加载,因为KML.Descendants包含每个节点。对于这些查询而言,它们的价值也是空的:

Dim foo = Kml.Descendants("Document") 
Dim foo = Kml.Descendants("Folder")

有人可以指出我正确的方向吗?好的Linq to XML教程的链接的加分点是,我在网上发现的链接在非常简单的情况下就停止了。

解决方案

我们可能需要在XElement名称中添加名称空间

Dim ns as string = "http://earth.google.com/kml/2.0"
dim foo = Kml.Descendants(ns + "Document")

忽略任何语法错误,我在C#中工作

我们会发现XElement.NameXElement.Name.LocalName /可能有所不同

通常,我会首先遍历文档中的所有XElements作为第一步,以确保使用正确的命名。

C
这是我的用法节选,好像我忘记了{}

private string GpNamespace = 
 "{http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions}";

 var results = admldoc.Descendants(GpNamespace + 
               "presentationTable").Descendants().Select(
                p => new dcPolicyPresentation(p));

以上两种修复方法均无济于事。有关详细信息,请参见我的评论。我相信spoon16和Bruce Murdock都走在正确的道路上,因为命名空间绝对是问题所在。

在进一步谷歌搜索之后,我在此页面上遇到了一些代码,这些代码提出了一种解决方法:只需从原始XML中删除xmlns属性即可。

' Read raw XML
    Dim RawXml As String = ReadFile("../kmlimport/ga.kml")
    ' HACK: Linq to XML choking on the namespace, just get rid of it
    RawXml = RawXml.Replace("xmlns=""http://earth.google.com/kml/2.0""", "")
    ' Parse XML
    Dim Kml As XDocument = XDocument.Parse(RawXml)
    ' Loop through placemarks
    Dim Placemarks = From Placemark In Kml.<Document>.<Folder>.Descendants("Placemark")
    For Each Placemark As XElement In Placemarks
        Dim Name As String = Placemark.<name>.Value
        ...
    Next

如果任何人都可以发布使用该名称空间的工作代码而不是对其进行修改,那么我将很乐意为他们提供答案。

感谢spoon16和Bruce Murdock为我指出了正确的方向。 Spoon16发布的代码可以工作,但是会强制我们将名称空间与每个单个元素名称连接起来,这不像我想要的那么干净。

我做了更多的搜索,并且弄清楚了应该如何做到这一点,这非常简洁,而且我喜欢用于引用XML元素的新<...>方括号语法。

Imports <xmlns:g='http://earth.google.com/kml/2.0'>
Imports System.Xml.Linq

 ...

    Dim Kml As XDocument = XDocument.Load(Server.MapPath("../kmlimport/ga.kml"))
    For Each Placemark As XElement In Kml.<g:Document>.<g:Folder>.<g:Placemark>
        Dim Name As String = Placemark.<g:name>.Value
    Next

注意第一行中xmlns之后的:g。这为我们提供了在其他地方引用此命名空间的快捷方式。

有关XNamespace类的更多信息,请参见MSDN文档。

Scott Hanselman为正在寻找基于C的解决方案的人提供了一个简洁的解决方案。

VB9中的XLINQ to XML支持

此外,使用XNamespace十分方便,而不仅仅是添加字符串。这有点正式。

// This code should get all Placemarks from a KML file            
var xdoc = XDocument.Parse(kmlContent);
XNamespace ns = XNamespace.Get("http://earth.google.com/kml/2.0");
var ele = xdoc.Element(ns + "kml").Element(ns + "Document").Elements(ns + "Placemark");

这在C#中对我有用:

XDocument doc = XDocument.Load(@"TheFile.kml");

var q = doc.Descendants().Where(x => x.Name.LocalName == "Placemark");