2009-08-31 32 views
5

Mam plik XML, który próbuję przeplecić w kolejności, zgodnie z atrybutem "order".Sortowanie XML za pomocą wartości atrybutu PHP

Oto przykład:

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

Moim celem jest pętlą przez każdy „drzewa” używając foreach, ale chcę, aby przeczytać je w kolejności atrybutu kolejności: baseball, Frisbee, Football. (0,1,2).

Przepraszamy za słaby angielski, nie mój pierwszy język.

Odpowiedz

6

To powinno dać ci co chcesz:

$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 są teraz posortowane według atrybutu zlecenia.

+1

to zawodzi, gdy liczba jest większa niż 9. To sortowanie w następujący sposób: 1, 100 2, 245, 300, 4. Zamiast 1, 2, 4, 100, 245, 300. Użyj sugestii Josha Davisa poniżej. To dobrze działa. – matthoiland

0

This page daje kilka świetnych przykładów które można wykorzystać cienki

1

pisałem rekurencyjną, rozszerzoną wersję, która będzie sortować według dowolnej liczby atrybutów, w kolejności:

//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; 
    } 
    } 
15

na przyszłość, tutaj jest coś, co można używać do kwerendy węzłów poprzez XPath i sortować wynik pośrednictwem XPath również: SimpleDOM. W tym przykładzie, rodzaj wszystkie <tree/> węzłów wartości atrybutu order:

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"; 
} 
+0

Działa to świetnie. Musiałem się nad tym zastanowić, aby zdać sobie sprawę, że SimpleDOM musi być pobrany jako dodatek. – Aaron

+0

Dołączam SimpleDom.php, ale system nadal nie realizuje metody sortedXPath, dlaczego? – budamivardi

+0

@budamivardi musisz używać simplexml_load_string zamiast simpledom_load_string lub simplexml_load_file zamiast pliku simpledom_load_file –

0

Jeśli masz wiele elementów, takich jak ten

$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; 

Można użyć 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); 
} 

wyjściowa:

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 
         ) 

       ) 

     ) 

) 

Inny przykład: https://stackoverflow.com/a/44379495/3506219

Powiązane problemy