XML: префикс пространства имен, как утверждается, не объявлен - PullRequest
3 голосов
/ 26 января 2010

У нас есть веб-сервис, который возвращает очень простой XML.

<?xml version="1.0"?>
<t:RequestResult xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://our.website.com/ns/" xmlns:t="http://our.website.com/ns/">
  <t:Result>No candy for you today.</t:Result>
  <t:Success>false</t:Success>
</t:RequestResult>

Абонент без проблем получает этот XML, используя XMLHTTP. Но запросы XPath не работают против этого XML из-за "Ссылка на необъявленный префикс пространства имен: 't'"

Почему так? Я бы сказал, что префикс 't' несколько объявлен. Является ли этот документ недействительным в любом случае?

В случае, если вам интересно, почему нам пришлось использовать XmlNamespaceDeclarations для добавления префиксов пространства имен , во-первых, потому что иначе результирующий документ не может быть запрошен, поскольку у него есть целевое пространство имен, но он не префикс для него, поэтому XPath игнорирует имена узлов, поскольку они не принадлежат запрошенному (пустому) пространству имен, и мы не хотим использовать такие конструкции, как "//*[namespace-uri()='http://our.website.com/ns' and local-name()='RequestResult']".

Ответы [ 2 ]

7 голосов
/ 27 января 2010

Вы уже ответили на вопрос, но стоит понять, почему это так.

Пространство имен, в котором находится элемент, не может быть определено исключительно префиксом пространства имен. Чтобы найти, в каком пространстве имен находится элемент с именем t:foo, вы должны искать по оси ancestor-or-self, пока не найдете ближайший узел, который определяет пространство имен для t:. Например:

<t:one xmlns:t="ns-one">
   <t:one>
      <t:two xmlns:t="ns-two">
         <t:two/>
      </t:two>
   </t:one>
</t:one>

В этом документе каждый элемент с именем one находится в пространстве имен ns-one, а каждый элемент с именем two находится в пространстве имен ns-two. Вы можете сказать, что самый глубокий элемент в этом документе находится в ns-two не потому, что t: по сути означает ns-two, а потому, что если вы ищите ось предка или самого себя, первый элемент, который вы нажали с xmlns:t атрибут на нем - его родитель - сообщает вам пространство имен.

Учитывая, с какими узлами должно совпадать выражение XPath //t:*? Невозможно сказать, потому что то, что пространство имен t: сопоставлено с изменениями по всему документу.

Кроме того, префиксы пространства имен являются временными, но пространства имен являются постоянными. Если вы знаете, что one находится в ns-one, вам действительно все равно, является ли его префикс t: или x: или он вообще не имеет префикса и имеет только атрибут xmlns.

Когда вы запрашиваете XML-документ с помощью XPath, вам нужен способ указать, в каком пространстве имен находится данный элемент. И это то, что SelectionNamespaces в DOMDocument, или менеджер пространства имен в C #, или что-то для: они сообщают вам, какие пространства имен представляют префиксы в ваших запросах XPath. Поэтому, если я установил префикс a: в ns-one, XPath //a:one найдет мне все элементы с именем one в пространстве имен ns-one, независимо от того, какой фактический префикс они используют в документ, который я ищу -

Это немного нелогично, когда вы впервые изучаете его, но на самом деле, это единственный способ, который вообще имеет какой-либо смысл.

4 голосов
/ 26 января 2010

Удивительно (для меня), это поведение по умолчанию для XPath. По умолчанию префиксы пространства имен не разрешены в запросе XPath.

Чтобы решить эту проблему, необходимо зарегистрировать нужные префиксы с помощью свойства SelectionNamespaces объекта DOMObject.

objXML.setProperty("SelectionNamespaces", "xmlns:t='http://our.website.com/ns/'")

После этого можно использовать выражения с t: в запросах XPath. Это также решает исходную проблему, которая вынудила нас использовать XmlNamespaceDeclarations в первую очередь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...