PHP 的 SimpleXML 不保持不同元素类型之间的顺序

Posted

技术标签:

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

据我所知,当您在 XML 文档树中的同一级别有多种类型的元素时,phpSimpleXML,包括 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 解析器?

【问题讨论】:

【参考方案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 库无关。

以上是关于PHP 的 SimpleXML 不保持不同元素类型之间的顺序的主要内容,如果未能解决你的问题,请参考以下文章

使用来自子元素的数据在 php 中使用 simplexml 选择其他元素中的数据

在 SimpleXML for PHP 中删除具有特定属性的子项

PHP 5 SimpleXML 函数

雷林鹏分享:PHP SimpleXML

PHP SimpleXML->addChild - 不需要的空命名空间属性

PHP SimpleXML解析具有多个属性的元素