PHP xml 到数组 - 如何摆脱空标签?

PHP xml to array - how to get rid of empty tags?

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

有人做过吗?

编辑

已解决。参见

可以使用XPath with the predicatenot(node())到select所有没有子节点的元素。

<?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>

此致!

我自己发现的。 花了一些时间,但效果很好

/** 
 * @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;
}

我的测试完全符合我的预期

和 returns imo 正是您对 xmlToArray 方法的期望。

我的意思是我们无法处理属性,但这不是要求。

测试:

    $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);

Returns:

[
    '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',
                    ],
                ],
            ],
        ],
    ],
];