PHP 的 SimpleXML 不保持不同元素类型之间的顺序
Posted
技术标签:
【中文标题】PHP 的 SimpleXML 不保持不同元素类型之间的顺序【英文标题】:PHP's SimpleXML doesn't keep order between different element types 【发布时间】:2014-06-21 02:43:34 【问题描述】:据我所知,当您在 XML 文档树中的同一级别有多种类型的元素时,php 的 SimpleXML
,包括 SimpleXMLElement
和 SimpleXMLIterator
都不会保持元素的顺序因为它们彼此相关,仅在每个元素内。
例如,考虑以下结构:
<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>
如果我有这个结构并使用SimpleXMLIterator
或SimpleXMLElement
来解析它,我最终会得到一个看起来像这样的数组:
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>
使用SimpleXMLIterator
或SimpleXMLElement
解析会产生以下数组:
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->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 中删除具有特定属性的子项