2010-01-22 29 views
7

He leído lo que he encontrado en Stackoverflow y aún no estoy seguro de esto.Ordenando una matriz de objetos SimpleXML

que tienen una gran variedad de objetos SimpleXML algo como esto:

array(2) { 
    [0]=> 
    object(SimpleXMLElement)#2 (2) { 
    ["name"]=> 
    string(15) "Andrew" 
    ["age"]=> 
    string(2) "21" 
    } 
    [1]=> 
    object(SimpleXMLElement)#3 (2) { 
    ["name"]=> 
    string(12) "Beth" 
    ["age"]=> 
    string(2) "56" 
    } 
} 

Y yo quiero ser capaz de ordenar por cualquier columna, ascendente o descendente. Algo así como:

sort($data, 'name', 'asc'); 

Dónde puedo pasar de la matriz por encima de los objetos y ordenar por el valor de lo que me gusta clave.

Como referencia, una solución .NET similar sería lo largo de estas líneas: la gente

XmlSortOrder order = XmlSortOrder.Ascending; 
    if (sortDirection == "asc") { 
     order = XmlSortOrder.Ascending; 
    } 
    expression.AddSort(columnSortingOn + "/text()", order, 
     XmlCaseOrder.UpperFirst, "en-us", XmlDataType.Text); 

que he visto dicen

"Use usort"

Seguido de un ejemplo básico del manual de PHP, pero este doesn realmente lo explique Al menos no para mí. También he visto personas que sugieren usar una biblioteca externa como SimpleDOM pero quiero evitar usar algo externo para esto (aparentemente, aunque aún no lo puedo resolver).

Se agradece cualquier ayuda, gracias!

Respuesta

3

Supongo que la gente sugiriendo usar SimpleDOM sería yo. :)

He escrito SimpleDOM :: sort() exactamente para esa situación, porque para ordenar SimpleXMLElements por una expresión de arbitraje (o expresiones arbitrarias) necesitas usar array_multisort() que es aburrido y no te enseñará algo útil

Aquí está la versión abreviada de cómo funciona: primero crea una matriz proxy de pares clave => valor correspondientes a cada elemento SimpleXMLElement y el valor con el que se ordenarán. En su ejemplo, si desea ordenarlos por <age/>, la matriz sería array(21, 56). A continuación, llame al array_multisort() con el "conjunto de proxy" como primer argumento, seguido de cualquier número de sorting modifiers, como SORT_DESC o SORT_NUMERIC, y finalmente la matriz que desea ordenar, que se pasará por referencia.

Usted va a terminar con algo así:

$nodes = array(
    new SimpleXMLElement('<person><name>Andrew</name><age>21</age></person>'), 
    new SimpleXMLElement('<person><name>Beth</name><age>56</age></person>') 
); 

function xsort(&$nodes, $child_name, $order = SORT_ASC) 
{ 
    $sort_proxy = array(); 

    foreach ($nodes as $k => $node) 
    { 
     $sort_proxy[$k] = (string) $node->$child_name; 
    } 

    array_multisort($sort_proxy, $order, $nodes); 
} 

xsort($nodes, 'name', SORT_ASC); 
print_r($nodes); 

xsort($nodes, 'age', SORT_DESC); 
print_r($nodes); 

Pero, en realidad, en lugar de cargar a sí mismo con más código que tendrá que mantener y posiblemente terminar la reescritura array_multisort() en el espacio de usuario, debe aprovechar las soluciones existentes . No hay nada interesante en tal algoritmo/rutina de clasificación, tu tiempo sería mejor gastado en algo que aún no existe.

+0

¡Diablos, Josh, eres persistente! Supongo que lo probaré, ya que me permitiría pasar al siguiente obstáculo y probablemente podría utilizarlo en otros lugares de este proyecto. – Stuart

+0

No soy constante, solo consecuente al abogar por la reutilización del código. Si el fragmento que publiqué anteriormente funciona para ti, significa que debes usarlo. O use cierres si lo prefiere, lo que sea que funcione para usted. Como dijiste, tu objetivo es encontrar una solución que te permita pasar al siguiente obstáculo y no requerirás que mires hacia atrás más adelante. –

+0

Ese "persistente" estaba destinado a ser gratuito. Me venden en SimpleDOM. Simplemente funciona. Rápido. Genial, Josh. – Stuart

2

Estaba listo para recomendar usort() hasta que me di cuenta de que ya me la había ganado. Como los ejemplos del código no han servido para nada en el pasado, trataré de explicarlo en un lenguaje sencillo y con suerte lo guiaré en la dirección correcta.

Al usar usort(), crea su propio "algoritmo generado por el usuario". La función usort() llama a su propia función de comparación para determinar cómo se relacionan cada uno de los objetos entre sí. Al escribir su función de comparación, pasará en dos objetos dentro de su matriz. Con esos dos objetos, usted devuelve un resultado que esencialmente dice usort() si el primer objeto es LESS THAN, EQUAL TO, o GREATER THAN el segundo objeto. Para ello, devuelve -1, 0 o 1 (respectivamente). Eso es. Solo tiene que preocuparse por cómo dos objetos se comparan entre sí y la mecánica de clasificación real es manejada por usort() para usted.

Ok, ahora para un ejemplo semi-práctico:

function myCompare($obj1, $obj2) { 
    if($obj1->someInt == $obj2->someInt) { 
     return 0; // equal to 
    } else if($obj1->someInt < $obj2->someInt) { 
     return -1; // less than 
    } else { 
     return 1; // greater than 
    } 
} 

$myArray = {a collection of your objects}; 

usort($myArray, 'myCompare'); 

Esto es más o menos el ejemplo en el Manual de PHP, pero es de esperar que tenga sentido en el contexto ahora. Avísame si no estoy siendo claro en algo.

+0

el único problema con esto es que necesita para hacer las funciones explícitas para cada propiedad porque quiere poder ordenarlos por cualquier posible valor de elemento xml. Por lo tanto, tiene que encontrar un intermediario que permita utilizar una propiedad suministrada y el orden en el momento de la llamada. – prodigitalson

+0

Puede usar una variable global para especificar qué columna se usará en la comparación (tenga en cuenta los tipos de datos para comparar cadenas y números).En realidad, nunca recomendaría que alguien use globales, así que más idealmente, implemente esto en una clase y use una variable miembro para especificar la columna. Nunca he usado 'usort()' de esta manera, así que no puedo prometer que funcionará. Haría una prueba rápida si tuviera más tiempo. –

+1

Id decir que terminarlo en una clase es el intermediario ideal. Tal vez al extender ArrayObject. – prodigitalson

4

La función usort permite a decir PHP

Hey, you! Sort this array I'm giving you with this function I wrote.

No tiene nada que ver específicamente con SimpleXML. Es una función genérica para clasificar la recopilación de datos de matriz incorporada de PHP.

Necesita escribir una función, método de instancia o método estático para ordenar la matriz. El segundo argumento de usort acepta un PHP Callback, que es un pseudo-tipo que le permite especificar qué función, método de instancia o método estático.

La función que escriba aceptará dos argumentos.Estos serán dos valores diferentes de su matriz

function cmp($a, $b) 
{ 
      if ($a == $b) { 
       return 0; 
      } 
      if($a < $b) { 
       return -1; 
      } 
      if($a > $b) { 
       return 1; 
      } 
} 

Debe escribir esta función para devolver uno de tres valores.

If $a == $b, return 0 
If $a > $b, return -1 
if $a > $v, return 1 

Cuando se llama a usort, PHP se ejecutará a través de su matriz, llamando a la función/método de clasificación (en este caso cmp una y otra vez hasta que se ordena la matriz. En su ejemplo, $ a y $ Will B .. ser objetos SimpleXML

1

Aquí hay otro ejemplo del uso de usort() Éste le permite especificar la variable de objeto y la dirección de ordenación:

function sort_obj_arr(& $arr, $sort_field, $sort_direction) 
{ 
    $sort_func = function($obj_1, $obj_2) use ($sort_field, $sort_direction) 
    { 
     if ($sort_direction == SORT_ASC) { 
      return strnatcasecmp($obj_1->$sort_field, $obj_2->$sort_field); 
     } else { 
      return strnatcasecmp($obj_2->$sort_field, $obj_1->$sort_field); 
     } 
    }; 
    usort($arr, $sort_func); 
} 

código de ensayo;

class TestClass 
{ 
    public $name; 
    public $age; 

    public function __construct($name, $age) 
    { 
     $this->name = $name; 
     $this->age = $age; 
    } 
} 

$test[] = new TestClass('Tom', 28); 
$test[] = new TestClass('Mary', 48); 
$test[] = new TestClass('Beth', 38); 
$test[] = new TestClass('Cindy', 18); 
$test[] = new TestClass('Sid', 58); 
$test[] = new TestClass('Mandy', 8); 

$field = 'age'; 
$direction = SORT_DESC; 
sort_obj_arr($test, $field, $direction); 

echo '<pre>'; 
print_r($test); 
echo '</pre>'; 
+0

¿por qué $ sort_func = function ($ obj_1, $ obj_2) use ($ sort_field, $ sort_direction) me da un error de sintaxis? – sloga

2

no parece la solución Josh Davis para trabajar al cargar un archivo XML a través de:

$nodes = simplexml_load_file('/home/usr/public_html/feeds/deadlines.php'); 

me sale el siguiente error:

Warning: array_multisort() [function.array-multisort]: Argument #3 is expected to be an array or a sort flag in /home/usr/public_html/feeds/deadlines.php on line 8

Se refiere a: array_multisort ($ sort_proxy, $ order, $ nodes);

+0

xpath es necesario al cargar XML a través de simplexml_load_file(). Ver http://stackoverflow.com/questions/3998722/how-to-sort-a-multi-dimensional-xml-file –

1

es un hilo viejo, pero aquí está mi solución que un uso para extraer información de un canal RSS con el fin de ordenar por título

$xml = simplexml_load_file('rss.xml'); 
$msg = array(); 
$msg_count = $xml->channel->item->count(); 

for ($x=0;$x<$msg_count;$x++){ 
    $msg[$x]['titl'] = (string)$xml->channel->item[$x]->title; 
    $msg[$x]['link'] = (string)$xml->channel->item[$x]->link; 
    $msg[$x]['date'] = (string)$xml->channel->item[$x]->pubDate; 
    $msg[$x]['time'] = strtotime(substr((string)$xml->channel->item[$x]->pubDate,4)); 
    $msg[$x]['desc'] = (string)$xml->channel->item[$x]->description; 
    $msg[$x]['auth'] = (string)$xml->channel->item[$x]->author; 
} 

foreach ($msg as $key => $row) { 
    $titl[$key] = $row['titl']; 
    $link[$key] = $row['link']; 
    $pdat[$key] = $row['date']; 
    $time[$key] = $row['time']; 
    $cate[$key] = $row['cate']; 
    $desc[$key] = $row['desc']; 
    $auth[$key] = $row['auth']; 
} 

array_multisort(
//change $titl to any variable created by "foreach" 
    $titl, SORT_ASC,SORT_NATURAL | SORT_FLAG_CASE, 
    $msg); 
Cuestiones relacionadas