Domanda
Sono un principiante di LINQ to XML e anche un principiante di KML; quindi abbi pazienza.
Il mio obiettivo è quello di estrarre singoli segnaposto da un file KML. Il mio KML inizia così:
<?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>
...
Questo è quanto ho ottenuto:
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
Finora non va bene - Kml.Descendants (" Placemark ") mi dà un elenco vuoto. Il documento viene caricato correttamente, poiché KML.Descendants contiene tutti i nodi. Per quello che vale, anche queste domande risultano vuote:
Dim foo = Kml.Descendants("Document")
Dim foo = Kml.Descendants("Folder")
Qualcuno può indicarmi la giusta direzione? I punti bonus per i collegamenti a buoni tutorial da Linq a XML - quelli che ho trovato online si fermano in scenari molto semplici.
Soluzione 2
Grazie a spoon16 e Bruce Murdock per avermi indicato nella giusta direzione. Il codice pubblicato da spoon16 funziona, ma ti costringe a concatenare lo spazio dei nomi con ogni singolo nome di elemento, che non è pulito come vorrei.
Ho fatto un po 'più di ricerca e ho capito come dovrebbe essere fatto - questo è super conciso e adoro il nuovo < ... > sintassi della parentesi per il riferimento a elementi 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
Nota : g seguendo gli xmlns nella prima riga. Questo ti dà una scorciatoia per fare riferimento a questo spazio dei nomi altrove.
Per ulteriori informazioni sulla classe XNamespace, vedere Documentazione MSDN .
Altri suggerimenti
Questo funziona per me in C #:
XDocument doc = XDocument.Load(@"TheFile.kml");
var q = doc.Descendants().Where(x => x.Name.LocalName == "Placemark");
Scott Hanselman ha una soluzione concisa per chi cerca una soluzione basata su C #.
Supporto da XLINQ a XML in VB9
Inoltre, usare XNamespace è utile, piuttosto che aggiungere semplicemente una stringa. Questo è un po 'più formale.
// 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");
Nessuna delle correzioni precedenti ha fatto il lavoro; vedere i miei commenti per i dettagli. Credo che spoon16 e Bruce Murdock siano sulla buona strada, dal momento che lo spazio dei nomi è sicuramente il problema.
Dopo ulteriori ricerche su Google ho trovato del codice su questa pagina che ha suggerito una soluzione alternativa: basta rimuovere l'attributo xmlns dall'XML originale.
' 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 qualcuno può pubblicare un codice funzionante che funziona con lo spazio dei nomi invece di modificarlo, li darò volentieri la risposta.
Potrebbe essere necessario aggiungere uno spazio dei nomi al nome XElement
Dim ns as string = "http://earth.google.com/kml/2.0"
dim foo = Kml.Descendants(ns + "Document")
ignoro eventuali errori di sintassi, lavoro in c #
Scoprirai che potrebbe esserci una differenza tra XElement.Name
vs XElement.Name.LocalName/
Di solito foreach
attraverso tutti i XElements
nel documento come primo passo per essere sicuro di usare il nome giusto.
C # Ecco un estratto del mio utilizzo, sembra che abbia dimenticato il {}
private string GpNamespace =
"{http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions}";
var results = admldoc.Descendants(GpNamespace +
"presentationTable").Descendants().Select(
p => new dcPolicyPresentation(p));