XPath (celowo) nie jest przeznaczony dla przypadku, w którym chcesz użyć tego samego wyrażenia XPath dla niektórych nieznanych obszarów nazw, które występują tylko w dokumencie XML. Oczekuje się, że znasz przestrzeń nazw z wyprzedzeniem, zadeklaruj przestrzeń nazw procesorowi XPath i użyj nazwy w swoim wyrażeniu. Odpowiedzi od Martina i Dana pokazują, jak to zrobić w języku C#.
Przyczyną tych trudności jest najlepiej wyrażona w XML namespaces specyfikacji:
Przedstawiamy aplikacje Extensible Markup Language (XML), gdzie pojedynczy dokument XML może zawierać elementy i atrybuty (tutaj określane jako " Słownik znaczników "), które są zdefiniowane i używane przez wiele modułów oprogramowania. Jedną z motywacji jest modułowość: jeśli istnieje taki słownik znaczników, który jest dobrze zrozumiały i dla którego dostępne jest użyteczne oprogramowanie, lepiej jest ponownie użyć tego znacznika niż go ponownie wymyślić.
Takie dokumenty, zawierające wiele słowników, stanowią problem rozpoznawania i kolizji. Moduły oprogramowania muszą być w stanie rozpoznać elementy i atrybuty, które są zaprojektowane do przetwarzania, nawet w obliczu "kolizji" występujących, gdy znaczniki przeznaczone dla innego pakietu oprogramowania używają tej samej nazwy elementu lub nazwy atrybutu.
Te rozważania wymagają, aby konstrukcje dokumentów miały nazwy skonstruowane w taki sposób, aby uniknąć konfliktów między nazwami z różnych słowników znaczników. Ta specyfikacja opisuje mechanizm, przestrzenie nazw XML, które to umożliwiają, przypisując rozszerzone nazwy elementom i atrybutom.
Oznacza to, że przestrzenie nazw mają być stosowane, aby upewnić się, co dokument mówi o: czy to <head>
elementem rozmowy o preambule dokumentu XHTML lub somebodies uderzeniem w dokumencie AnatomyML?Nigdy nie "przypuszczasz", że jesteś agnostykiem w przestrzeni nazw i jest to prawie pierwsza rzecz, którą powinieneś zdefiniować w dowolnym słowniku XML.
Powinno być możliwe robienie tego, co chcesz, ale myślę, że nie można tego zrobić w jednym wyrażeniu XPath. Przede wszystkim musisz pogrzebać w dokumencie i wyodrębnić wszystkie obszary nazwURIS, a następnie dodać je do menedżera przestrzeni nazw, a następnie uruchomić rzeczywiste wyrażenie XPath, które chcesz (i musisz wiedzieć coś o dystrybucji przestrzeni nazw w dokumencie w tym miejscu punkt, lub masz wiele wyrażeń do uruchomienia). Myślę, że prawdopodobnie najlepiej jest użyć czegoś innego niż XPath (np. DOM lub podobny do SAX API), aby znaleźć przestrzeń nazwURIS, ale można również odkryć oś przestrzeni nazw XPath (w XPath 1.0), użyć funkcji (w XPath 2.0) lub użyj wyrażeń, takich jak Oleg's "configuration/*[local-name() = 'MyNode']"
. W każdym razie myślę, że najlepiej jest spróbować uniknąć pisania agnostycznego XPath! Dlaczego nie znasz swojego obszaru nazw przed czasem? Jak zamierzasz unikać dopasowywania rzeczy, których nie chcesz dopasować?
Edytuj - znasz obszar nazwURI?
Okazuje się, że twoje pytanie myliło nas wszystkich. Najwyraźniej znasz identyfikator URI przestrzeni nazw, ale nie znasz prefiksu przestrzeni nazw, który jest używany w dokumencie XML. Rzeczywiście, w tym przypadku nie jest używany prefiks przestrzeni nazw, a URI staje się domyślnym obszarem nazw, w którym jest zdefiniowany. Kluczową rzeczą jest to, że wybrany prefiks (lub brak przedrostka) nie ma znaczenia dla twojego wyrażenia XPath (i ogólnie parsowania XML). Atrybut prefix/xmlns to tylko jeden sposób skojarzenia węzła z identyfikatorem URI przestrzeni nazw, gdy dokument jest wyrażony jako tekst. Możesz rzucić okiem na this answer, gdzie próbuję i wyjaśnić przedrostki przestrzeni nazw.
Powinieneś spróbować myśleć o dokumencie XML w ten sam sposób, w jaki parser myśli o nim - każdy węzeł ma identyfikator URI przestrzeni nazw i lokalną nazwę. Prefiks/reguły dziedziczenia przestrzeni nazw tylko zapisują wielokrotne wpisywanie URI. Jednym ze sposobów na zapisanie tego jest notacja Clark: oznacza to, że piszesz {http://www.example.com/namespace/example} LocalNodeName, ale ta notacja jest zwykle używana tylko do dokumentacji - XPath nic nie wie o tej notacji.
Zamiast tego, XPath używa własnych przedrostków przestrzeni nazw. Coś jak /ns1:root/ns2:node
. Są one jednak całkowicie oddzielne i nie mają nic wspólnego z żadnym prefiksem, który może być użyty w oryginalnym dokumencie XML. Każda implementacja XPath będzie miała możliwość odwzorowania własnych prefiksów na identyfikatory URI przestrzeni nazw. Do implementacji C# używasz XmlNamespaceManager
, w Perlu podajesz hasz, xmllint pobiera argumenty wiersza poleceń ... Wszystko, co musisz zrobić, to utworzyć dowolny prefiks dla znanego identyfikatora URI przestrzeni nazw i użyć tego przedrostka w wyrażeniu XPath . Nie ma znaczenia, jakiego prefiksu używasz, w XML'ie zależy ci tylko na połączeniu URI i localName.
Inną rzeczą do zapamiętania (często jest to niespodzianka) jest to, że XPath nie dziedziczy dziedzin. Musisz dodać prefiks dla każdego, który ma przestrzeń nazw, niezależnie od tego, czy przestrzeń nazw pochodzi z dziedziczenia, z atrybutu xmlns, czy z prefiksu przestrzeni nazw. Ponadto, chociaż powinieneś zawsze myśleć w kategoriach URI i localNames, istnieją również sposoby uzyskania dostępu do przedrostka z dokumentu XML. Rzadko kiedy trzeba z nich korzystać.
Nie jest jasne, co dokładnie chcesz osiągnąć. Jakie są kryteria, które określają, których węzłów szukasz? Szukasz elementów opartych na ich przestrzeni nazw? W takim przypadku twój kod znałby przestrzeń nazw. Co do {my uri} jest "Składnia XPath", gdzie według specyfikacji XPath 1.0, czy uważasz, że ta składnia została zdefiniowana? Niezależnie od tego, czy wstawisz identyfikator URI przestrzeni nazw w nawiasach klamrowych, czy przekażesz identyfikator URI przestrzeni nazw do metody AddNamespace, nie powinno to mieć znaczenia dla kodu C#, w obu przypadkach identyfikator URI przestrzeni nazw musi być dostępny jako ciąg znaków. –
@Martin: Chciałbym określić przestrzeń nazw w XPath, ale mam tylko identyfikator URI przestrzeni nazw i bez przedrostka przestrzeni nazw. Przyjrzałem się bliżej, skąd "wymyśliłem" {} i prawdopodobnie przeszedłem niepoprawnie ... Mam to z tego odniesienia: http://www.jclark.com/xml/xmlns.htm. Dziękuję za wskazanie tego. Oczywiście, nawet jeśli nie jest to poprawne, wydaje się, że użyteczną rzeczą jest to, aby móc zrobić to łatwo ..;) –
Scott, musisz wybrać dowolny dozwolony prefiks, który ci się podoba, powiązać go z identyfikatorem URI przestrzeni nazw, który używasz AddNamespace (prefiks, namespaceURI) i użyj wybranego prefiksu w wyrażeniu XPath. Tak działa XPath, co najmniej XPath 1.0. Prefiks nie musi w ogóle istnieć w wejściowym kodzie XML lub może być inny niż w wejściowym kodzie XML, wybór elementu nastąpi na podstawie dopasowania przestrzeni nazw, a nie przedrostka. –