Linq to XML для KML?

Я новичок в 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 — те, которые я нашел в Интернете, останавливаются на очень простых сценариях.


person Herb Caudill    schedule 30.09.2008    source источник


Ответы (5)


Это работает для меня на С#:

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

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

Спасибо Spoon16 и Брюсу Мердоку за то, что указали мне правильное направление. Код, опубликованный ложкой16, работает, но заставляет вас объединять пространство имен с каждым именем элемента, что не так чисто, как хотелось бы.

Я еще немного поискал и выяснил, как это должно быть сделано — это очень лаконично, и мне нравится новый синтаксис скобок ‹...> для ссылки на элементы 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

Обратите внимание на :g после xmlns в первой строке. Это дает вам ярлык для ссылки на это пространство имен в другом месте.

Дополнительные сведения о классе XNamespace см. в документации MSDN< /а>.

person Herb Caudill    schedule 30.09.2008

У Скотта Хансельмана есть краткое решение для тех, кто ищет решение на основе C#.

Поддержка XLINQ в XML в VB9

Кроме того, удобно использовать 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");
person Matthew Ruston    schedule 21.10.2008

Ни одно из вышеперечисленных исправлений не помогло; подробности см. в моих комментариях. Я считаю, что и ложка16, и Брюс Мердок находятся на правильном пути, так как пространство имен определенно является проблемой.

После дальнейшего поиска в Google я наткнулся на код на этой странице, который предлагал обходной путь: просто удалите атрибут xmlns из исходного XML.

    ' 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

Если кто-нибудь может опубликовать рабочий код, который работает с пространством имен, а не уничтожает его, я с радостью дам им ответ.

person Herb Caudill    schedule 30.09.2008

Возможно, вам потребуется добавить пространство имен к имени XElement.

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

игнорировать любые синтаксические ошибки, я работаю в С#

Вы обнаружите, что может быть разница между XElement.Name и XElement.Name.LocalName/.

Обычно я foreach просматриваю все 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));
person Bruce Murdock    schedule 30.09.2008
comment
Это дает мне исключение во время выполнения: System.Xml.XmlException - символ ':', шестнадцатеричное значение 0x3A, не может быть включен в имя. - person Herb Caudill; 30.09.2008
comment
Спасибо - это работает. Я нашел более краткий подход, который я опубликую ниже. - person Herb Caudill; 30.09.2008