【问题标题】:PHP's SimpleXML doesn't keep order between different element typesPHP 的 SimpleXML 不保持不同元素类型之间的顺序
【发布时间】:2014-06-21 02:43:34
【问题描述】:

据我所知,当您在 XML 文档树中的同一级别有多种类型的元素时,PHP 的 SimpleXML,包括 SimpleXMLElementSimpleXMLIterator 都不会保持元素的顺序因为它们彼此相关,仅在每个元素内。

例如,考虑以下结构:

<catalog>
    <book>
        <title>Harry Potter and the Chamber of Secrets</title>
        <author>J.K. Rowling</author>
    </book>
    <book>
        <title>Great Expectations</title>
        <author>Charles Dickens</author>
    </book>
</catalog>

如果我有这个结构并使用SimpleXMLIteratorSimpleXMLElement 来解析它,我最终会得到一个看起来像这样的数组:

Array (
    [book] => Array (
        [0] => Array (
            [title] => Array (
                [0] => Harry Potter and the Chamber of Secrets
            )
            [author] => Array (
                [0] => J.K. Rowling
            )
        )
        [1] => Array (
            [title] => Array (
                [0] => Great Expectations
            )
            [author] => Array (
                [0] => Charles Dickens
            )
        )
    )
)

这很好,因为我只有 book 元素,并且它在这些元素中保持正确的顺序。但是,假设我也添加了电影元素:

<catalog>
    <book>
        <title>Harry Potter and the Chamber of Secrets</title>
        <author>J.K. Rowling</author>
    </book>
    <movie>
        <title>The Dark Knight</title>
        <director>Christopher Nolan</director>
    </movie>
    <book>
        <title>Great Expectations</title>
        <author>Charles Dickens</author>
    </book>
    <movie>
        <title>Avatar</title>
        <director>Christopher Nolan</director>
    </movie>
</catalog>

使用SimpleXMLIteratorSimpleXMLElement 解析会产生以下数组:

Array (
    [book] => Array (
        [0] => Array (
            [title] => Array (
                [0] => Harry Potter and the Chamber of Secrets
            )
            [author] => Array (
                [0] => J.K. Rowling
            )
        )
        [1] => Array (
            [title] => Array (
                [0] => Great Expectations
            )
            [author] => Array (
                [0] => Charles Dickens
            )
        )
    )
    [movie] => Array (
        [0] => Array (
            [title] => Array (
                [0] => The Dark Knight
            )
            [director] => Array (
                [0] => Christopher Nolan
            )
        )
        [1] => Array (
            [title] => Array (
                [0] => Avatar
            )
            [director] => Array (
                [0] => James Cameron
            )
        )
    )
)

因为它是这样表示数据的,所以我好像没办法说XML文件中书籍和电影的顺序其实是book, movie, book, movie。它只是将它们分为两类(尽管它保持每个类别中的顺序)。

有没有人知道一种解决方法,或者没有这种行为的不同 XML 解析器?

【问题讨论】:

    标签: php xml xml-parsing simplexml


    【解决方案1】:

    “如果我 ... 使用 SimpleXMLIterator 或 SimpleXMLElement 来解析它,我最终会得到一个数组” - 不,你不会,你最终会得到一个对象,它在某些情况下恰好表现得像一个数组方式。

    该对象的递归转储的输出与迭代它的结果不同

    特别是,运行foreach( $some_node-&gt;children() as $child_node ) 将按照它们在文档中出现的顺序为您提供节点的所有子节点,无论名称如何,如this live code demo 所示。

    代码:

    $xml = <<<EOF
    <catalog>
        <book>
            <title>Harry Potter and the Chamber of Secrets</title>
            <author>J.K. Rowling</author>
        </book>
        <movie>
            <title>The Dark Knight</title>
            <director>Christopher Nolan</director>
        </movie>
        <book>
            <title>Great Expectations</title>
            <author>Charles Dickens</author>
        </book>
        <movie>
            <title>Avatar</title>
            <director>Christopher Nolan</director>
        </movie>
    </catalog>
    EOF;
    
    $sx = simplexml_load_string($xml);
    foreach ( $sx->children() as $node )
    {
        echo $node->getName(), '<br />';
    }
    

    输出:

    book
    movie
    book
    movie
    

    【讨论】:

    • 嗯,好的,谢谢!我知道你得到了一个对象,但是当我用SimpleXMLIterator 解析时,在我的例子中,我确实 得到了一个数组,因为当我解析时我把所有的东西都放入了一个数组中。但我一定做错了什么,因为您的代码不仅非常简单,而且可以按我的意愿工作。谢谢!
    • @JoshSherick 您创建的数组结构无法保留项目的顺序,因为您的结果中只有两个顶级项目:'book''movie'。这是一个很好的例子,说明为什么拥有一个 SimpleXML 对象比尝试将整个 XML 文档表示为一个数组更好 - 不同的目的需要不同类型的遍历。
    【解决方案2】:

    您可以使用 Order 注释:

    @Root(name="Person")
    @Order(elements={"first", "second", "third"})
    public class Person {
        private String first;
        private String second;
        private String third;
    }
    

    http://simple.sourceforge.net/download/stream/doc/tutorial/tutorial.php#deserialize

    【讨论】:

    • 您似乎误读了这个问题。这是关于名为 SimpleXML 的 PHP 模块,与同名的 Java 库无关。
    猜你喜欢
    • 2015-11-29
    • 2023-03-08
    • 2013-03-21
    • 2015-04-21
    • 2012-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多