ChatGPT解决这个技术问题 Extra ChatGPT

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

我有以下 XML:

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

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

/List/Fields/Field

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

不,这不是重复的。该问题专门针对 C#,而这严格来说是 xpath/xml。此外,他的命名空间不是空白的,而我的是。
您需要某种程度的抽象......您正在询问如何使用 XPath 表达式选择默认命名空间下的元素。这是最常见的问题。

P
Patrick from NDepend team

我还有以下 xPath: /List/Fields/Field 当我从 XML 中删除 xmlns 时,xPath 工作正常。当它在那里时,我的 xPath 什么也没找到

如果您无法注册命名空间绑定并且无法使用(假设注册的前缀为“x”):

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

那么还有另一种方法:

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

那么如何访问这些属性呢?
@KaiJauk,无前缀属性始终位于“无命名空间”中,无论它们的父元素是否在默认命名空间的范围内。所以,没问题。当然,也可以使用 @*[name() = 'myName']@*[name() = 'myPrefix:myName']
@36305 啊好吧,这意味着我可以像 /*[local-name()="mynode" and @myAttr="value"] 一样使用它?
如果您所指的命名空间有前缀 (xmlns:x),则 name() 将包含前缀 (x:List)。 local_name() 为您提供不带前缀的元素名称(列表)。
@andrew.rockwell 是的
r
rogermushroom

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 表达式,其方法取决于您使用的库。


此答案有效,而接受的答案无效....感谢@zode64 的帮助。我正在努力让我的 xpath 表达式为包含 xml 的名称空间工作。现在有了这个,我不必再担心名称空间了。万分感谢..
A
Anomie

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

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

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

是的,我是一个 .NET 人,通常我的解决方案是 .NET 等价物。不幸的是,我们正在使用第三方“快速”开发环境,它无法让我们这样做......
此外,如果没有前缀,为什么它们甚至包含命名空间? (xPath 的 x: 部分)
有一个命名空间。它只是在这个特定文件中使用“默认”前缀。该文件在语义上是相同的,如果它是 <foo:List xmlns:foo="http://schemas.microsoft.com/sharepoint/soap/"><foo:Fields><foo:Field></foo:Field></foo:Fields></foo:List>
@Abe Miessler 您在 xml 中提到的命名空间是根元素及其子元素的默认命名空间。在您的 xpath 中,您必须使用相同的 uri 命名空间,但不能使用相同的前缀,这只是一个标签。如果您没有注册您的命名空间,您的 xpath 将引用具有空 uri 的元素。您还可以使用空前缀注册命名空间,因此您的 xpath 不需要 'x:' 前缀。
绑定名称空间的能力对于 XPath 库来说非常重要,如果你的库不提供这种能力,你应该把它扔掉。
G
Greg Domjan

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

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

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

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 

D
David Gausmann

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

//Fields/Field

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