Reputation: 95
I have a xml file structured like
<?xml version="1.0"?> <library> <book id="1003"> <title>Jquery MVC</title> <author>Me</author> <price>500</price> </book> <book id="1001"> <title>Php</title> <author>Me</author> <price>600</price> </book> <book id="1002"> <title>Where to use IFrame</title> <author>Me</author> <price>300</price> </book> </library>
In order to sort this xml according to the book id,
after reviewing this method from stackoverflow
i coded like this
$dom = new DOMDocument();
$dom->load('DOM.xml');
$library = $dom->documentElement;
$xpath = new DOMXPath($dom);
$result = $xpath->query('/library/book');
function sort_trees($t1,$t2){
return strcmp($t1['id'], $t2['id']);
}
usort($result, 'sort_trees');
print_r($result);*/
But it gives me an error
Warning: usort() expects parameter 1 to be array, object given in /var/www/html/testphp/phpxml/readxml.php on line 24
Upvotes: 5
Views: 8617
Reputation: 1035
(copied over from your duplicate question) This works
$dom = new DOMDocument();
$dom->load('dom.xml');
$xp = new DOMXPath($dom);
$booklist = $xp->query('/library/book');
$books = iterator_to_array($booklist);
function sort_by_numeric_id_attr($a, $b)
{
return (int) $a->getAttribute('id') - (int) $b->getAttribute('id');
}
usort($books, 'sort_by_numeric_id_attr');
$newdom = new DOMDocument("1.0");
$newdom->formatOutput = true;
$root = $newdom->createElement("library");
$newdom->appendChild($root);
foreach ($books as $b) {
$node = $newdom->importNode($b,true);
$root->appendChild($newdom->importNode($b,true));
}
$newdom->save('DOM2.xml');
As you can see, you need to create a new DOMDocument, and add the sorted children to it (via importNode to copy the DOMNodes from one DOMDocument to another).
Upvotes: 0
Reputation: 31621
The answer you cite is for SimpleXML, but you are using DOMDocument.
If you want to continue to use DOMDocument you need to keep its API in mind.
$dom = new DOMDocument();
$dom->load('DOM.xml');
$xp = new DOMXPath($dom);
$booklist = $xp->query('/library/book');
// Books is a DOMNodeList, not an array.
// This is the reason for your usort() warning.
// Copies DOMNode elements in the DOMNodeList to an array.
$books = iterator_to_array($booklist);
// Second, your sorting function is using the wrong API
// $node['id'] is SimpleXML syntax for attribute access.
// DOMElement uses $node->getAttribute('id');
function sort_by_numeric_id_attr($a, $b)
{
return (int) $a->getAttribute('id') - (int) $b->getAttribute('id');
}
// Now usort()
usort($books, 'sort_by_numeric_id_attr');
// verify:
foreach ($books as $book) {
echo $book->C14N(), "\n";
}
If you need to create a new output document with the nodes sorted, create a new document, import the root element, then import the book nodes in sorted order and add to the document.
$newdoc = new DOMDocument('1.0', 'UTF-8');
$libraries = $newdoc->appendChild($newdoc->importNode($dom->documentElement));
foreach ($books as $book) {
$libraries->appendChild($newdoc->importNode($book, true));
}
echo $newdoc->saveXML();
However, a much better approach is to use XSLT:
<?xml version="1.0" encoding="UTF-8" ?>
<!-- file "sort_by_numeric_id.xsl" -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output encoding="UTF-8" method="xml" />
<xsl:template match="node()|@*">
<xsl:copy><xsl:apply-templates select="node()|@*"/></xsl:copy>
</xsl:template>
<xsl:template match="/*">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="*">
<xsl:sort select="@id" data-type="number"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Then use XSLTProcessor (or xsltproc
from the command line):
$xsltdoc = new DOMDocument();
$xsltdoc->load('sort_by_numeric_id.xsl');
$xslt = new XSLTProcessor();
$xslt->importStyleSheet($xsltdoc);
// You can now use $xslt->transformTo*() methods over and over on whatever documents you want
$libraryfiles = array('library1.xml', 'library2.xml');
foreach ($libraryfiles as $lf) {
$doc = new DOMDocument();
$doc->load($lf);
// write the new document
$xslt->transformToUri($doc, 'file://'.preg_replace('/(\.[^.]+)?$/', '-sorted$0', $lf, 1);
unset($doc); // just to save memory
}
Upvotes: 10