PHP: сортировка нодлистов XML по нескольким элементам

1

Начинающий программист.

Я нахожусь в php, работая с ноделистом dom dom, состоящим из выбранных узлов, полученных из запроса XPath в XML файле. Выдержка содержания нодлиста:

<properties>
    <property>
        <price>270</price>
        <address>3/2 Farran Street, Castlemaine, VIC, Australia</address>
        <infants>3</infants>
    </property>
    <property>
        <price>250</price>
        <address>2/37 William Street, Castlemaine, VIC, Australia</address>
        <infants>2</infants>
    </property>
    <property>
        <price>250</price>
        <address>2/37 William Street, Castlemaine, VIC, Australia</address>
        <infants>3</infants>
    </property>
    ...

Я хочу, чтобы отсортировать нодлист по price по возрастанию, а в случае одинаковых цен, ни в из infants нисходящих. В приведенном выше фрагменте, например, результатом будет:

<property>
    <price>250</price>
    <address>2/37 William Street, Castlemaine, VIC, Australia</address>
    <infants>3</infants>
</property>
<property>
    <price>250</price>
    <address>2/37 William Street, Castlemaine, VIC, Australia</address>
    <infants>2</infants>
</property>
<property>
    <price>270</price>
    <address>3/2 Farran Street, Castlemaine, VIC, Australia</address>
    <infants>3</infants>
</property>

Я видел некоторые вопросы по сортировке, связанные с многомерными массивами, но я не могу перевести их в нодлисты. Я могу сортировать по price ok (см. Ниже), но я не могу определить, как потом сортировать infants.

$properties = iterator_to_array($matches); // where matches = a return from an XPath query
usort($properties, 'sortByPrice');

function sortByPrice ($a, $b) {
    $aPrice = $a->getElementsByTagName("price");
    $aPrice = $aPrice->item(0)->nodeValue;
    $bPrice = $b->getElementsByTagName("price");
    $bPrice = $bPrice->item(0)->nodeValue;
    return (int) $aPrice - (int) $bPrice;
}
Теги:
xpath
sorting

3 ответа

0
Лучший ответ

если ваш код работает нормально по цене, почему бы просто не расширить его:

$properties = iterator_to_array($matches); // where matches = a return from an XPath query
usort($properties, 'sortByPrice');

function sortByPrice ($a, $b) {
    $aPrice = $a->getElementsByTagName("price");
    $aPrice = $aPrice->item(0)->nodeValue;
    $bPrice = $b->getElementsByTagName("price");
    $bPrice = $bPrice->item(0)->nodeValue;
    $r = (int) $aPrice - (int) $bPrice;
    if (!$r) {
       $ainfants = $a->getElementsByTagName("infants");
       $ainfants = $ainfants->item(0)->nodeValue;
       $binfants = $b->getElementsByTagName("infants");
       $binfants = $bPrice->item(0)->nodeValue;
       $r = (int) $ainfants - (int) $binfants;
    }
    return $r;
}
  • 0
    О, глупый я. Спасибо!
  • 0
    даже Гомер иногда кивает :)
0

Вы можете получать скалярные значения в зависимости от узла контекста с DOMXPath::evaluate(). number() будет переводить первый узел в результат пути местоположения в поплавок. Если ни один узел не был найден, результат равен нулю.

$dom = new DOMDocument();
$dom->loadXml($xml);
$xpath = new DOMXPath($dom);

$properties = iterator_to_array($xpath->evaluate('//properties/property'));
usort(
  $properties,
  function(DOMElement $a, DOMElement $b) use ($xpath) {
    $aPrice = (int)$xpath->evaluate('number(price)', $a);
    $bPrice = (int)$xpath->evaluate('number(price)', $b);
    if ($aPrice == $bPrice) {
      $aInfants = (int)$xpath->evaluate('number(infants)', $a);
      $bInfants = (int)$xpath->evaluate('number(infants)', $b);
      return $bInfants - $aInfants;
    }
    return $aPrice - $bPrice;
  }
);
0

Попробуйте эту функцию. Он действует как обобщение uasort PHP uasort:

function sortByKeyValue($the_array, $key)
{
   $cmp_val="((\$a['$key']>\$b['$key'])?1:
   ((\$a['$key']==\$b['$key'])?0:-1))";
   $cmp=create_function('$a, $b', "return $cmp_val;");
   uasort($the_array, $cmp);

   return $the_array;
}

В вашем случае вы можете использовать его таким образом:

$properties = iterator_to_array($matches);
sortByKeyValue($properties, 'price');
sortByKeyValue($properties, 'infants');

Я надеюсь, что это помогает.

  • 0
    Это скрытый eval() . Медленно и опасно.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню