XPath (намеренно) не предназначен для случая, когда вы хотите использовать то же выражение XPath для некоторых неизвестных пространств имен, которые существуют только в документе XML. Предполагается, что вы заранее знаете пространство имен, объявите пространство имен процессору XPath и будете использовать имя в своем выражении. Ответы Мартина и Дэна показывают, как это сделать в C #.
Причина этой трудности лучше всего выражена в пространствах имен XML spec:
Мы предполагаем приложения расширяемого языка разметки (XML), в которых один XML-документ может содержать элементы и атрибуты (здесь называемые «словарь разметки»), которые определены и используются несколькими программными модулями. Одной из причин этого является модульность: если существует такой словарь разметки, который понятен и для которого имеется полезное программное обеспечение, лучше повторно использовать эту разметку, а не заново ее изобретать.
Такие документы, содержащие несколько словарей разметки, создают проблемы распознавания и коллизий. Программные модули должны иметь возможность распознавать элементы и атрибуты, которые они предназначены для обработки, даже в условиях «коллизий», возникающих, когда разметка, предназначенная для какого-либо другого программного пакета, использует то же имя элемента или имя атрибута.
Эти соображения требуют, чтобы конструкции документа имели имена, сконструированные так, чтобы избежать столкновений между именами из разных словарей разметки. Эта спецификация описывает механизм, пространства имен XML, который выполняет это, назначая расширенные имена элементам и атрибутам.
То есть пространства имен должны использоваться, чтобы удостовериться, что вы знаете, о чем говорит ваш документ: элемент <head>
говорит о преамбуле к документу XHTML или заголовке somebody в документе AnatomyML? Вы никогда не «должны» быть агностиком в отношении пространства имен, и это почти первое, что вы должны определить в любом словаре XML.
Должна быть возможность делать то, что вы хотите, но я не думаю, что это можно сделать в одном выражении XPath. Прежде всего вам нужно покопаться в документе и извлечь все namespaceURI, затем добавить их в менеджер пространства имен и затем запустить нужное выражение XPath (и вам нужно кое-что узнать о распределении пространств имен в документе указать, или у вас есть много выражений для запуска). Я думаю, что вам, вероятно, лучше всего использовать что-то кроме XPath (например, DOM или SAX-подобный API) для поиска namespaceURI, но вы также можете изучить ось пространства имен XPath (в XPath 1.0), используйте namespace-uri-from-QName
функцию (в XPath 2.0) или используйте выражения, как у Олега "configuration/*[local-name() = 'MyNode']"
. В любом случае, я думаю, что вам лучше всего избегать написания XPath, независимого от пространства имен! Почему вы не знаете свое пространство имен раньше времени? Как вы собираетесь избегать совпадений с вещами, которые вы не собираетесь сопоставлять?
Редактировать - вы знаете пространство именURI?
Так что получается, что ваш вопрос смутил нас всех. Очевидно, вы знаете URI пространства имен, но вы не знаете префикс пространства имен, который используется в документе XML. Действительно, в этом случае префикс пространства имен не используется, и URI становится пространством имен по умолчанию, где он определен. Главное, что нужно знать, это то, что выбранный префикс (или отсутствие префикса) не имеет отношения к вашему выражению XPath (и синтаксическому анализу XML в целом). Атрибут prefix / xmlns - это всего лишь один из способов связать узел с URI пространства имен, когда документ выражен в виде текста. Возможно, вы захотите взглянуть на этот ответ , где я попытаюсь уточнить префиксы пространства имен.
Вы должны попытаться представить XML-документ таким же образом, как и анализатор - у каждого узла есть URI пространства имен и локальное имя. Правила префикса / наследования пространства имен просто экономят при наборе URI много раз. Один из способов записать это в нотации Кларка: то есть вы пишете {http://www.example.com/namespace/example}LocalNodeName,, но эта нотация обычно используется только для документации - XPath ничего не знает об этой нотации.
Вместо этого XPath использует свои собственные префиксы пространства имен. Что-то вроде /ns1:root/ns2:node
. Но они полностью отделены и не имеют ничего общего с какими-либо префиксами, которые могут использоваться в исходном документе XML. Любая реализация XPath будет иметь возможность сопоставить свои собственные префиксы с URI пространства имен. Для реализации C # вы используете XmlNamespaceManager
, в Perl вы предоставляете хеш, xmllint принимает аргументы командной строки ... Так что все, что вам нужно сделать, - это создать произвольный префикс для известного вам URI пространства имен и использовать этот префикс в XPath выражение. Неважно, какой префикс вы используете, в XML вы просто заботитесь о сочетании URI и localName.
Еще одна вещь, которую нужно помнить (это часто удивляет), это то, что XPath не выполняет наследование пространства имен. Вам необходимо добавить префикс для каждого, у которого есть пространство имен, независимо от того, происходит ли пространство имен от наследования, атрибута xmlns или префикса пространства имен. Кроме того, хотя вы всегда должны думать с точки зрения URI и localNames, существуют также способы доступа к префиксу из XML-документа. Это редко приходится использовать их.