2010-01-26 47 views
3

我们已经有了一个Web服务,它返回一个非常简单的XML。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> 

调用者使用XMLHTTP得到这个XML没问题。 但XPath查询不agains这个XML,因为工作“引用了未声明的命名空间前缀:‘T’”

为什么会这样?我会说't'前缀有点声明。 此文件以任何方式失效吗?

如果您想知道为什么我们必须首先使用use XmlNamespaceDeclarations to add namespace prefixes,那是因为否则生成的文档无法查询,因为它有一个目标名称空间,但没有它的前缀,所以XPath会忽略节点名称因为它们不属于被请求的(空的)名称空间,我们不想使用像"//*[namespace-uri()='http://our.website.com/ns' and local-name()='RequestResult']"这样的构造。

回答

7

您已经回答了这个问题,但值得理解。

元素所在的命名空间不能单独由命名空间前缀确定。要找到名为t:foo的元素所在的名称空间,您必须搜索祖先或自我轴,直到找到为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命名空间中,每一个元素,其名称为twons-two命名空间。您可以知道该文档中最深的元素在ns-two中,而不是因为t:本质上意味着ns-two,但是因为如果您向上搜索祖先轴或自己轴,则第一个元素用xmlns:t属性(其父 - 告诉你名字空间。

鉴于那个XPath表达式//t:*应匹配哪个节点?这是不可能的,因为什么名字空间t:被映射到整个文档中的变化。

另外,名称空间前缀是临时的,但名称空间是永久的。如果您知道onens-one中,那么您确实不在乎它的前缀是否为t:x:,或者它根本没有前缀,只有xmlns属性。

当您使用XPath查询XML文档时,您需要指定给定元素所在的命名空间的方式。这就是DOMDocument中的​​,或者C#中的名称空间管理器,或者其他用途:它们告诉您XPath查询中前缀的名称空间。因此,如果我已将前缀a:设置为ns-one,则XPath //a:one将在ns-one命名空间中找到名为one的所有元素,而不管它们在我正在搜索的文档中使用的实际前缀是什么。

当你第一次了解它时,这有点违反直觉,但实际上,这是唯一有意义的方法。

+0

我想使这是一个被接受的答案。但是它仅仅反驳了实际的答案,所以,为了未来读者的方便,你能否将我的答案纳入你的答案,以便我可以接受它作为一个整体? – GSerg 2010-01-28 13:29:30

3

令人惊讶的是(对我来说),这是XPath的默认行为。默认情况下,XPath查询中不允许使用名称空间前缀。

要解决此问题,必须使用DOMObject的​​属性注册所需的前缀。

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

后,人们可以使用XPath查询与t:合格表达式。 这也解决了原来的问题,迫使我们首先使用XmlNamespaceDeclarations。

相关问题