使用PHP按属性值对XML进行排序

7

我有一个XML文件,想按照“order”属性顺序依次循环。

以下是示例:

<page>
<talentTrees>
<tree name="Football" order="2">
<tree name="Baseball" order="0">
<tree name="Frisbee" order="1">
</talentTrees>
</page>

我的目标是使用 foreach 循环遍历每个“tree”,但我想按照 order 属性的顺序读取它们:棒球,飞盘,足球(0,1,2)。

抱歉我的英语不太好,毕竟不是我的母语。

6个回答

17

供以后参考,这里有一种可以使用XPath查询节点并通过XPath对结果进行排序的方法:SimpleDOM。在此示例中,我按order属性的值对所有<tree/>节点进行排序:

include 'SimpleDOM.php';

$page = simpledom_load_string('<page>
    <talentTrees>
        <tree name="Football" order="2"/>
        <tree name="Baseball" order="0"/>
        <tree name="Frisbee" order="1"/>
    </talentTrees>
</page>');

$nodes = $page->sortedXPath('//tree', '@order');

foreach ($nodes as $node)
{
    echo $node->asXML(), "\n";
}

这很好用。我不得不看了一会儿才意识到SimpleDOM需要作为一个包含文件下载。 - Aaron
我已经包含了SimpleDom.php文件,但系统仍然无法识别sortedXPath方法,为什么? - budamivardi
1
@budamivardi,你应该使用simplexml_load_string而不是simpledom_load_string,或者使用simplexml_load_file而不是simpledom_load_file。 - Andrew Liu

9
这应该能给您想要的东西:
$string = <<<EOS
<page>
<talentTrees>
<tree name="Football" order="2" />
<tree name="Baseball" order="0" />
<tree name="Frisbee" order="1" />
</talentTrees>
</page>
EOS;

$xml = simplexml_load_string($string);

$trees = $xml->xpath('/page/talentTrees/tree');
function sort_trees($t1, $t2) {
    return strcmp($t1['order'], $t2['order']);
}

usort($trees, 'sort_trees');
var_dump($trees);

$trees 现在按照 order 属性进行排序。


1
当数字大于9时,此方法会失败。它将按以下方式排序:1、100、2、245、300、4。而不是1、2、4、100、245、300。请使用Josh Davis的建议,它可以很好地解决这个问题。 - matthoiland

1
如果你有很多像这样的元素。
$string = <<<EOS
<page>
<talentTrees>
<tree name="Football" order="2" />
<tree name="Baseball" order="0" />
<tree name="Frisbee" order="1" />
</talentTrees>
<talentTrees>
<tree name="Football2" order="1" />
<tree name="Baseball2" order="2" />
<tree name="Frisbee2" order="0" />
</talentTrees>
</page>
EOS;

你可以使用foreach
$xml = simplexml_load_string($string);

function sort_trees($t1, $t2) {
    return $t1['order'] - $t2['order'];
}

foreach($xml->talentTrees as $talentTrees){
    foreach($talentTrees->tree as $tree){
    $trees[]= $tree;
    }
    usort($trees, 'sort_trees');
    print_r($trees);
    unset($trees);
}

输出:

Array
(
    [0] => Array
        (
            [0] => SimpleXMLElement Object
                (
                    [@attributes] => Array
                        (
                            [name] => Baseball
                            [order] => 0
                        )

                )

            [1] => SimpleXMLElement Object
                (
                    [@attributes] => Array
                        (
                            [name] => Frisbee
                            [order] => 1
                        )

                )

            [2] => SimpleXMLElement Object
                (
                    [@attributes] => Array
                        (
                            [name] => Football
                            [order] => 2
                        )

                )

        )

    [1] => Array
        (
            [0] => SimpleXMLElement Object
                (
                    [@attributes] => Array
                        (
                            [name] => Frisbee2
                            [order] => 0
                        )

                )

            [1] => SimpleXMLElement Object
                (
                    [@attributes] => Array
                        (
                            [name] => Football2
                            [order] => 1
                        )

                )

            [2] => SimpleXMLElement Object
                (
                    [@attributes] => Array
                        (
                            [name] => Baseball2
                            [order] => 2
                        )

                )

        )

)

举个例子:https://stackoverflow.com/a/44379495/3506219


1

我编写了一个递归的扩展版本,可以按任意数量的属性进行排序:

//sort_xml_by_attr($simplexmlobject,array('attr_one','attr_two','attr_three'))

  class SortXML {
    public $xml;
    var $attr;
    function SortXML($xml,$attr) {
      $this->xml = $xml;
      $this->attr = $attr;
    }
    function cmp_attr($a,$b) {
      $a1 = (string)$a->xml[(string)$a->attr];
      $b1 = (string)$b->xml[(string)$b->attr];
      if (is_numeric($a1) && is_numeric($b1)) {
        if (is_float($a1) && is_float($b1)) {
          $a1 = (float)$a1;
          $b1 = (float)$b1;
        } else {
          $a1 = (int)$a1;
          $b1 = (int)$b1;
        }
      }
      if ($a1 == $b1) return 0;
      return ($a1 > $b1) ? +1 : -1;
    }
  }

  function sort_xml_by_attr($xml_obj,$attr) {
    if (count($attr)>1) {
      // break up array by unique values of the first attribute in the list
      $unique_attrs = array();
      foreach ($xml_obj as $i) $unique_attrs[] = (string)$i[$attr[0]];
      $unique_attrs = array_unique($unique_attrs);
      sort($unique_attrs);
      // create an array of arrays who share a unique attribute value
      foreach ($unique_attrs as $i) {
        foreach ($xml_obj as $p) {
          if ($p[$attr[0]] == $i) $xml_arrays[$i][] = $p;
        }
      }
      // remove first element to progress the recursion to the next attribute
      array_shift($attr); 
      $new_array = array();
      // concatenate sorted arrays
      foreach ($xml_arrays as $i) {
        $new_array = array_merge($new_array,sort_xml_by_attr($i,$attr));
      }
      return $new_array;
    } else {
      // create wrapper objects with new comparison function 
      foreach ($xml_obj as $i) $new_obj[] = new SortXML($i,$attr[0]);
      usort($new_obj,array('SortXML','cmp_attr'));
      foreach ($new_obj as $i) $sorted_obj[] = $i->xml;
      return $sorted_obj;
    }
  }

-2

-2

这个页面提供了一些很好的例子,我认为你可以使用


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接