简单 XML 元素:抓取 <link rel="alternate"> 节点内的 href

Simple XML Element: Grab the href inside <link rel="alternate"> node

我正在尝试从 xml 文件中解析不同的 link。我阅读了文档和每一个 post 我发现的关于解析 xml 文件的信息,但我没有找到一种方法来访问我想要的节点。例如:

<link rel="self" type="text/html" title="title0" length="8359" href="http://example0.com"/>
<link rel="alternate" type="text/html" title="title1" length="8359" href="http://example3.com"/>
<link rel="related" type="text/html" title="title2" length="8359" href="http://example4.com"/>
<link rel="related" type="text/html" title="title3" length="8359" href="http://example4.com"/>
<link rel="related" type="text/html" title="title4" length="8359" href="http://example5.com"/>
<link rel="related" type="text/html" title="title5" length="8359" href="http://example5.com"/>

我如何访问:

  1. 具有 rel="self"(return 字符串)的 link 的 href。
  2. 具有 rel="alternate"(return 字符串)的 link 的 href。
  3. 具有 rel="related"(return 数组)的 link 的 hrefs。

使用 SimpleXML:

$xml=simplexml_load_file('url_to_xml') or die('Error: Cannot create object');

...

如果您正在处理大文件,将文件拆分成行然后使用 preg_match 处理每一行可能是个好主意。如果您的 XML 文件具有相似的结构,这显然效果最好。

嗯,你可以使用 if/switch 语句,例如。

foreach($xml->getElementsByTagName('link') as $tag) {
   switch($tag->getAttribute('rel')) {
      case 'self':
         $href_of_self = $tag->getAttribute('href');
         break;
      case 'related':
         ...
   }
}

通过标签获取元素和获取元素的属性可以通过以下方法完成: http://php.net/manual/en/domdocument.getelementsbytagname.php http://php.net/manual/en/domelement.getattribute.php

您通常希望使用 XPath 或类似的东西来解析 XML 之类的文档。 SimpleXML 支持。示例:

<?php
$string = <<<XML
<div>
  <link rel="self" type="text/html" title="title0" length="8359" href="http://example0.com"/>
  <link rel="alternate" type="text/html" title="title1" length="8359" href="http://example3.com"/>
  <link rel="related" type="text/html" title="title2" length="8359" href="http://example4.com"/>
  <link rel="related" type="text/html" title="title3" length="8359" href="http://example4.com"/>
  <link rel="related" type="text/html" title="title4" length="8359" href="http://example5.com"/>
  <link rel="related" type="text/html" title="title5" length="8359" href="http://example5.com"/>
</div>
XML;
$xml = new SimpleXMLElement($string);
foreach(['self', 'alternate', 'related', 'dne'] as $rel) {
  $val = @$xml->xpath("//link[@rel='$rel']/@href");
  $val = $val ? array_map(function($n) { return (string)$n; }, $val) : [];
  $val = count($val) == 1 ? $val[0] : $val;
  var_dump($val);
}

如果您不习惯使用 xpath,那么您可以像访问对象一样访问 link 元素:

    <?php
    $string = <<<XML
    <div>
      <link rel="self" type="text/html" title="title0" length="8359" href="http://example0.com"/>
      <link rel="alternate" type="text/html" title="title1" length="8359" href="http://example3.com"/>
      <link rel="related" type="text/html" title="title2" length="8359" href="http://example4.com"/>
      <link rel="related" type="text/html" title="title3" length="8359" href="http://example4.com"/>
      <link rel="related" type="text/html" title="title4" length="8359" href="http://example5.com"/>
      <link rel="related" type="text/html" title="title5" length="8359" href="http://example5.com"/>
    </div>
    XML;

    $xml = new SimpleXMLElement($string);

    $related = [];

    foreach($xml->link as $link) {

        switch($link['rel']){
            case 'self':
                $self = $link['href'];
                break;
            case 'alternate':
                $alternate = $link['href'];
                break;
            case 'related':
                array_push($related, $link['href']);
                break;
        }

    }

    print $self;
    // outputs : http://example0.com

    print $alternate;
    // outputs : http://example3.com

    print_r($related);
    /* outputs : Array
(
    [0] => SimpleXMLElement Object
        (
            [0] => http://example4.com
        )

    [1] => SimpleXMLElement Object
        (
            [0] => http://example4.com
        )

    [2] => SimpleXMLElement Object
        (
            [0] => http://example5.com
        )

    [3] => SimpleXMLElement Object
        (
            [0] => http://example5.com
        )

)
*/

如果您不喜欢 switch 语句,您可以使用 'if' 条件语句来代替:

foreach($xml->link as $link) {
    if($link['rel'] == 'self'){
       $self = $link['href'];
    }
    if($link['rel'] == 'alternate'){
       $alternate = $link['href'];
    }
    if($link['rel'] == 'related'){
        array_push($related, $link['href']);
    }
}

您可以使用http://sabre.io/xml as describes itself as "An XML library for PHP you may not hate". Pay attention at function parseCurrentElement() https://github.com/fruux/sabre-xml/blob/master/lib/Reader.php

您可以创建自定义 reader

class CustomXmlReader extends \Sabre\Xml\Reader {}
class CustomXmlService extends \Sabre\Xml\Service {}

问题可以笼统地表述为"how to access an XML element's attributes based on the value of one of its other attributes"。有两种基本方法:遍历所有候选元素,并检查属性值;或使用 XPath 搜索文档。

找到匹配元素后,您需要访问属性,这在 SimpleXML 中意味着了解两种语法:

  • $something['bar'] 从表示元素的对象(例如 <foo>)到表示其属性之一的对象(例如 bar="..."
  • (string)$something 将变量转换为字符串,对于 SimpleXML,它会为您提供元素或属性的完整字符串内容

在 SimpleXML 中使用迭代很简单,因为您只需以一种相当直观的方式使用 foreachif。假设 $xml 已经指向 <link> 元素的父元素:

foreach ( $xml->link as $link ) {
    if ( $link['rel'] == 'self' ) {
        // Found <link rel="self">
        // assign to variable, return from function, etc
        // To access the attribute, we use $link['href']
        // To get the text content of the selected node,
        //   we cast to string with (string)$link['href']
        $self_link = (string)$link['href'];
    }
}

使用 XPath 允许您使用紧凑的表达式在整个文档中搜索具有特定名称和属性值的元素:

  • //foo 搜索文档
  • 中任意位置名为 <foo> 的所有元素
  • [bar] 表示 "which has a child element named "bar
  • [@bar] 表示 "which has an attribute named "bar",这就是我们想要的
  • [@bar="baz"]表示"bar"属性的值必须是"baz"

所以在我们的例子中,//link[@rel="self"]

在 SimpleXML 中,您可以在任何节点上调用 ->xpath(),并获得 零个或多个对象的数组。然后你会想要遍历这些,提取适当的值:

$xpath_results = $xml->xpath('//link[@rel="self"]');
foreach ( $xpath_results as $node ) {
     // Again, we have a SimpleXMLElement object, and want 
     //    the string content of the 'href' attribute:
     $self_link = (string)$node['href'];
}