在xml to array - remove empty array php处存在相同的问题 不知道你如何处理。我的意思是我如何才能获得一个不是2年前问到的问题的答案。 因此,我在这里问自己的问题:
简单脚本:
$xml
= '<?xml version="1.0"?>
<Envelope>
<foo>
<bar>
<baz>Hello</baz>
<bat/>
</bar>
</foo>
<foo>
<bar>
<baz>Hello Again</baz>
<bat></bat>
</bar>
</foo>
<foo>
<bar>
<baz>Hello Again</baz>
<bat> </bat>
</bar>
</foo>
</Envelope>';
$xml = new \SimpleXMLElement(
$xml,
LIBXML_NOBLANKS | LIBXML_NOEMPTYTAG | LIBXML_NOCDATA
);
$array = json_decode(json_encode((array)$xml), true);
// [
// 'foo' => [
// 0 => [
// 'bar' => [
// 'baz' => 'Hello',
// 'bat' => [], <<-- how to get this to NULL
// ],
// ],
// 1 => [
// 'bar' => [
// 'baz' => 'Hello Again',
// 'bat' => [], <<-- how to get this to NULL
// ],
// ],
// 2 => [
// 'bar' => [
// 'baz' => 'Hello Again',
// 'bat' => [ <<-- how to get this to NULL
// 0 => ' ', or at least to value of " " without array
// ],
// ],
// ],
// ],
// ];
如您所见,<bat/>
标签为空,最后一个<bat> </bat>
标签为空白。
我想将它们发送到数组中的null
。
我尝试了以下操作,但这仅适用于第一级ofc:
$data = (array)$xml;
foreach ($data as &$item) {
if (
$item instanceof \SimpleXMLElement
and $item->count() === 0
) {
// is a object(SimpleXMLElement)#1 (0) {}
$item = null;
}
}
我尝试递归执行失败。
也尝试了RecursiveIteratorIterator
但失败了。
但是必须有一种方法可以使这些偏移量变为null
。
有人做过吗?
编辑
答案 0 :(得分:0)
您可以将XPath与predicate not(node())
一起使用,以选择所有没有子节点的元素。
<?php
$doc = new DOMDocument;
$doc->preserveWhiteSpace = false;
$doc->loadxml('<?xml version="1.0"?>
<Envelope>
<foo>
<bar>
<baz>Hello</baz>
<bat/>
</bar>
</foo>
<foo>
<bar>
<baz>Hello Again</baz>
<bat></bat>
</bar>
</foo>
<foo>
<bar>
<baz>Hello Again</baz>
<bat></bat>
</bar>
</foo>
</Envelope>');
$xpath = new DOMXPath($doc);
foreach( $xpath->query('//*[not(node())]') as $node ) {
$node->parentNode->removeChild($node);
}
$doc->formatOutput = true;
echo $doc->savexml();
打印:
<?xml version="1.0"?>
<Envelope>
<foo>
<bar>
<baz>Hello</baz>
</bar>
</foo>
<foo>
<bar>
<baz>Hello Again</baz>
</bar>
</foo>
<foo>
<bar>
<baz>Hello Again</baz>
</bar>
</foo>
</Envelope>
致谢!
答案 1 :(得分:0)
发现我自己。 花点时间但效果很好。
/**
* @param array|\SimpleXMLElement[]|\SimpleXMLElement $data .
*
* @return array
*/
protected function emptyNodesToNull($data)
{
if ($data instanceof \SimpleXMLElement and $data->count() === 0) {
// is empty object like
// SimpleXMLElement::__set_state(array())
// which was f.e. a <foo/> tag
// or
// SimpleXMLElement::__set_state(array(0 => ' ',))
// which was f.e. a <foo> </foo> (with white space only)
return null;
}
$data = (array)$data;
foreach ($data as &$value) {
if (is_array($value) or $value instanceof \SimpleXMLElement) {
$value = $this->emptyNodesToNull($value);
} else {
// $value is the actual value of a node.
// Could do further checks here.
}
}
return $data;
}
我的测试完全符合我的预期
并完全从xmlToArray方法返回imo。
我的意思是我们将无法处理属性,但这不是必需条件。
测试:
$xml
= '<?xml version="1.0"?>
<Envelope>
<a/><!-- expecting null -->
<foo>
<b/><!-- expecting null -->
<bar>
<baz>Hello</baz>
<!-- expecting here an array of 2 x null -->
<c/>
<c/>
</bar>
</foo>
<foo>
<bar>
<baz>Hello Again</baz>
<d> </d><!-- expecting null -->
<item>
<firstname>Foo</firstname>
<email></email><!-- expecting null -->
<telephone/><!-- expecting null -->
<lastname>Bar</lastname>
</item>
<item>
<firstname>Bar</firstname>
<email>0</email><!-- expecting value 0 (zero) -->
<telephone/><!-- expecting null -->
<lastname>Baz</lastname>
</item>
<!-- expecting array of values 1, 2 null, 4 -->
<number>1</number>
<number>2</number>
<number></number>
<number>4</number>
</bar>
</foo>
</Envelope>';
$xml = new \SimpleXMLElement($xml);
$array = $class::emptyNodesToNull($xml);
返回:
[
'Envelope' => [
'a' => null,
'foo' => [
0 => [
'b' => null,
'bar' => [
'baz' => 'Hello',
'c' => [
0 => null,
1 => null,
],
],
],
1 => [
'bar' => [
'baz' => 'Hello Again',
'd' => null,
'item' => [
0 => [
'firstname' => 'Foo',
'email' => null,
'telephone' => null,
'lastname' => 'Bar',
],
1 => [
'firstname' => 'Bar',
'email' => '0',
'telephone' => null,
'lastname' => 'Baz',
],
],
'number' => [
0 => '1',
1 => '2',
2 => null,
3 => '4',
],
],
],
],
],
];