24
Sep/09
0

XML selectNodes() ordered

Here is a helper function to select nodes from an XML document order by certain child node value of these nodes.
If selectNodes() is a pendant of MySQL SELECT command, this helper function would be a pendant of SELECT… ORDER BY…
As far I know there is no standart XML or XPath function to perform it.
Written in PHP for DOM Document model.
By default, the function sorts descending. To sort ascending, remove the comment on the end of function body.
In this example, nodes will be sorted by node value of the field range:

$str='<root>
<sub><snode><p><range>0</range><text>node5</text></p></snode></sub>
<sub><snode><p><range>2</range><text>node1</text></p></snode></sub>
<sub><snode><p><range>1</range><text>node2</text></p></snode></sub>
<sub><snode><p><range>5</range><text>node3</text></p></snode></sub>
<sub><snode><p><range>4</range><text>node4</text></p></snode></sub>
<sub><snode><p><range>38</range><text>this</text></p></snode></sub>
</root>';
$dom=new DomDocument();
$dom->loadXML($str);
$ordered_array=getSortedNodes($dom->documentElement,'snode','range'); 

foreach($ordered_array as $n) {
 echo $n->nodeName.' '.$n->getElementsByTagName('range')->item(0)->nodeValue.'<br>';
}
 /**
* @returns array
*/
function getSortedNodes($parentNode,$sortedNodeName,
                                           $rangeNodeName='range') {
	$snodes=$parentNode->getElementsByTagName($sortedNodeName);
	$snodes_array=array();
	foreach($snodes as $snode)
		$snodes_array[]=$snode;
	$new=array();
	$max=0;
	$i=0;
	$rangeNodes=$parentNode->getElementsByTagName($rangeNodeName);
	$rangeNodesLength=$rangeNodes->length;
	//exclude elements with range value=0 because of unknown error
	foreach($rangeNodes as $rN) {
		if((float)$rN->nodeValue==0)
			$rangeNodesLength--;
	}
	while($i<$rangeNodesLength) {
		foreach($snodes_array as $key=>$snode) {
			$range=$snode->getElementsByTagName($rangeNodeName)->item(0);
			if($range) {
				if((float)$range->nodeValue > $max) {
					$max=$range->nodeValue;
					$tmp=$range->parentNode;
					//if the range node is not directly in $parentNode
					while($tmp->nodeName!=$sortedNodeName)
						$tmp=$tmp->parentNode;
					$max_snode=$tmp;
					$max_key=$key;
				}
			}
		}
		$new[]=$max_snode;
		$max=0;
		unset($snodes_array[$max_key]);
		$i++;
	}
      //$new=array_reverse($new,true); - to sort ascending
	return $new;
}
Tagged as: ,
Comments (0) Trackbacks (0)

No comments yet.

Leave a comment

No trackbacks yet.