سؤال
أنا مبتدئ في LINQ إلى 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 الجيدة - تلك التي وجدتها عبر الإنترنت تتوقف عند سيناريوهات بسيطة للغاية.
المحلول 2
شكرًا لـoon16 وBruce Murdock لتوجيهي في الاتجاه الصحيح.الكود الذي نشرته ملعقة 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
لاحظ ال :ز باتباع XMLNS في السطر الأول.يمنحك هذا اختصارًا للإشارة إلى مساحة الاسم هذه في مكان آخر.
لمزيد من المعلومات حول فئة XNamespace، راجع وثائق MSDN.
نصائح أخرى
هذا يعمل بالنسبة لي في C#:
XDocument doc = XDocument.Load(@"TheFile.kml");
var q = doc.Descendants().Where(x => x.Name.LocalName == "Placemark");
لدى سكوت هانسيلمان حلاً موجزًا لأولئك الذين يبحثون عن حل يعتمد على لغة C#.
أيضًا، يعد استخدام 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");
لم يقم أي من الإصلاحات المذكورة أعلاه بالمهمة؛انظر تعليقاتي للحصول على التفاصيل.أعتقد أن كلا منoon16 وBruce Murdock يسيران على الطريق الصحيح، نظرًا لأن مساحة الاسم هي المشكلة بالتأكيد.
بعد مزيد من البحث على 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
إذا كان بإمكان أي شخص نشر تعليمات برمجية تعمل مع مساحة الاسم بدلاً من قصفها، فسأقدم لهم الإجابة بكل سرور.
قد تحتاج إلى إضافة مساحة اسم إلى اسم XElement
Dim ns as string = "http://earth.google.com/kml/2.0"
dim foo = Kml.Descendants(ns + "Document")
تجاهل أي أخطاء في بناء الجملة، أنا أعمل في C#
ستجد أنه يمكن أن يكون هناك اختلاف في 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));