递归遍历 SimpleXML 对象*结构未知*
Recursively iterating through a SimpleXML object *where the structure is not known*
我在网上找到的每个 xml 迭代示例(包括 PHP 文档、W3School 和堆栈溢出 搜索)都假定我们知道结构提前。我想创建一个循环,在每个分支中尽可能深入地迭代,并简单地 returns 它找到的节点名称和值。例如:
<za-lord>
<orderid>dresden1234</orderid>
<customer>toot-toot</customer>
<pizza>
<sauce>marinara</sauce>
<crust>thin</crust>
<toppings>
<cheese>extra</cheese>
<veg>
<onions>yes</onions>
<peppers>extra</peppers>
<olives>no</olives>
</veg>
<meat>
<groundbeef>yes</groundbeef>
<ham>no</ham>
<sausage>no</sausage>
</meat>
</toppings>
</pizza>
</za-lord>
那么我要找的是:
orderid = dresden1234
customer = toot-toot
sauce = marinara
crust = thin
cheese = extra
onions = yes
peppers = extra
olives = no
groundbeef = yes
ham = no
sausage = no
我现在已经花了几个小时编写代码示例,测试 foreach 的不同变体,简而言之,没有任何东西可以满足我的需求。事先不知道结构,是否可以使用 SimpleXML 递归迭代上面的 xml 和 return 节点名称和值,如果可以,如何?
您可以使用 SimpleXMLIterator
对象并对其进行递归以获取所有节点值:
function list_nodes($sxi) {
for($sxi->rewind(); $sxi->valid(); $sxi->next() ) {
if ($sxi->hasChildren()) {
list_nodes($sxi->current());
}
else {
echo $sxi->key() . " = " . $sxi->current() . "\n";
}
}
}
$sxi = new SimpleXMLIterator($xmlstr);
list_nodes($sxi);
输出:
orderid = dresden1234
customer = toot-toot
sauce = marinara
crust = thin
cheese = extra
onions = yes
peppers = extra
olives = no
groundbeef = yes
ham = no
sausage = no
更新
如果您的 xml 可以有命名空间,您必须采取更复杂的方法,检查文档中每个命名空间中每个节点的子节点:
function list_children($node, $names) {
$children = false;
foreach ($names as $name) {
if (count($node->children($name))) {
$children = true;
foreach ($node->children($name) as $child) {
list_children($child, $names);
}
}
}
if (!$children) {
echo $node->getName() . " = $node\n";
}
}
$xml = new SimpleXMLElement($xmlstr);
list_children($xml, array_merge(array(''), $xml->getNamespaces(true)));
输出(对于演示 xml,与问题相同但添加了名称空间):
orderid = dresden1234
customer = toot-toot
sauce = marinara
crust = thin
cheese = extra
onions = yes
peppers = extra
olives = no
ham = no
sausage = no
groundbeef = yes
我在网上找到的每个 xml 迭代示例(包括 PHP 文档、W3School 和堆栈溢出 搜索)都假定我们知道结构提前。我想创建一个循环,在每个分支中尽可能深入地迭代,并简单地 returns 它找到的节点名称和值。例如:
<za-lord>
<orderid>dresden1234</orderid>
<customer>toot-toot</customer>
<pizza>
<sauce>marinara</sauce>
<crust>thin</crust>
<toppings>
<cheese>extra</cheese>
<veg>
<onions>yes</onions>
<peppers>extra</peppers>
<olives>no</olives>
</veg>
<meat>
<groundbeef>yes</groundbeef>
<ham>no</ham>
<sausage>no</sausage>
</meat>
</toppings>
</pizza>
</za-lord>
那么我要找的是:
orderid = dresden1234
customer = toot-toot
sauce = marinara
crust = thin
cheese = extra
onions = yes
peppers = extra
olives = no
groundbeef = yes
ham = no
sausage = no
我现在已经花了几个小时编写代码示例,测试 foreach 的不同变体,简而言之,没有任何东西可以满足我的需求。事先不知道结构,是否可以使用 SimpleXML 递归迭代上面的 xml 和 return 节点名称和值,如果可以,如何?
您可以使用 SimpleXMLIterator
对象并对其进行递归以获取所有节点值:
function list_nodes($sxi) {
for($sxi->rewind(); $sxi->valid(); $sxi->next() ) {
if ($sxi->hasChildren()) {
list_nodes($sxi->current());
}
else {
echo $sxi->key() . " = " . $sxi->current() . "\n";
}
}
}
$sxi = new SimpleXMLIterator($xmlstr);
list_nodes($sxi);
输出:
orderid = dresden1234
customer = toot-toot
sauce = marinara
crust = thin
cheese = extra
onions = yes
peppers = extra
olives = no
groundbeef = yes
ham = no
sausage = no
更新
如果您的 xml 可以有命名空间,您必须采取更复杂的方法,检查文档中每个命名空间中每个节点的子节点:
function list_children($node, $names) {
$children = false;
foreach ($names as $name) {
if (count($node->children($name))) {
$children = true;
foreach ($node->children($name) as $child) {
list_children($child, $names);
}
}
}
if (!$children) {
echo $node->getName() . " = $node\n";
}
}
$xml = new SimpleXMLElement($xmlstr);
list_children($xml, array_merge(array(''), $xml->getNamespaces(true)));
输出(对于演示 xml,与问题相同但添加了名称空间):
orderid = dresden1234
customer = toot-toot
sauce = marinara
crust = thin
cheese = extra
onions = yes
peppers = extra
olives = no
ham = no
sausage = no
groundbeef = yes