【问题标题】:PHP xml to array - how to get rid of empty tags?PHP xml 到数组 - 如何摆脱空标签?
【发布时间】:2019-09-06 22:22:32
【问题描述】:

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
//                 ],
//             ],
//         ],
//     ],
// ];

如您所见,&lt;bat/&gt; 标记为空,最后一个 &lt;bat&gt; &lt;/bat&gt; 标记中有一个空格。

我想把这些放到数组中的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

以前有人做过吗?

编辑

已解决。见https://stackoverflow.com/a/55733384/3411766

【问题讨论】:

  • 每次我看到有人试图编写一个通用的 XML 到数组的函数,特别是当它以像 $array = json_decode(json_encode((array)$xml), true); 这样的 hack 开头时,我感到绝望。与其在通用算法给出“错误”答案的所有情况下跳入特殊情况,不如使用 XML 解析器(如 SimpleXML)来访问您实际需要的数据,并创建一个数组(或预定义对象)这对您的实际应用很有意义。

标签: php arrays xml recursion simplexml


【解决方案1】:

您可以使用XPathpredicate 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>

问候!

【讨论】:

  • 不确定最后一个元素 &lt;bat&gt; &lt;/bat&gt; 在 OP 版本中是否有空格。
  • 这里像@NigelRen 回答一样:这会删除偏移量。正如发布的那样,我想让它们为空。所以 {offset} 没有设置但存在。与 xml 相同(存在但为空)
【解决方案2】:

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

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

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

并返回 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);

返回:

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

【讨论】:

  • 谢谢,这正是我需要的!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-20
  • 2021-08-26
  • 1970-01-01
  • 2011-11-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多