XPath (намеренно) не предназначен для случая, когда вы хотите использовать одно и то же выражение XPath для некоторых неизвестных пространств имен, которые существуют только в документе XML. Предполагается, что вы заранее знаете пространство имен, объявляете пространство имен процессору XPath и используете это имя в своем выражении. Ответы Мартина и Дэна показывают, как это сделать на C #.
Причина этой трудности лучше всего описана в спецификации пространств имен XML:
Мы представляем себе приложения Extensible Markup Language (XML), в которых один XML-документ может содержать элементы и атрибуты (здесь называемые «словарем разметки»), которые определены для нескольких программных модулей и используются ими. Одним из мотивов этого является модульность: если существует такой словарь разметки, который хорошо понят и для которого доступно полезное программное обеспечение, лучше повторно использовать эту разметку, чем изобретать ее заново.
Такие документы, содержащие несколько словарей разметки, создают проблемы распознавания и коллизии. Программные модули должны иметь возможность распознавать элементы и атрибуты, для обработки которых они предназначены, даже в условиях «коллизий», возникающих, когда разметка, предназначенная для какого-либо другого программного пакета, использует то же имя элемента или имя атрибута.
Эти соображения требуют, чтобы у конструкций документа были имена, построенные так, чтобы избежать конфликтов между именами из разных словарей разметки. Эта спецификация описывает механизм, пространства имен XML, который выполняет это путем присвоения расширенных имен элементам и атрибутам.
То есть предполагается, что пространства имен должны использоваться, чтобы убедиться, что вы знаете, о чем говорит ваш документ: говорит ли этот <head>
элемент о преамбуле к документу XHTML или о чьей-то голове в документе AnatomyML? Вы никогда не должны "быть агностиком" в отношении пространства имен, и это в значительной степени первое, что вы должны определить в любом словаре XML.
Должно быть возможно делать то, что вы хотите, но я не думаю, что это можно сделать в одном выражении XPath. Прежде всего, вам нужно порыться в документе и извлечь все URI пространств имен, затем добавить их в диспетчер пространств имен, а затем запустить фактическое выражение XPath, которое вы хотите (и вам нужно кое-что знать о распределении пространств имен в документе на этом точка, или вам нужно выполнить много выражений). Я думаю, вам, вероятно, лучше всего использовать что-то другое, кроме XPath (например, DOM или SAX-подобный API), чтобы найти URI пространства имен, но вы также можете изучить ось пространства имен XPath (в XPath 1.0), используйте _ 2_ (в XPath 2.0) или используйте такие выражения, как "configuration/*[local-name() = 'MyNode']"
Олега . В любом случае, я думаю, что лучше всего попытаться избежать написания XPath, не зависящего от пространства имен! Почему вы не знаете свое пространство имен заранее? Как вы собираетесь избегать совпадения вещей, которые вы не собираетесь совпадать?
Изменить - вы знаете namespaceURI?
Получается, что ваш вопрос всех нас запутал. По-видимому, вы знаете 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-документа. Редко приходится использовать их.
person
Andrew Walker
schedule
26.03.2010
foreach (XElement myNode in doc.Descendants("{lcmp}MyNode"))
. Конечно, вы также можете использовать переменную, напримерXNamespace df = "lcmp"; foreach (XElement myNode in doc.Descendants(df + "MyNode"))
- person Martin Honnen   schedule 27.03.2010