Pergunta

Eu sou um LINQ to novato XML, e um novato KML bem; Então tenha paciência comigo.

Meu objetivo é extrair marcadores individuais de um arquivo KML. Meu KML começa assim:

<?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>
    ...

Esta é, tanto quanto eu comecei:

    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

Até agora há boas - Kml.Descendants ( "Placemark") me dá uma enumeração vazia. O documento é carregado corretamente - porque KML.Descendants contém cada nó. Por que vale a pena essas consultas vêm acima de vazio, bem como:

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

Pode alguém me aponte na direção certa? Os pontos de bônus para ligações a boa Linq para tutoriais XML - os que eu encontrei parada online em cenários muito simples.

Foi útil?

Solução 2

Graças a spoon16 e Bruce Murdock por me apontar na direção certa. O código que spoon16 postou funciona, mas obriga a concatenar o namespace com cada nome único elemento, que não é tão limpo quanto eu gostaria.

Eu fiz um pouco mais procura e eu descobri como isto é suposto ser feito - este é super concisa, e eu amo o novo <...> suporte de sintaxe para referindo-se a elementos 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

Observe o : g seguindo as xmlns na primeira linha. Isto dá-lhe um atalho para se referir a isso em outro lugar namespace.

Para saber mais sobre a classe XNamespace, consulte a MSDN documentação.

Outras dicas

Isso funciona para mim em C #:

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

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

Scott Hanselman tem uma solução concisa para aqueles que procuram uma solução baseada C #.

XLinq para suporte a XML em VB9

Além disso, usar XNamespace vem a calhar, em vez de apenas anexando uma string. Isto é um pouco mais formal.

// 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");

Nenhuma das correções acima fez o trabalho; ver os meus comentários para mais detalhes. Eu acredito que ambos spoon16 e Bruce Murdock está no caminho certo, uma vez que o namespace é definitivamente a questão.

Depois de mais Googling me deparei com algum código em desta página que sugeriu uma solução:. apenas tira o atributo xmlns do XML original

    ' 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

Se qualquer um pode postar código de trabalho que trabalha com o namespace em vez de nuking-lo, eu vou com prazer dar-lhes a resposta.

Você pode precisar adicionar um espaço de nomes para o nome XElement

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

ignorar quaisquer erros de sintaxe, eu trabalho em c #

Você vai encontrar não pode haver uma diferença na XElement.Name vs XElement.Name.LocalName/

Eu costumo foreach por toda a XElements no doc como um primeiro passo para ter certeza que eu estou usando a nomenclatura correta.

C # Aqui está um trecho do meu uso, parece que eu esqueci o {}

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

 var results = admldoc.Descendants(GpNamespace + 
               "presentationTable").Descendants().Select(
                p => new dcPolicyPresentation(p));
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top