PHP XPath 搜索返回 0 个结果 [英] PHP XPath search returning 0 results

查看:27
本文介绍了PHP XPath 搜索返回 0 个结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面我有一个 PHP 脚本,我需要搜索一个 XML 文件并找到 的 ID.出于某种原因,目前它返回 0 结果,我不知道为什么.如果有人能明白为什么它会返回 0 个结果,如果他们能让我知道原因,我将不胜感激.

Below I have a PHP script that I need to search through an XML file and find the ID for <AnotherChild>. For some reason, at the moment it returns 0 results and I can't figure out why. If anyone can see why it's returning 0 results I'd really appreciate it if they could let me know why.

XML:

<TransXChange xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.transxchange.org.uk/" xsi:schemaLocation="http://www.transxchange.org.uk/ http://www.transxchange.org.uk/schema/2.1/TransXChange_general.xsd" CreationDateTime="2013-07-12T18:12:21.8122032+01:00" ModificationDateTime="2013-07-12T18:12:21.8122032+01:00" Modification="new" RevisionNumber="3" FileName="swe_44-611A-1-y10.xml" SchemaVersion="2.1">
    <Node1>...</Node1>
    <Node2>...</Node2>
    <Node3>...</Node3>
    <Node4>...</Node4>
    <Node5>...</Node5>
    <Node6>...</Node6>
    <Node7>
        <Child>
            <id>ABCDEFG123</id>
        </Child>
        <AnotherChild>
            <id>ABCDEFG124</id>
        </AnotherChild>
    </Node7>
    <Node8>...</Node8>
</TransXChange>

PHP:

<?php

  $xmldoc = new DOMDocument();
  $xmldoc->load("directory1/directory2/file.xml");

  $xpathvar = new DOMXPath($xmldoc);
  $xpathvar->registerNamespace('transXchange', 'http://www.transxchange.org.uk/');

  $queryResult = $xpathvar->query('//AnotherChild/id');
  foreach($queryResult as $result) {
    echo $result->textContent;
  }
?>

谢谢

推荐答案

评论中链接的两个问题确实回答了这个问题,但他们没有说清楚为什么他们回答它IMO,因此我将在我在聊天中的回答之后添加此内容.

The two questions linked in comments do actually answer this question, but they don't quite make it clear enough why they answer it IMO, so I'll add this following my answer in chat.

考虑以下 XML 文档:

Consider the following XML document:

<root>
  <child>
    <grandchild>foo</grandchild>
  </child>
</root>

这根本没有 xmlns 属性,这意味着您可以查询 //grandchild 并获得您期望的结果.每个节点都位于默认命名空间中,因此无需在 XPath 中注册命名空间即可寻址所有内容.

This has no xmlns attributes at all, which means you can query //grandchild and get the result you expect. Every node is in the default namespace, so everything can be addressed without registering a namespace in XPath.

现在考虑:

<root xmlns="http://www.bar.com/">
  <child>
    <grandchild>foo</grandchild>
  </child>
</root>

这声明了 http://www.bar.com/ 的命名空间,因此您必须使用该命名空间来寻址成员节点.

This declares a namespace of http://www.bar.com/ and as a result you must use that namespace to address a member node.

正如您已经发现的,这样做的方法是使用 DOMXPath::registerNamespace() - 但您错过的关键点是(在 PHP 的 XPath 实现中)每个命名空间都必须注册一个前缀,并且您必须使用该前缀来寻址属于它的节点.无法在 XPath 中使用空前缀注册命名空间.

As you have already figured out, the way to do this is to use DOMXPath::registerNamespace() - but the crucial point that you missed is that (in PHP's XPath implementation) every namespace must be registered with a prefix, and you must use that prefix to address nodes that belong to it. It is not possible register a namespace in XPath with an empty prefix.

因此,鉴于上面的第二个示例,让我们看看如何执行原始的 //grandchild 查询:

So, given the second example above, lets look at how we would execute the original //grandchild query:

<?php

    $doc = new DOMDocument();
    $doc->loadXML($xml);

    $xpath = new DOMXPath($doc);
    $xpath->registerNamespace('bar', 'http://www.bar.com/');

    $nodes = $xpath->query('//bar:grandchild');
    foreach($nodes as $node) {
        // do stuff with $node
    }

注意我们如何使用它的 URI 注册命名空间,并且我们指定了一个前缀.即使原始 XML 不包含此前缀,我们仍会在查询中使用该前缀 - example.

Note how we registered the namespace using it's URI, and we specified a prefix. Even though the original XML did not contain this prefix, we use the prefix in the query - example.

要了解原因,让我们看看另一段 XML:

To understand why, lets look at another piece of XML:

<baz:root xmlns:baz="http://www.bar.com/">
  <baz:child>
    <baz:grandchild>foo</baz:grandchild>
  </baz:child>
</baz:root>

此文档与第二个文档语义相同 - 代码示例与 (证明).前缀与命名空间是分开的.请注意,尽管这在文档中使用了 baz: 前缀,但 XPath 使用了 bar: 前缀.这是因为标识命名空间的想法是 URI,不是前缀.

This document is semantically identical to the second - the code sample would work equally well with either (proof). The prefix is separate from the namespace. Note that even though this uses a baz: prefix in the document, the XPath uses the bar: prefix. This is because the think that identifies the namespace is the URI, not the prefix.

因此,当文档使用命名空间时,我们必须使用命名空间,而不是针对它,通过在 XPath 中注册命名空间并使用我们注册它的前缀来引用属于的任何节点到那个命名空间.

So when a document uses a namespace, we must work with the namespace, not against it, by registering the namespace in XPath and using the prefix we registered it against to refer to any nodes that belong to that namespace.

为完整起见,当我们将这些原则应用于您的原始文档时,您将与问题中的代码一起使用的查询是:

For completeness, when we apply these principles to your original document, the query that you would use with the code in the question is:

//transXchange:AnotherChild/transXchange:id

这篇关于PHP XPath 搜索返回 0 个结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆