Xml 命名空间破坏了我的 xpath!

我有以下 XML:

<List xmlns="http://schemas.microsoft.com/sharepoint/soap/">
<Fields>
<Field>
</Field>
</Fields>
</List>

这是从 SharePointWeb 服务返回的 XML 的精简版本。我还有以下 xPath:

/List/Fields/Field

当我从 XML 中删除 xmlns时,xPath 工作正常。当它在里面的时候,我的 xPath 什么也找不到。我是否应该对 xPath 做一些不同的处理?不能修改 XML。

103984 次浏览

您最有可能必须在 xpath 库中注册该名称空间 uri。根据库的不同,您可以使用“ default”前缀,或者您可能需要给它一个命名的前缀,并在 xpath 查询中使用它。

例如,在 php 中(因为没有指定语言)使用 DOMXPath 可以执行以下操作:

$xpath = new DOMXPath($document);
$xpath->registerNamespace('x', 'http://schemas.microsoft.com/sharepoint/soap/');
$xpath->query('/x:List/x:Fields/x:Field');

List 元素已经用默认名称空间定义,并且内部的所有元素都采用这种方式。

因此,您需要像下面这样忽略元素名称空间:

/*[local-name()='List']/*[local-name()='Fields]/*[local-name()='Field]

但这意味着 xpath 将拾取 List-Fields-Field 中的任何其他元素

您可以执行名称空间检查和本地名称检查,如下所示:

/*[local-name()='List' and namespace-uri()='http://schemas.microsoft.com/sharepoint/soap/']/*[local-name()='Fields' and namespace-uri()='http://schemas.microsoft.com/sharepoint/soap/']/*[local-name()='Field' and namespace-uri()='http://schemas.microsoft.com/sharepoint/soap/']

或者,您可以向库注册名称空间,然后显式指定该名称空间的前缀,并将其添加到 xpath 表达式中,该表达式的方法取决于您正在使用的库。

我还有以下 xPath:

/List/Fields/Field

当我从 XML 中删除 xmlns 时 XPath 运行良好,当它在 我的 xPath 什么都没找到

If you cannot register a namespace binding and cannot use (assuming the registered prefix is "x"):

/x:List/x:Fields/x:Field

然后还有另一种方式 :

/*[name()='List']/*[name()='Fields']/*[name()='Field']

我只是在使用 Xalan-c 时遇到了这个问题

我最初没有完全理解的一点是,XPath 或 XSLT 名称空间别名/前缀可能与文档的别名/前缀不同——这取决于您的名称空间解析器。

似乎如果文档上有一个名称空间,那么它就无法与 path 元素匹配,除非使用名称空间。(标准但不总是遵循?)

XalanDocumentPrefixResolver 将把 XPath 或 XSLT 名称空间映射到 URI,并尝试通过获取前缀来给它们 id ——在没有前缀的情况下,它使用的名称变成了 xmlns

/xmlns:List/xmlns:Fields/xmlns:Field

或者,您可以创建自己的解析器,但是它仍然需要在 xpath: (中使用最小的名称空间

这是我在测试时拼凑的一个,不能保证内存

// don't care what prefix given, there can only be the one
struct NoPrefixResolver : public xalanc::PrefixResolver {


NoPrefixResolver(const xalanc::XalanDOMString&   theURI) : m_uri(theURI){}


virtual const xalanc::XalanDOMString*
getNamespaceForPrefix(const xalanc::XalanDOMString&     prefix) const {
return &m_uri;
}


virtual const xalanc::XalanDOMString&   getURI() const {
return m_uri;
}


const xalanc::XalanDOMString    m_uri;
};


/x:List/x:Fields/x:Field
/a:List/b:Fields/c:Field

如果可以跳过 document 元素,下面的 XPath 也可以提供帮助:

//Fields/Field

只要在任何其他节点之下没有“ Fields”,只要子节点没有名称空间,就可以这样做。