Olvassuk be az XML dokumentumot egy XmlDataDocument vagy XmlDocument objektumba, majd XPath szintaktikával lekérdezéseket is futtathatunk benne. Első találkozásunkkor, amikor a példának talált lekérdezéseket alaposabban megnéztem, úgy tűnt, ezek a kifejezések vetekednek az ókori hieroglifákkal.
Íme egy példa elrettentésül (én elsőre eléggé megijedtem tőle, nem tudom más hogy van vele):
var nodeList = xml.selectNodes("*[ myevent:System[(myevent:Level=4 or myevent:Level=0)_
and (myevent:EventID=1644)] and myevent:EventData[starts-with(myevent:Data[5],'10.200.137.145')] ]");
Persze kedvenc autós xml fájlomra (lásd lejjebb) az XPath is nagyon szépen működik (és egyszerű is a használata), így néz ki:
For Each node As System.Xml.XmlNode In doc.SelectNodes("/Autok/Auto")
.....
Next node
A valóság szerintem valahol a kettő között van, át kell rágni a szintaktikát, erre az MSDN a legjobb, nem is kívánok vele versenyezni, inkább a saját tapasztalataimmal szerzett tanulságot osztom meg.
Az első nekifutás nagyon jól ment, kedvenc autós példámmal:
<Autok>
<Auto>Trabant</Auto>
<Auto>Mercedes</Auto>
</Autok>
Igenám, de munkám során nem ilyen XML fájllal hozott össze a sors, hanem olyannal, aminek teljesen "fel volt cicomázva" a feje, mindenféle hivatkozás, XSD, névtér, meg minden, ahogy rendesen kell.
Azonnal belefutottam a következő problémába: hiába próbáltam bárhogyan címezni egy vagy több nodot, az eredmény mindig üres halmaz lett. Némi kutakodással a Googlen annyit sikerült megtudnom, hogy ezzel sokan mások is így vannak, kész, megrágott megemésztett megoldást azonban nem találtam.
Eddig sikerült jutnom:
For Each node As System.Xml.XmlNode In doc.SelectNodes("/")
Eddig tökéletes, szépen megjelenítette gyakorlatilag az egész XML tartalmát, de bármit írtam utána, már csak üres halmaz. Amikor arra lettem figyelmes, hogy a SelectNodes utasításnak van egy másik paramétere is, ami NamespaceManager típusú. Persze nyilván nem tudja szegény hogy milyen névtérben keresgéljen. (De hogy egy sima "/"-re miért tudja mégis az rejtély...)
A megoldás:
Dim xmlDoc As New XmlDocument
xmlDoc.Schemas.Add("http://valami.xsd", xsd_doksi)
xmlDoc.Load(xml_doksi)
Eddig nincs benne semmi különös, itt a lényeg:
Dim xnm As XmlNamespaceManager = New XmlNamespaceManager(xmlDoc.NameTable)
xnm.AddNamespace("elnevezes", "http://valami.xsd")
És csodák csodája, így már működik:
aktnod = xmlDoc.SelectSingleNode("/elnevezes:root/elnevezes:kivalasztott_nod", xnm)
If aktnod Is Nothing Then
kiolvasottertek = ""
Else
Try
kiolvasottertek = aktnod.SelectSingleNode("elnevezes:kivalasztott_al_nod", xnm).InnerText
Catch ex As Exception
kiolvasottertek = ""
End Try
End If
Ha több nodot szeretnénk kiválasztani:
For Each valamilyen_nod As XmlNode In aktnod.SelectNodes("elnevezes:valamelyik_nod", xnm)
...
Next
A trükk csak annyi hogy kapnia kell egy névteret (a példában "Elnevezes"), és mindig erre kell hivatkoznunk.
Ettől kezdve akár kiválaszthatunk egyetlen nodot a SelectSingleNode utasítással, vagy többet a SelectNodes utasítással, illetve a nodokat szűrhetjük, vagy kereshetünk bennük.
Talán még ettől is gyorsabb és könnyebb a használata ha létrehozunk egy XPathNavigator objektumot, amivel könnyedén kiválaszthatjuk a kívánt nodo(ka)t, és ahogyan a nevében is benne van, navigálhatunk vele a dokumentumban. Erre is egy rövid példakód:
Dim doc As New XPathDocument("C:\peldak\autok.xml")
Dim navigator As XPathNavigator = doc.CreateNavigator
Dim nodes As XPathNodeIterator = navigator.Select("/autok/auto")
nodes.MoveNext()
Dim nodesNavigator As XPathNavigator = nodes.Current
Dim nodesText As XPathNodeIterator = nodesNavigator.SelectDescendants(XPathNodeType.Text, False)
While nodesText.MoveNext()
TextBox1.Text = TextBox1.Text & nodesText.Current.Value
End While
A lekérdezések szintaktikája megér egy külön cikket, mert nagyon sokat tudnak, és csak elsőre olyan ijesztő...