Проблема с сортировкой PHP с помощью simpleXML

test.xml:

<?xml version="1.0"?> <props> <prop> <state statename="Mississippi"> <info> <code>a1</code> <location>Jackson</location> </info> <info> <code>d2</code> <location>Gulfport</location> </info> <info> <code>g6</code> <location>Hattiesburg</location> </info> </state> <state statename="Texas"> <info> <code>i9</code> <location>Dallas</location> </info> <info> <code>a7</code> <location>Austin</location> </info> </state> <state statename="Maryland"> <info> <code>s5</code> <location>Mount Laurel</location> </info> <info> <code>f0</code> <location>Baltimore</location> </info> <info> <code>h4</code> <location>Annapolis</location> </info> </state> </prop> </props> 

test.php

 // start the sortCities function sortCities($a, $b){ return strcmp($a->location, $b->location); } // start the sortStates function sortStates($t1, $t2) { return strcmp($t1['statename'], $t2['statename']); } $props = simplexml_load_file('test.xml'); foreach ($props->prop as $prop) { $sortedStates = array(); foreach($prop->state as $states) { $sortedStates[] = $states; } usort($sortedStates, "sortStates"); // finish the sortStates /* --- */ echo '<pre>'."\n"; print_r($sortedStates); echo '</pre>'."\n"; /* --- */ foreach ($prop->children() as $stateattr) { // this doesn't do it //foreach($sortedStates as $hotel => @attributes){ // blargh! if(isset($stateattr->info)) { $statearr = $stateattr->attributes(); echo '<optgroup label="'.$statearr['statename'].'">'."\n"; $options = array(); foreach($stateattr->info as $info) { $options[] = $info; } usort($options, "sortCities"); // finish the sortCities foreach($options as $stateattr => $info){ echo '<option value="'.$info->code.'">'.$info->location.'</option>'."\n"; } echo '</optgroup>'."\n"; } else { //empty nodes don't do squat } } } ?> 

Это массив, который:

 print_r($sortedStates); 

распечатывает:

 Array ( [0] => SimpleXMLElement Object ( [@attributes] => Array ( [statename] => Maryland ) [info] => Array ( [0] => SimpleXMLElement Object ( [code] => s5 [location] => Mount Laurel ) [1] => SimpleXMLElement Object ( [code] => f0 [location] => Baltimore ) [2] => SimpleXMLElement Object ( [code] => h4 [location] => Annapolis ) ) ) [1] => SimpleXMLElement Object ( [@attributes] => Array ( [statename] => Mississippi ) [info] => Array ( [0] => SimpleXMLElement Object ( [code] => a1 [location] => Jackson ) [1] => SimpleXMLElement Object ( [code] => d2 [location] => Gulfport ) [2] => SimpleXMLElement Object ( [code] => g6 [location] => Hattiesburg ) ) ) [2] => SimpleXMLElement Object ( [@attributes] => Array ( [statename] => Texas ) [info] => Array ( [0] => SimpleXMLElement Object ( [code] => i9 [location] => Dallas ) [1] => SimpleXMLElement Object ( [code] => a7 [location] => Austin ) ) ) ) 

это:

 // start the sortCities function sortCities($a, $b){ return strcmp($a->location, $b->location); } 

плюс эта часть кода:

  $options = array(); foreach($stateattr->info as $info) { $options[] = $info; } usort($options, "sortCities"); // finish the sortCities foreach($options as $stateattr => $info){ echo '<option value="'.$info->code.'">'.$info->location.'</option>'."\n"; } 

выполняет прекрасную работу по сортировке по узлу «location» внутри каждой optgroup.

Вы можете видеть, что в массиве я могу сортировать его по атрибуту «statename». У меня возникают проблемы с эхом и объединением двух функций, чтобы он автоматически сортировал как штаты, так и города внутри и формировал нужные группы optgroups.

Я попытался скопировать строки для городов и изменить имена, названные несколькими способами безрезультатно.

Поэтому, используя структуру XML выше, я пытаюсь заставить ее выглядеть так:

 <optgroup label="Maryland"> <option value="h4">Annapolis</option> <option value="f0">Baltimore</option> <option value="s5">Mount Laurel</option> </optgroup> <optgroup label="Mississippi"> <option value="d2">Gulfport</option> <option value="g6">Hattiesburg</option> <option value="a1">Jackson</option> </optgroup> <optgroup label="Texas"> <option value="a7">Austin</option> <option value="i9">Dallas</option> </optgroup> 

Таким образом, независимо от того, какой порядок упорядочивают состояния в XML и как бы упорядочиваются местоположения в узле внутри состояний, они всегда упорядочивают по алфавиту при создании optgroup.


Artefacto-

последние 2 блока кода показывают функцию для сортировки узлов по имени (узлы местоположения).

 // start the sortCities function sortCities($a, $b){ return strcmp($a->location, $b->location); } // start the sortStates function sortStates($t1, $t2) { return strcmp($t1['statename'], $t2['statename']); } 

вторая функция сортирует по атрибуту (statename) в массиве, но, расчесывая две функции или, скорее, вложенные в них, так что состояния и города сортируются в алфавитном порядке, меня озадачило.


@Artefacto,

Спасибо за ответ. Кажется, имеет смысл, как он вложен. Проблема заключается в том, что ни один из моих серверов не запускает PHP 5.3. Таким образом, общие функции бросают ошибки. Я должен был упомянуть об этом, но не думал об этом. Они работают 5.2. Я пытаюсь вернуть скрипт обратно и застрял в секции.

 <?php $doc = simplexml_load_file('test.xml'); $states = get_object_vars($doc->prop->children()); $states = $states["state"]; function sortStates($t1, $t2) { return strcmp($t1['statename'], $t2['statename']); }; usort($states, "sortStates"); /* this is just here for testing */ echo '<pre>'; print_r($states); echo '</pre>'; /* end testing */ /* array_walk($states, function (&$state) { $state = get_object_vars($state); array_walk($state["info"], function (&$el) { $el = get_object_vars($el); } ); usort($state["info"], function($a, $b) { return strcmp($a["location"], $b["location"]); } ); } ); */ ?> 

Заключенный раздел, начинающийся с array_walk. Я не могу понять, как переписать «функцию (& $ state)» со следующей смертью.

Solutions Collecting From Web of "Проблема с сортировкой PHP с помощью simpleXML"

Вы хотите отсортировать список SimpleXMLElement s на основе некоторого значения атрибута или элемента. Обычно вы делаете это, поворачивая список в массив, а затем применяете сортировку по этому массиву.

Функция, полезная для PHP, – iterator_to_array . Это делает задачу превратить что-то настолько волшебное в simplexml в более «фиксированный» массив.

Скажем, ваши элементы тура в $result->tour . По умолчанию simplexml возвращает здесь итератор , то, что вы не можете сортировать из коробки. Давайте преобразуем его в массив:

 $tours = iterator_to_array($result->tour, false); 

Теперь переменная $tours представляет собой массив, содержащий каждый элемент <tour> в качестве SimplXMLElement . Теперь вы можете отсортировать этот массив с помощью функции массива. Эти функции сортировки массива описаны в руководстве по PHP, и я обычно предлагаю, как я могу сортировать многомерный массив в php как хорошую отправную точку:

 $tourDates = array_map( function($tour) {return trim($tour->next_bookable_date); }, $tours ); // sort $tours array by dates, highest to lowest $success = array_multisort($tourDates, SORT_DESC, $tours); 

И это уже так. Весь код с первого взгляда:

 $tours = iterator_to_array($result->tour, false); $tourDates = array_map( function($tour) {return trim($tour->next_bookable_date); }, $tours ); // sort $tours array by dates, highest to lowest $success = array_multisort($tourDates, SORT_DESC, $tours); foreach ($tours as $tour) { ... } 

Мой подход состоял в том, чтобы преобразовать объекты SimpleXMLElement в массивы:

 $doc = new SimpleXMLElement($xml); $states = get_object_vars($doc->prop->children()); $states = $states["state"]; usort($states, function($t1, $t2) { return strcmp($t1['statename'], $t2['statename']); }); array_walk($states, function (&$state) { $state = get_object_vars($state); array_walk($state["info"], function (&$el) { $el = get_object_vars($el); } ); usort($state["info"], function($a, $b) { return strcmp($a["location"], $b["location"]); } ); } ); 

изменение этого

 foreach ($prop->children() as $stateattr) 

к этому

 foreach ($sortedStates as $stateattr) 

сделал это.

мог бы поклясться, что я уже это пробовал.