在php中使用xpath忽略命名空间

时间:2017-08-10 08:44:29

标签: php xpath xml-namespaces

我想从xml文件中提取一些标签。 xml文件可能如下所示:

<mediawiki xmlns="http://www.mediawiki.org/xml/export-0.10/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mediawiki.org/xml/export-0.10/ http://www.mediawiki.org/xml/export-0.10.xsd" version="0.10" xml:lang="de">
[... some more tags ...]
  <page>
    <title>Title 1</title>
    [... some more tags ...]
  </page>
  <page>
    <title>Title 2</title>
    [... some more tags ...]
  </page>
</mediawiki>

我用的时候 https://www.freeformatter.com/xpath-tester.html 拉“//标题”一切正常,我收到两个标题。

但是当我使用以下php时:

$xml = simplexml_load_file('articles.xml');
$result = $xml->xpath('//title');
var_dump($result);

结果数组为空。

我已经检查了许多类似的问题,发现如果我使用相同的URL设置registerXPathNamespace,它会起作用。但是,我正在阅读的XML来自几个使用不同软件的外部源(以上只是一个可能的例子)。他们可能随时改变。因此,每次打开XML时,我都需要读出URL并将其放入registerXPathNamespace。使其工作的另一个选择是从XML中剥离xmlns。如果我想要做的就是提取“标题”(和其他一些)标签,无论名称空间是什么,这两个选项似乎都非常复杂。

是否有一种简单的方法可以告诉xpath忽略命名空间? (如果没有办法忽略它:什么是最简单和持久的解决方案,以避免更改URL的问题?)

到目前为止,我正在使用硬编码

foreach ($xml->page as $page) {
  $title = $page->title;
  //[... do something ...]
}

哪个有效。但是我认为xpath会很方便(更灵活,不是硬编码,更耐用)并且想尝试一下。

3 个答案:

答案 0 :(得分:0)

您可以通配符名称空间,例如//*:title

答案 1 :(得分:0)

您可以从文档中获取名称空间,然后从这些名称中注册默认名称空间。由于默认命名空间以空白键结束,这有点令人痛苦,但这就是为什么从数组中获取第一个值然后使用它有点软糊涂。

所以代码类似于:

$xml = simplexml_load_file('articles.xml');
$ns = $xml->getDocNamespaces();
$xml->registerXPathNamespace('def', array_values($ns)[0]);
$result = $xml->xpath('//def:title');
var_dump($result);

答案 2 :(得分:0)

尽管选择的注册默认名称空间的解决方案可行,但这还要求我似乎毫无理由地弄乱了xpath查询。在我的特殊情况下,我怀疑还有许多其他情况,从文档中完全删除名称空间会更有帮助。不幸的是,没有出现可以使用php中的DOM工具来做到这一点,所以我不得不求助于正则表达式。我要说的是,我真的很讨厌这样做,因为我是一再因为使用正则表达式来操纵XML和HTML的人而不断地追求他人的人。

无论如何,这对我有用:

$xml = file_get_contents('my_document.xml');
$xml = preg_replace('/(xmlns|xsi)[^=]*="[^"]*" ?/i', '', $xml);
$doc = simplexml_load_string($xml);

voilà,现在您可以根据需要查询xpath,而无需命名空间前缀:

$result = $xml->xpath('//title');

根据您的文档,这可能不是一个好主意,尤其是在元素上有名称空间前缀的情况下,但是在许多基本情况下,它就可以正常工作。