Как отсортировать XML-файл с помощью DOM

У меня есть XML-файл, структурированный как

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

Чтобы отсортировать этот xml в соответствии с идентификатором книги,

после просмотра этого метода из stackoverflow

я закодирован таким образом

 $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);*/ 

Но это дает мне ошибку

Предупреждение: usort () ожидает, что параметр 1 будет массивом, объект указан в /var/www/html/testphp/phpxml/readxml.php в строке 24

Solutions Collecting From Web of "Как отсортировать XML-файл с помощью DOM"

Ответ, который вы цитируете для SimpleXML, но вы используете DOMDocument.

Если вы хотите продолжать использовать DOMDocument, вам нужно учесть его API.

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

Если вам нужно создать новый выходной документ с отсортированными узлами, создать новый документ, импортировать корневой элемент, затем импортировать узлы книги в отсортированном порядке и добавить в документ.

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

Однако гораздо лучше использовать 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> 

Затем используйте XSLTProcessor (или xsltproc из командной строки):

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

(скопировано из вашего дублированного вопроса) Это работает

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

Как вы можете видеть, вам нужно создать новый DOMDocument и добавить к нему отсортированные дочерние элементы (через importNode для копирования DOMNodes из одного DOMDocument в другой).