【问题标题】:simplexml and xpath, read siblingsimplexml 和 xpath,读取同级
【发布时间】:2015-03-05 03:31:03
【问题描述】:

我有以下 XML 文件:

<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
    <item>
        [...]
        <wp:postmeta>
            <wp:meta_key>_wp_old_slug</wp:meta_key>
            <wp:meta_value><![CDATA[item-1-slug]]></wp:meta_value>
        </wp:postmeta>
        <wp:postmeta>
            <wp:meta_key>_yoast_wpseo_title</wp:meta_key>
            <wp:meta_value><![CDATA[item-1-title]]></wp:meta_value>
        </wp:postmeta>
        [...]
    </item>
    <item>
        [...]
        <wp:postmeta>
            <wp:meta_key>_wp_old_slug</wp:meta_key>
            <wp:meta_value><![CDATA[item-2-slug]]></wp:meta_value>
        </wp:postmeta>
        <wp:postmeta>
            <wp:meta_key>_yoast_wpseo_title</wp:meta_key>
            <wp:meta_value><![CDATA[item-2-title]]></wp:meta_value>
        </wp:postmeta>
        [...]
    </item>
</channel>
</rss>

我正在使用

循环浏览我的项目
$xmlurl = file_get_contents($xmlFile);
$xml = simplexml_load_string($xmlurl, null, LIBXML_NOCDATA);
$items = $xml->channel->item;
foreach( $items as $item ) {

}

在这个循环中,我想读取&lt;wp:meta_key&gt;_yoast_wpseo_title&lt;/wp:meta_key&gt; 节点的兄弟节点的值。例如,对于第 1 项,我想获得“item-1-title”。 我可能必须使用 xpath,但我真的不知道如何进行。

我该怎么做?

【问题讨论】:

    标签: xml xpath simplexml siblings


    【解决方案1】:

    此解决方案包括对 Wordpress XML 命名空间的引用:

    $doc = new SimpleXmlElement($xml);
    $doc->registerXPathNamespace ('wp', 'http://wordpress.org/export/1.0/');
    
    $wp_meta_title = $doc->xpath("//wp:postmeta[wp:meta_key = '_yoast_wpseo_title']/wp:meta_value");
    
    foreach ($wp_meta_title as $title) {
        echo (string)$title . "\n";
    }
    

    结果:

    item-1-title
    item-2-title
    

    http://ideone.com/qjOfIW

    //wp:postmeta[wp:meta_key = '_yoast_wpseo_title']/wp:meta_value 的路径很简单,我认为不需要特别解释。

    【讨论】:

      【解决方案2】:
      $xpath = './/wp:meta_key[text()="_yoast_wpseo_title"]/following-sibling::wp:meta_value[1]/text()';
      $items = $xml->channel->item;
      foreach( $items as $item ) {
        $result = $item->xpath($xpath);
        print "$result[0]\n";
      }
      
      // => item-1-title
      // => item-2-title
      

      XPath 表达式解释:

      .                               - from the current node...
      //wp:meta_key                   - get all descendant wp:meta_key nodes
      [text()="_yoast_wpseo_title"]   - whose text content is _yoast_wpseo_title
      /following-sibling::            - then get the siblings that come after this
      wp:meta_value[1]                - with tag wp:meta_value; only take the first
      /text()                         - and read its text
      

      【讨论】:

      • @Tomalak:当然不是,也不应该。但是我看不到完整的 XML,所以我只是在根目录上扔了一个 (rss)。如果它不存在,则需要更改某些内容。 (我相信使用$item-&gt;registerXPathNamespace)。
      • 如果它不起作用,“当然”,那么我认为你不应该将它添加为解决方案。即使您在输入 XML 中的 rss 元素上“抛出”命名空间声明,它也不会起作用(除非 SimpleXML 不知道命名空间)。
      • @MathiasMüller:期望从不完整的问题中得到完整的解决方案是不合理的。如果 OP 仅具有无效的 XML(具有未声明的命名空间),或者碰巧将 WordPress 命名空间以外的其他内容分配给 wp 前缀,即使 Tomalak 的回答也可能是错误的。 (它也不会保留 OP 的循环,因此会失去项目和相应值之间的关联。)在我的测试中,我确实在 rss 元素上抛出了一个命名空间声明,它起作用了。为什么不呢?
      • 因为 SimpleXML 不应该允许您使用带有您事先未注册的前缀的路径表达式。 (所以,我说的是 PHP,而不是输入 XML)它应该返回一个错误,指出 wp: 与命名空间 URI 无关。我可能错了 - 如果是这样,请告诉我我错在哪里。
      • @MathiasMüller:如果在根元素上声明,它将被识别。
      猜你喜欢
      • 1970-01-01
      • 2013-11-11
      • 2012-01-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多