Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
252 views
in Technique[技术] by (71.8m points)

php - How to sort a xml file using DOM

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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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(), "
";
}

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
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...