PHP:按多个元素对XML节点列表进行排序

Beginner programmer here.

I am in php, working with a dom document nodelist comprising of selected nodes retrieved from an XPath query on an xml file. Excerpt of contents of nodelist:

<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>
    ...

I wish to sort the nodelist by price ascending, and in the case of matching prices, by no of infants descending. In the above snippet, for example, the result would be:

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

I have seen some sorting questions answered relating to multi-dimensional arrays but I can't seem to translate these to nodelists. I can sort by price ok (see below), but I can't determine how to then sort by 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;
}

if your code works ok for price, why not just extend it:

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

Try this function. It acts as a generalisation of the uasort PHP function:

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

In your case, you may use it thus:

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

I hope it helps.

You can fetch scalar values depending on a context node with DOMXPath::evaluate(). number() will cast the first node in the location path result into a float. If no node was found the result is zero.

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