从xml中解析具有相同名称的特定行

时间:2014-07-07 13:32:31

标签: php xml simplexml

我有一个包含10条记录的xml,结构为:

<entry>
<title>My Title</title>
<link rel="alternate" type="text/html" href="http://myweb.com/posts/one.html"/>
<published>2014-07-07T00:34:00+00:00</published>
<updated>2014-07-07T00:34:00+00:00</updated>
<id>http://myweb.com/posts/one.html</id>
<author>
<name>Myweb.com</name>
</author>
<content>
Some Content Here
</content>
<link rel="enclosure" href="http://myweb.com/uploads/300px-300px.jpg" type="image/jpeg" length=""/>
</entry>

我正在使用下面的代码解析它,它几乎工作得很好,除了我无法获取重复行中的图像网址:

 <link rel="enclosure" href="http://myweb.com/uploads/300px-300px.jpg" type="image/jpeg" length=""/>

我的代码是:

$url = "http://myweb.com/posts.xml";
$xml = simplexml_load_file($url);
foreach($xml->entry as $PRODUCT) {

$my_title = trim($PRODUCT->title);
$url = trim($PRODUCT->id);
$im = (string)$PRODUCT->xPath('//link[@rel="enclosure"]');

echo $my_title . " " . $url . " " . $im;
echo "<br>";

}

这:$im = (string)$PRODUCT->xPath('//link[@rel="enclosure"]'); 返回&#34;数组&#34;而不是网址inisde href。

由于

2 个答案:

答案 0 :(得分:2)

  

这:$im = (string)$PRODUCT->xPath('//link[@rel="enclosure"]');返回“Array”而不是url inisde href。

每当你在PHP中看到一个包含单词“Array”的字符串时,你需要别的东西,你需要想一下“嗯,我好像把一个数组转换为一个字符串,这是怎么发生的?” (同样,如果您意外地看到字符串“A”,请考虑它是“Array”的单字母子字符串的可能性。)

在这种情况下,原因很简单:如果你查找the manual page for the SimpleXMLElement::xpath() method,你会看到它返回一个数组,除非有错误(找不到匹配不是错误,并且会给你一个空数组。)

这是令人惊讶的唯一原因是,大多数methods on that class返回同一个类的另一个实例,对于像(string)强制转换这样的事情具有魔术重载。然而,所有这些对象表示XML文档的或多或少的连贯片段(例如,一个或多个连续节点,或由特定标签名称过滤的兄弟姐妹),并且永远不能表示“无”。 XPath结果可能为空,或者包含来自整个文档的各种类型的节点;我不确定,但我怀疑这就是为什么在这里选择数组返回而不是另一种SimpleXMLElement对象的原因。

因此,$PRODUCT->xPath('//link[@rel="enclosure"]')[0]将为您提供第一个结果(如果您不能依赖至少PHP 5.4,或者想要在没有匹配的节点之间插入检查,那么$xpath_results = $PRODUCT->xPath('//link[@rel="enclosure"]'); $im = $xpath_results[0]。< / p>

但这里有一些额外的捕获量:

  • 命名空间:as ThW points out,Atom提要通常具有XML命名空间声明,您需要通过注册前缀来处理XPath查询,例如: $product->registerXpathNamespace('atom', 'http://www.w3.org/2005/Atom');然后在您的XPath表达式中使用它(例如//atom:link而不是//link)。
  • 您没有指定您想要href属性:更改您的XPath表达式以选择它(//link[@rel="enclosure"]/@href)或更改您从SimpleXMLElement返回的抓取它的访问权限( $xpath_results[0]['href'])。

坚持下去(并摆脱那个丑陋和不寻常的全帽变量名称),紧凑版本(没有错误检查,最低可读性)将是:

$product->registerXpathNamespace('atom', 'http://www.w3.org/2005/Atom');
(string)$product->xPath('//atom:link[@rel="enclosure"]')[0]['href']

$product->registerXpathNamespace('atom', 'http://www.w3.org/2005/Atom');
(string)$product->xPath('//atom:link[@rel="enclosure"]/@href')[0]

答案 1 :(得分:1)

看起来它是Atom提要的一部分。这意味着它有一个命名空间。要在具有命名空间的XML上使用Xpath,您必须在命名空间中注册别名/前缀。这与SimpleXML有点复杂,你必须在每个元素上执行它,你正在调用xpath()方法,它将始终返回一个SimpleXMLElement对象数组。

$feed = simplexml_load_string($xml);

foreach($feed->entry as $product) {
  $product->registerXpathNamespace('atom', 'http://www.w3.org/2005/Atom');
  var_dump((string)$product->xpath('//atom:link[@rel="enclosure"]')[0]['href']);
}

演示:https://eval.in/170439

使用DOMXpath这更容易,命名空间只需要在DOMXpath对象上注册一次,DOMXpath :: evaluate()可以返回标量值。第二个参数是Xpath表达式的上下文:

$dom = new DOMDocument();
$dom->loadXml($xml);
$xpath = new DOMXpath($dom);
$xpath->registerNamespace('atom', 'http://www.w3.org/2005/Atom');

foreach($xpath->evaluate('//atom:entry') as $product) {
  var_dump($xpath->evaluate('string(atom:link[@rel="enclosure"]/@href)', $product));
}

演示:https://eval.in/170444