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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5239685/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-06 14:35:56  来源:igfitidea点击:

Xml Namespace breaking my xpath!

xmlxpathxml-namespaces

提问by Abe Miessler

I have the following XML:

我有以下 XML:

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

This is a slimmed down version of XML being returned from a SharePoint web service. I also have the following xPath:

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

/List/Fields/Field

When I remove the xmlnsfrom my XML the xPath works fine. When it's in there my xPath finds nothing. Is there something I should be doing differently with my xPath? Modifying the XML is not an option.

当我xmlns从我的 XML 中删除时,xPath 工作正常。当它在那里时,我的 xPath 什么也没找到。我应该对 xPath 做一些不同的事情吗?修改 XML 不是一个选项。

回答by Dimitre Novatchev

I also have the following xPath:

/List/Fields/Field 

When I remove the xmlns from my XML the xPath works fine. When it's in there my xPath finds nothing

我还有以下 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”):

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

then there is another way:

那么还有另一种方式

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

回答by rogermushroom

The List element has been defined with a default namespace and this is adopted by all elements inside.

List 元素已经定义了一个默认命名空间,并且它被内部的所有元素采用。

You therefore need to ignore the element namespace like so:

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

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

but this means that the xpath will pick up any other element with List - Fields - Field

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

You can do a namespace check as well as a local-name check like so:

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

/*[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/']

Or you can register the namespace with the library and then explicitly specify the prefix for that namespace and add it to xpath expression, the method of which is dependent on the library you are using.

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

回答by Anomie

You most likely have to register that namespace uri with your xpath library. Depending on the library, you may be able to use the 'default' prefix or you may need to give it a named prefix and use that in your xpath queries.

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

For example, in php (since you didn't specify a language) using DOMXPath you could do something like this:

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

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

回答by Greg Domjan

I've just been having this issue while using Xalan-c

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

The bit I didn't quite get initially is that the XPath or XSLT namespace aliases/prefixes can be different to that of the document - depending on your namespace resolver.

我最初不太明白的一点是 XPath 或 XSLT 名称空间别名/前缀可能与文档的名称不同 - 取决于您的名称空间解析器。

It appears that if there is a namespace on the doc, then it fails to match a path element unless a namespace is used. (standard but not always followed?)

看来,如果文档上有命名空间,则除非使用命名空间,否则它无法匹配路径元素。(标准但并不总是遵循?)

The XalanDocumentPrefixResolver will map XPath or XSLT namespaces to URI and try and give them id by getting the prefix - where there is no prefix it used the name which turned into xmlns

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

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

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

Alternatively you could create your own resolver, but it still requires a minimal namespace used in the xpath :(

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

Here is one I hacked together while testing, no guarantee of memory

这是我在测试时一起破解的,不保证内存

// 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 

回答by David Gausmann

If you can skip the document element, the following XPath can also help:

如果您可以跳过文档元素,以下 XPath 也可以提供帮助:

//Fields/Field

This works as long as you don't have 'Fields' below any other node and as long the sub nodes have no namespace.

只要您在任何其他节点下方没有“字段”,并且子节点没有命名空间,这就会起作用。