Вопрос по sorting, php, xml – Как отсортировать XML-файл с помощью DOM

3

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

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

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

после рассмотренияthis method from stackoverflow

я так закодировал

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

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

Warning: usort() expects parameter 1 to be array, object given in /var/www/html/testphp/phpxml/readxml.php on line 24

Ваш Ответ

2   ответа
0

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

$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, чтобы скопировать DOMNode из одного DOMDocument в другой).

10

Вы цитируете ответ для 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
}
ZVONError: User Rate Limit Exceededthe XSLT tutorialError: User Rate Limit Exceeded
Error: User Rate Limit Exceeded user1066679
Error: User Rate Limit Exceeded->load('filename.xml')Error: User Rate Limit Exceeded->loadXML('<root/>')Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded$xError: User Rate Limit Exceeded
Error: User Rate Limit Exceeded user1066679

Похожие вопросы