如何使用SimpleXML获取具有命名空间的节点的属性?

发布于 2024-11-18 19:43:07 字数 1432 浏览 4 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

初懵 2024-11-25 19:43:07

您在问题中获得的代码确实有效。您已正确编写,您可以通过使用 从不在默认命名空间中作为根元素的命名空间元素访问属性SimpleXMLElement::children() 方法,带有 XML 命名空间相关参数 $ns$is_prefix

$youtube->entry->children('yt', TRUE)->duration->attributes()->seconds; // is "1870"

因为这基本上是正如你在问题中所做的那样,人们可以说你已经回答了你自己的问题。与扩展的在线演示 #2 进行比较。


长答案:您在问题中获得的代码确实有效。您可以在此处的在线交互式示例中找到示例 XML 和代码:在线演示 #1 - 它显示了不同 PHP 和 LIBXML 版本的结果。

代码:

$buffer = '<feed xmlns="http://www.w3.org/2005/Atom" xmlns:yt="http://gdata.youtube.com/schemas/2007">
    <entry>
        <yt:duration seconds="1870"/>
    </entry>
</feed>';

$xml = new SimpleXMLElement($buffer);

echo "ibxml version: ", LIBXML_DOTTED_VERSION, "\n";

foreach ($xml->entry as $item)
{
    //original comment: how to get seconds?
    $namespaces = $item->getNameSpaces(true);
    $yt         = $item->children($namespaces['yt']);
    $seconds    = $yt->duration->attributes();

    echo $seconds['seconds'], "\n"; // original comment: but doesn't work.
}

echo "done. should read 1870 one time.\n";

结果:

5.3.26、5.4.16 - 5.5.0 的输出

ibxml version: 2.9.1
1870
done. should read 1870 one time.

5.3.15 - 5.3.24、5.4.5 - 5.4.15 的输出

ibxml version: 2.8.0
1870
done. should read 1870 one time.

5.1.2 - 5.3.14、5.4.0 - 5.4.4 的输出

ibxml version: 2.7.8
1870
done. should read 1870 one time.

从这个角度来看,一切看起来都是如此 美好的。由于您没有给出任何具体的错误描述,因此很难说您的案例出了什么问题。您提出问题时可能使用的 PHP 版本已经过时,例如出现致命错误:

致命错误:调用未定义的方法 SimpleXMLElement::getNameSpaces()

可能也是由于 libxml 版本过时所致。根据测试,以下 libxml 版本可以在 PHP 5.1.2-5.5.0 上正常工作:

  • ibxml 版本:2.9.1
  • ibxml 版本:2.8.0
  • ibxml 版本:2.7.8

The code you've got in your question does work. You have correctly written that you can access an attribute from a namespaced-element that is not in the default namespace as the root-element by making use of the SimpleXMLElement::children() method with the XML-namespace related parameters $ns and $is_prefix:

$youtube->entry->children('yt', TRUE)->duration->attributes()->seconds; // is "1870"

As this is basically the same as you did in your question, one could say that you have answered your own question. Compare with the extended Online Demo #2.


Long answer: The code you've got in your question does work. You can find your example XML and code in an interactive example online here: Online Demo #1 - it shows the result with different PHP and LIBXML versions.

Code:

$buffer = '<feed xmlns="http://www.w3.org/2005/Atom" xmlns:yt="http://gdata.youtube.com/schemas/2007">
    <entry>
        <yt:duration seconds="1870"/>
    </entry>
</feed>';

$xml = new SimpleXMLElement($buffer);

echo "ibxml version: ", LIBXML_DOTTED_VERSION, "\n";

foreach ($xml->entry as $item)
{
    //original comment: how to get seconds?
    $namespaces = $item->getNameSpaces(true);
    $yt         = $item->children($namespaces['yt']);
    $seconds    = $yt->duration->attributes();

    echo $seconds['seconds'], "\n"; // original comment: but doesn't work.
}

echo "done. should read 1870 one time.\n";

Results:

Output for 5.3.26, 5.4.16 - 5.5.0

ibxml version: 2.9.1
1870
done. should read 1870 one time.

Output for 5.3.15 - 5.3.24, 5.4.5 - 5.4.15

ibxml version: 2.8.0
1870
done. should read 1870 one time.

Output for 5.1.2 - 5.3.14, 5.4.0 - 5.4.4

ibxml version: 2.7.8
1870
done. should read 1870 one time.

From this perspective everything looks fine. As you have not given any concrete error description it's hard to say what went wrong on your case. You were probably using a PHP version that was outdated the time you asked your question, for example getting a fatal error:

Fatal error: Call to undefined method SimpleXMLElement::getNameSpaces()

Probably also due to an outdated libxml version. According to the test, the following libxml versions work fine with PHP 5.1.2-5.5.0:

  • ibxml version: 2.9.1
  • ibxml version: 2.8.0
  • ibxml version: 2.7.8
悸初 2024-11-25 19:43:07

所以我找到了一种使用 xpath 来做到这一点的方法,这是最好的方法还是有一种与我在问题中的代码一致的方法?只是出于好奇。

$source = 'youtube.xml';

// load as file
$youtube = new SimpleXMLElement($source, null, true);
$youtube->registerXPathNamespace('yt', 'http://gdata.youtube.com/schemas/2007');

$count = 0;
foreach($youtube->entry as $item){

    //title works
    echo $item->title;

    $attributes = $item->xpath('//yt:duration/@seconds');
    echo $attributes[$count]['seconds'];
    $count++;
}

So I found a way to do it using xpath, is this the best way or is there a way that's consistent with my code in the question? Just out of curiosity.

$source = 'youtube.xml';

// load as file
$youtube = new SimpleXMLElement($source, null, true);
$youtube->registerXPathNamespace('yt', 'http://gdata.youtube.com/schemas/2007');

$count = 0;
foreach($youtube->entry as $item){

    //title works
    echo $item->title;

    $attributes = $item->xpath('//yt:duration/@seconds');
    echo $attributes[$count]['seconds'];
    $count++;
}
君勿笑 2024-11-25 19:43:07

我也曾在这种情况下挣扎,然后我找到了解决方案。如何读取复杂的 XML 属性命名空间非常简单。

foreach($media->group->content as $content) {
    $attrs = $content->attributes();
    $ytformat = $content->attributes("yt","format");

    echo(" attr = " . $ytformat . "; ");

    if ($ytformat == 5) {
        $url = $attrs['url'];
        $type = $attrs['type'];

        echo ($url . " - " . $type);
    }
}

希望它有帮助...:)

I was struggling with this situation as well then I found the solution. It's so simple on how to read a complex XML attribute namespace.

foreach($media->group->content as $content) {
    $attrs = $content->attributes();
    $ytformat = $content->attributes("yt","format");

    echo(" attr = " . $ytformat . "; ");

    if ($ytformat == 5) {
        $url = $attrs['url'];
        $type = $attrs['type'];

        echo ($url . " - " . $type);
    }
}

Hope it helps...:)

若水微香 2024-11-25 19:43:07

以下是仅使用attributes()和children()的另一个解决方案,经过测试并且工作正常! :)

$data=<<<XML

<rss version="2.0" xmlns:media="http://search.yahoo.com/mrss/">
 <channel>
   <item>
    <title>Title: 0</title>
    <link test="test" test2="This is a test">Link:0</link>
    <media:thumbnail url="Thumbnail URL: 0"/>
    <media:content url="Content URL: 0" type="video/mp4" />
  </item>
    <item>
    <title>Title: 1</title>
    <link>Link:1</link>
    <media:thumbnail url="1"/>
    <media:content url="1" type="video/mp4" />
  </item>
 </channel>
</rss>

XML;



$xml=simplexml_load_string($data);

//reading simple node
echo $xml->channel[0]->item[0]->title;

echo "<br>----------------------------------<br>";

//reading/updating simple node's attribute
echo $xml->channel[0]->item[0]->link->attributes()->test2="This is a NEW test!.";

echo "<br>----------------------------------<br>";

//reading/updating namespaced node's attribute
echo $xml->channel[0]->item[0]->children('media',TRUE)->content->attributes()->type="VIDEO/MP6";

//saving...
$xml->asXml('updated.xml');

The following is another solution using attributes() and children() only, tested and working OK! :)

$data=<<<XML

<rss version="2.0" xmlns:media="http://search.yahoo.com/mrss/">
 <channel>
   <item>
    <title>Title: 0</title>
    <link test="test" test2="This is a test">Link:0</link>
    <media:thumbnail url="Thumbnail URL: 0"/>
    <media:content url="Content URL: 0" type="video/mp4" />
  </item>
    <item>
    <title>Title: 1</title>
    <link>Link:1</link>
    <media:thumbnail url="1"/>
    <media:content url="1" type="video/mp4" />
  </item>
 </channel>
</rss>

XML;



$xml=simplexml_load_string($data);

//reading simple node
echo $xml->channel[0]->item[0]->title;

echo "<br>----------------------------------<br>";

//reading/updating simple node's attribute
echo $xml->channel[0]->item[0]->link->attributes()->test2="This is a NEW test!.";

echo "<br>----------------------------------<br>";

//reading/updating namespaced node's attribute
echo $xml->channel[0]->item[0]->children('media',TRUE)->content->attributes()->type="VIDEO/MP6";

//saving...
$xml->asXml('updated.xml');
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文