简体   繁体   English

XML:声称名称空间前缀在事实上未声明

[英]XML: A namespace prefix is claimed to be not declared when it fact it is

We've got a web service that returns a very simple XML. 我们有一个Web服务,它返回一个非常简单的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>

The caller gets this XML no problem, using XMLHTTP. 调用者使用XMLHTTP获取此XML没问题。 But XPath queries don't work agains this XML because of "Reference to undeclared namespace prefix: 't'" 但是,由于“引用未声明的命名空间前缀:'t',因此XPath查询不会再次使用此XML

Why so? 为什么这样? I'd say the 't' prefix is somewhat declared. 我会说't'前缀有点声明。 Is this document invalid in any way? 该文件是否以任何方式无效?

In case you wonder why we had to use XmlNamespaceDeclarations to add namespace prefixes in the first place, that is because otherwise the resulting document cannod be queried upon becase it has a target namespace but hasn't got a prefix for it, so XPath ignores node names because they don't belong to requested (empty) namespace, and we don't wan't to use constructions like "//*[namespace-uri()='http://our.website.com/ns' and local-name()='RequestResult']" . 如果你想知道我们为什么必须首先使用XmlNamespaceDeclarations添加名称空间前缀 ,那是因为否则生成的文档会被查询,因为它有一个目标名称空间但没有前缀,所以XPath忽略节点名称,因为它们不属于请求的(空)名称空间,我们不想使用像"//*[namespace-uri()='http://our.website.com/ns' and local-name()='RequestResult']"

You've already answered the question, but it's worth understanding why this is. 你已经回答了这个问题,但值得理解为什么会这样。

The namespace that an element is in cannot be determined solely by the namespace prefix. 元素所在的命名空间不能仅由命名空间前缀确定。 To find what namespace an element named t:foo is in, you have to search up the ancestor-or-self axis until you find the nearest node that defines the namespace for t: . 要查找名为t:foo的元素所在的命名空间,必须搜索祖先或自定轴,直到找到为t:定义命名空间的最近节点。 For instance: 例如:

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

In that document, every element whose name is one is in the ns-one namespace, and every element whose name is two is in the ns-two namespace. 在该文档中,名称为one每个元素都在ns-one名称空间中,名称为two每个元素都在ns-two名称空间中。 You can tell that the deepest element in that document is in ns-two not because t: intrinsically means ns-two , but because if you search up the ancestor-or-self axis, the first element that you hit with an xmlns:t attribute on it - its parent - tells you the namespace. 你可以看出该文档中最深的元素是ns-two不是因为t:本质上意味着ns-two ,而是因为如果你搜索祖先或自己的轴,你用xmlns:t命中的第一个元素xmlns:t它的属性 - 它的父 - 告诉你命名空间。

Given that, which nodes should the XPath expression //t:* match? 鉴于此,XPath表达式//t:*匹配哪些节点? It's impossible to say, because what namespace t: is mapped to changes throughout the document. 这是不可能的,因为什么名称空间t:映射到整个文档的变化。

Also, namespace prefixes are temporary, but namespaces are permanent. 此外,名称空间前缀是临时的,但名称空间是永久性的。 If you know that one is in ns-one , you really, truly don't care whether its prefix is t: or x: or if it has no prefix at all and just an xmlns attribute. 如果你知道one是在ns-one ,你真的,真的不在乎它的前缀是t:还是x:或者它是否根本没有前缀而只是一个xmlns属性。

When you're querying an XML document with XPath, you need a way of specifying what namespace a given element is in. And that's what SelectionNamespaces in a DOMDocument, or a namespace manager in C#, or whatever are for: they tell you what namespaces the prefixes in your XPath queries represent. 当您使用XPath查询XML文档时,您需要一种方法来指定给定元素所在的命名空间。这就是DOMDocument中的SelectionNamespaces ,或C#中的命名空间管理器,或者其他用于它们的内容:它们告诉您哪些命名空间XPath查询中的前缀表示。 So if I've set the prefix a: to ns-one , the XPath //a:one will find me all of the elements named one in the ns-one namespace, irrespective of what the actual prefix they're using in the document I'm searching is. 因此,如果我将前缀a:设置为ns-one ,则XPath //a:one将找到ns-one命名空间中名为one所有元素,而不管它们在我正在搜索的文件是。

This is a little counterintuitive when you're first learning it, but really, it's the only way that makes any sense at all. 当你第一次学习它时,这有点违反直觉,但实际上,这是唯一有意义的方法。

Surprisingly enough (for me), this is the default behaviour for XPath. 令人惊讶的是(对我而言),这是XPath的默认行为。 By default, namespace prefixes are not allowed in an XPath query. 默认情况下,XPath查询中不允许使用名称空间前缀。

To resolve this, one must register desired prefixes with SelectionNamespaces property of the DOMObject. 要解决此问题,必须使用DOMObject的SelectionNamespaces属性注册所需的前缀。

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

After that one can use expressions qualified with t: in XPath queries. 之后,可以在XPath查询中使用用t:限定的表达式。 This also resolvers the original problem that forced us to use XmlNamespaceDeclarations in the first place. 这也解决了原来的问题,迫使我们首先使用XmlNamespaceDeclarations。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM