Ile razy spotkaliście się, że wam to po prostu nie działa? Wykonujecie prosty kod:
var list = root.SelectNodes("/blog//posts//post/comments/comment[@user-name='Gutek']");
a lista zawiera zero elementów? Patrzycie w XML i mówicie, nie możliwe.
A jednak. Po 12h pracy wróciłem do domu i stwierdziłem, że pora zabrać się za przenoszenie postów – niby wszystko miało być pięknie. Posty wyeksportowałem do standardu BlogML za pomocą małego rozszerzenia do Community Server. Dane wyeksportowane jednakże zawierały pewne moim zdaniem bugi – na przykład, zamiast nazwy autora komentarza było podane „http://”, atrybut e-mail autora komentarza był pominięty, zaś wszystkie znaki specjalne takie jak <> czy & mimo CDATA były konwertowane do postaci & amp; itp. Podliczyłem liczbę zmian jakie muszę wykonać w tym stworzenie atrybutów zmiana treści i stwierdziłem iż najprostszym i najszybszym sposobem będzie wykorzystanie do tego wszystkiego C# – w końcu jesteśmy programistami? :)
Właśnie mijała 15h mojej egzystencji i wiedziałem, że następnego dnia nie będzie lepiej, więc nie myśląc zbytnio o jakiś super ekstra rozwiązaniu sięgnąłem po klasę XmlDocument, w której myślałem, że wszystko szybko załatwię. Nic bardziej błędnego.
Po 30 minutach zacząłem sobie wyrwać włosy z głowy, albo ja byłem kompletnie głupi i napisałem błędny kod, albo po prostu ktoś popełnił wielki błąd w BCL – co po prawie 16h uważałem za coraz bardziej prawdopodobne :)
Zanim jednak się poddałem, zacząłem przeglądać Google w poszukiwaniu rozwiązania – znalazłem wiele opisów tego samego problemu ale żaden nie dawał rozwiązania. Moja wiara w Bug BCL z każdą minutę rosła. Głos rozsądku jednak podpowiadał – gdyby XmlDocument i SelectNodes nie działały poprawnie to po MS nie została by przecież sucha nitka, a i Google by dał wiele setek tysięcy wyników mówiących jako to MS jest skoro nie wspiera poprawnie XmlDocument.
W końcu natrafiłem na mała zmiankę, że XmlDocument wymaga namespace by działał poprawnie. Więc przejrzałem się swojemu xml’owi i rzeczywiście namespace był zadeklarowany, ale był jako domyślny . Idąc dalej tym tropem w końcu natrafiłem na artykuł starający się wytłumaczyć dlaczego tak się dzieje. Dalsze poszukiwania dały tylko i wyłącznie jedyną poprawną odpowiedź: XPath 1.0 nie wspiera tak zwanych Default Namespace przez co za każdym razem kiedy robimy zapytanie musimy podać zarówno prefix jak i namespace.
Wykonanie więc poniższego kodu, rozwiązało cały problem jaki miałem:
var xmlns = _xmlDoc.DocumentElement.Attributes["xmlns"].Value; var nsmgr = new XmlNamespaceManager(_xmlDoc.NameTable); nsmgr.AddNamespace("BlogMl", xmlns); var root = _xmlDoc.DocumentElement; var list = root.SelectNodes("/BlogMl:blog//BlogMl:posts//BlogMl:post/BlogMl:comments/BlogMl:comment[@user-name='Gutek']", nsmgr);
Więc ogólnie pamiętajcie, jeżeli wasz XML zawiera atrybut xmlns to zastanówcie się nad wykorzystaniem innego sposobu niż XmlDocument lub dodajcie namespace :)
Też się kiedyś z tą dokładnie kwestią niemało namęczyłem…
Ja chyba miałem po prostu szczęście. Robiłem podobne rzeczy ale przykład z którego korzystałem miał już namespace.
Comments are closed.