【问题标题】:How to sort a xml file using DOM如何使用 DOM 对 xml 文件进行排序
【发布时间】:2012-05-10 05:59:02
【问题描述】:

我有一个结构类似的 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>

为了根据书的id对这个xml进行排序,

查看this method from 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 行给出

【问题讨论】:

    标签: php xml sorting


    【解决方案1】:

    您引用的答案是 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
    }
    

    【讨论】:

    • loadXML 给出了一个错误,所以我改为加载。但结果没有排序
    • 你的输出是什么?我测试了这个用 xml 字符串替换 $x 并得到了排序结果。
    • 警告:DOMDocument::loadXML(): 需要开始标签,在实体中找不到'
    • 您在加载 XML 时犯了一些非常基本的错误。您的 XML 可能不是字符串,或者该字符串可能无效。 -&gt;load('filename.xml') 加载文件,-&gt;loadXML('&lt;root/&gt;') 加载字符串。
    • ZVON 有很多资源。从the XSLT tutorial 开始。忽略 XSLT 2,因为 PHP 和大多数开源软件都不支持它。
    【解决方案2】:

    (从您的重复问题中复制)这行得通

    $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 复制到另一个)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多