0

我正在尝试使用 Xpath 解析一些 XML。如果没有找到现有前缀,我正在寻找的功能是以编程方式注册具有特定前缀的命名空间。

当我在 Xpath 查询中使用前缀时,我得到一个空数组,这表明 Xpath 是有效的,它只是没有返回任何结果。

这是我正在使用的 XML 示例。请注意,这是我实际代码的简化版本,它是为了说明我的问题。

$xml =  <<<EOD
<rss version="2.0">
<channel>
    <title> somdomain - RSS Video Feed</title>
    <link>http://www.somdomain.com/</link>
    <description>Latest Videos Released on somdomain</description>
    <language>en-us</language>
    <pubDate>Thu, 19 Sep 2013 16:53:29 GMT</pubDate>
    <lastBuildDate>Thu, 19 Sep 2013 16:53:29 GMT</lastBuildDate>
    <image>
    <title>RSS Video Feed</title>
    <url>
    http://somdomain/cb/white.png
    </url>
    <link>http://www.somdomain.com/</link>
    </image>
    <link xmlns="http://www.w3.org/2005/Atom" href="http://www.somdomain.com/rss/" rel="self" type="application/rss+xml"/>
        <item>
            <title>The title </title>
            <link>
            http://www.somdomain.com/watch/8487128/
            </link>
            <description>
             <IMG border="1" src="http://cdn1.image.somdomain.php/8.jpg" />  <BR/> Length: 07:08 <BR/> Keywords:
            </description>
            <pubDate>Thu, 19 Sep 2013 16:00:11 GMT</pubDate>
            <guid>
            http://www.somdomain.com/watch/
            </guid>
        </item>
    </channel>
</rss>
EOD;
//default namespace
$d = "x";
$xml = new SimpleXMLElement($xml);
$ns = $xml->getNamespaces(true);
//there will only be one element here, $prefix is an empty string and 
// $url is http://www.w3.org/2005/Atom
foreach($ns as $prefix=>$url)
{
     //no prefix so use $d
    if($prefix=="")
    {
        $prefix = $d;
    }
    //register the namespace
    $xml->registerXPathNamespace($prefix, $url);
}


$result = $xml->xpath('/x:rss/x:channel/x:item');
//nothing
print_r($result);

我不确定为什么这不起作用。我在想注册命名空间本质上应该是现有命名空间的别名,因此“x:rss/x:channel/x:item”应该是一个有效的查询。谁能告诉我我在这里做错了什么?任何意见,将不胜感激。谢谢!

4

2 回答 2

2

<rss/>元素没有定义命名空间,只有元素<link href="http://www.somdomain.com/rss/" />(和所有后代)有这个。

使用查询

/rss/channel/item

反而。如果您开始选择此<link/>元素(或以下),您将需要命名空间:

/rss/channel/x:link/@href
于 2013-09-19T20:26:40.207 回答
2

首先,根据它们在文档中的别名来为您的 XPath 注册命名空间通常是一个坏主意:这似乎更容易,但前缀可能会在没有通知的情况下更改,而实际的命名空间名称 (URI) 将保持不变。(例如,生成的代码可能会简单地使用前缀,如ns1:,ns2:等;这些可以很容易地在以后交换)。

相反,您应该查看您关心的实际命名空间,并为它们选择自己的前缀。在这种情况下,您的评论已经指出,所涉及的唯一命名空间是http://www.w3.org/2005/Atom. 如果稍后添加任何代码,您将不会有任何代码使用它们,因此为它们注册前缀无论如何都不会对您有任何好处。

所以用这一行替换你的整个循环:

 $xml->registerXPathNamespace('x', 'http://www.w3.org/2005/Atom');

其次,您必须考虑哪些元素实际上位于该名称空间中。尽管它没有前缀,但它是在link元素内部声明的,因此它仅适用于文档的该部分作为默认命名空间。在该“范围”之外,没有xmlns声明默认命名空间的属性,因此其他元素位于没有 name 的命名空间中

正如Jens Erat 指出的那样,要在 XPath 中引用这些元素,您根本不使用名称空间前缀:

$result = $xml->xpath('/rss/channel/item');
于 2013-09-21T15:52:31.823 回答