【问题标题】:How to get attribute of node with namespace using SimpleXML? [closed]如何使用 SimpleXML 获取具有命名空间的节点的属性? [关闭]
【发布时间】:2011-09-28 10:32:30
【问题描述】:

youtube.xml

<feed xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:gd="http://schemas.google.com/g/2005" xmlns:yt="http://gdata.youtube.com/schemas/2007">  

    <entry>
        ...
        <yt:duration seconds="1870"/>
        ...
    </entry>

</feed>

update_videos.php

$source = 'youtube.xml';

// load as file
$youtube = new SimpleXMLElement($source, null, true);

foreach($youtube->entry as $item){
    //title works
    echo $item->title;

    //now how to get seconds? My attempt...
    $namespaces = $item->getNameSpaces(true);
    $yt = $item->children($namespaces['yt']);
    $seconds = $yt->duration->attributes();
    echo $seconds['seconds'];
    //but doesn't work :(
}   

【问题讨论】:

  • @hakre,不确定它是否重复。我看不到提问者在哪里询问如何获取具有命名空间的节点的attribute
  • 只能复制。我认为您的问题是有效的,我想知道为什么很难找到这些信息。 stackoverflow.com/questions/3438900/… 并检查:blog.sherifmansour.com/?p=302 - 只是在谷歌上搜索 simplexml 和命名空间
  • 问题中的代码现在似乎可以按预期工作,至少在 PHP 5.2 和this testbed 中是这样。问题可能是seconds 属性不被认为在yt 命名空间中,即使duration 元素是as discussed elsewhere。这需要您选择 NULL 命名空间来获取属性,这可能在某些旧版本的 PHP 中不起作用?
  • @IMSoP:I also can confirm your findings。我的结论如下: OP 没有提供任何体面的错误描述,所以很难说到底是什么问题。只能假设,所以我建议在提供更多信息之前搁置这个问题。如果可能的话,那么长时间之后就好了。如果不是,这个问题需要降级,因为它没有具体说明它的要求,并且阻碍了它所涉及的常见问题。

标签: php xml namespaces simplexml


【解决方案1】:

所以我找到了一种使用 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++;
}

【讨论】:

    【解决方案2】:

    我也在与这种情况作斗争,然后我找到了解决方案。如何读取复杂的 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);
        }
    }
    

    希望对您有所帮助...:)

    【讨论】:

    • 您对attributes() 的调用只是偶然发生的——第二个参数是布尔值$is_prefix,而字符串'format' 被解释为true。我想你追求的是$content-&gt;attributes("yt", true)-&gt;format
    【解决方案3】:

    以下是仅使用 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');
    

    【讨论】:

      【解决方案4】:

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

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

      由于这与您在问题中所做的基本相同,因此可以说您已经回答了自己的问题。与扩展的Online Demo #2 比较。


      长答案:您在问题中得到的代码确实有效。您可以在此处的在线交互式示例中找到您的示例 XML 和代码:Online Demo #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

      【讨论】:

        猜你喜欢
        • 2012-07-05
        • 2012-11-10
        • 2016-11-09
        • 2020-04-19
        • 2023-03-09
        • 2014-06-15
        • 2012-01-22
        • 1970-01-01
        • 2020-10-03
        相关资源
        最近更新 更多