【问题标题】:Is there an xml_encode() like json_encode() in PHP?PHP中有没有像json_encode()这样的xml_encode()?
【发布时间】:2011-11-28 08:59:52
【问题描述】:

在 PHP 中,使用 json_encode() 很容易传回 json 对象。
但是,是否有与此等效的 XML?

【问题讨论】:

    标签: php xml ajax


    【解决方案1】:

    您可以定义自己的xml_encode() 函数,例如来自http://darklaunch.com/2009/05/23/php-xml-encode-using-domdocument-convert-array-to-xml-json-encode 的函数

    function xml_encode($mixed, $domElement=null, $DOMDocument=null) {
        if (is_null($DOMDocument)) {
            $DOMDocument =new DOMDocument;
            $DOMDocument->formatOutput = true;
            xml_encode($mixed, $DOMDocument, $DOMDocument);
            echo $DOMDocument->saveXML();
        }
        else {
            // To cope with embedded objects 
            if (is_object($mixed)) {
              $mixed = get_object_vars($mixed);
            }
            if (is_array($mixed)) {
                foreach ($mixed as $index => $mixedElement) {
                    if (is_int($index)) {
                        if ($index === 0) {
                            $node = $domElement;
                        }
                        else {
                            $node = $DOMDocument->createElement($domElement->tagName);
                            $domElement->parentNode->appendChild($node);
                        }
                    }
                    else {
                        $plural = $DOMDocument->createElement($index);
                        $domElement->appendChild($plural);
                        $node = $plural;
                        if (!(rtrim($index, 's') === $index)) {
                            $singular = $DOMDocument->createElement(rtrim($index, 's'));
                            $plural->appendChild($singular);
                            $node = $singular;
                        }
                    }
    
                    xml_encode($mixedElement, $node, $DOMDocument);
                }
            }
            else {
                $mixed = is_bool($mixed) ? ($mixed ? 'true' : 'false') : $mixed;
                $domElement->appendChild($DOMDocument->createTextNode($mixed));
            }
        }
    }
    

    【讨论】:

    • 工作正常,只是要小心,它太聪明了——如果你有一个以“s”结尾的标签名称——它会自动生成一个单数形式的标签并将其添加到里面...(例如,在制作具有不应有任何“坐标”子标签的“坐标”标签的 kml 时尝试):-P
    【解决方案2】:

    JSON 可以原生表达 php 数组、整数、字符串等。 XML 没有这样的概念——只有元素、属性和文本。如果要逐字传输对象,请使用 JSON。如果要实现复杂的 API,请使用 XML,例如 php DOM interface

    【讨论】:

    • 请注意,JSON 不是二进制安全的,这意味着您不能安全地将任何可能包含二进制数据的变量添加到 json。 (这意味着,例如,您不能通过 JSON 安全地发送 PDF) - 例如,这 非常 可能会失败并且只返回 bool(false): json encoding error: <?php var_dump(json_encode(array('bin'=>random_bytes(1337))));
    • 我作弊,我将二进制数据转换为字符串数据并使用 json 发送。在另一端,您只需将其再次转换回来。
    【解决方案3】:

    你可以使用xmlrpc_encode

     xmlrpc_encode ($your_array);
    

    请小心,因为此功能是实验性的。

    参考:http://php.net/manual/en/function.xmlrpc-encode.php

    【讨论】:

    • 这是一个 noce 函数,但有时会动摇。
    • 确实,自 PHP 4.1.0 起,21 年前的实验性版本。
    【解决方案4】:

    这里是 php7.0+ 的一个,我敢打赌它远非最佳,代码很重要,并且 没有 进行了很多测试,但至少它适用于我的数据(不像 Seph 的代码)...

    示例:

    $test = array (
            'normal1' => 'foo',
            'normal2' => 'bar',
            'foo_assoc' => [ 
                    'foo',
                    'bar',
                    'baz',
                    [ 
                            'derp',
                            'derpmore' 
                    ] 
            ],
            'foo_nonassoc' => [ 
                    'derppp' => 'yes',
                    'daarpp' => 'no',
                    'lel',
                    'far' => 'away' 
            ],
            'normal3' => 'lala',
            'deep' => [ 
                    'deeper' => [ 
                            'deeper2' => [ 
                                    'deepest' => [ 
                                            'quite',
                                            'deep',
                                            'indeed' 
                                    ],
                                    'checkmate' 
                            ] 
                    ] 
            ],
            'special' => 'encoding<special>characters&test',
            'me_n_you' => 'true' 
    );
    
    echo (hhb_xml_encode ( $test ));
    

    输出:

    <normal1>foo</normal1>
    <normal2>bar</normal2>
    <foo_assoc>foo</foo_assoc>
    <foo_assoc>bar</foo_assoc>
    <foo_assoc>baz</foo_assoc>
    <foo_assoc>derp</foo_assoc>
    <foo_assoc>derpmore</foo_assoc>
    <foo_nonassoc>
      <derppp>yes</derppp>
      <daarpp>no</daarpp>
      <foo_nonassoc>lel</foo_nonassoc>
      <far>away</far>
    </foo_nonassoc>
    <normal3>lala</normal3>
    <deep>
      <deeper>
        <deeper2>
          <deepest>quite</deepest>
          <deepest>deep</deepest>
          <deepest>indeed</deepest>
          <deeper2>checkmate</deeper2>
        </deeper2>
      </deeper>
    </deep>
    <special>encoding&lt;special&gt;characters&amp;test</special>
    <me_n_you>true</me_n_you>
    

    功能:

    • 编辑:修复了编码空数组的错误。
    • 编辑:使代码与 PHP8 兼容
        function hhb_xml_encode(array $arr, string $name_for_numeric_keys = 'val'): string {
            if (empty ( $arr )) {
                // avoid having a special case for <root/> and <root></root> i guess
                return '';
            }
            $is_iterable_compat = function ($v): bool {
                // php 7.0 compat for php7.1+'s is_itrable
                return is_array ( $v ) || ($v instanceof \Traversable);
            };
            $isAssoc = function (array $arr): bool {
                // thanks to Mark Amery for this
                if (array () === $arr)
                    return false;
                return array_keys ( $arr ) !== range ( 0, count ( $arr ) - 1 );
            };
            $endsWith = function (string $haystack, string $needle): bool {
                // thanks to MrHus
                $length = strlen ( $needle );
                if ($length == 0) {
                    return true;
                }
                return (substr ( $haystack, - $length ) === $needle);
            };
            $formatXML = function (string $xml) use ($endsWith): string {
                // there seems to be a bug with formatOutput on DOMDocuments that have used importNode with $deep=true
                // on PHP 7.0.15...
                $domd = new DOMDocument ( '1.0', 'UTF-8' );
                $domd->preserveWhiteSpace = false;
                $domd->formatOutput = true;
                $domd->loadXML ( '<root>' . $xml . '</root>' );
                $ret = trim ( $domd->saveXML ( $domd->getElementsByTagName ( "root" )->item ( 0 ) ) );
                assert ( 0 === strpos ( $ret, '<root>' ) );
                assert ( $endsWith ( $ret, '</root>' ) );
                $full = trim ( substr ( $ret, strlen ( '<root>' ), - strlen ( '</root>' ) ) );
                $ret = '';
                // ... seems each line except the first line starts with 2 ugly spaces,
                // presumably its the <root> element that starts with no spaces at all.
                foreach ( explode ( "\n", $full ) as $line ) {
                    if (substr ( $line, 0, 2 ) === '  ') {
                        $ret .= substr ( $line, 2 ) . "\n";
                    } else {
                        $ret .= $line . "\n";
                    }
                }
                $ret = trim ( $ret );
                return $ret;
            };
            
            // $arr = new RecursiveArrayIterator ( $arr );
            // $iterator = new RecursiveIteratorIterator ( $arr, RecursiveIteratorIterator::SELF_FIRST );
            $iterator = $arr;
            $domd = new DOMDocument ();
            $root = $domd->createElement ( 'root' );
            foreach ( $iterator as $key => $val ) {
                // var_dump ( $key, $val );
                $ele = $domd->createElement ( is_int ( $key ) ? $name_for_numeric_keys : $key );
                if (! empty ( $val ) || $val === '0') {
                    if ($is_iterable_compat ( $val )) {
                        $asoc = $isAssoc ( $val );
                        $tmp = hhb_xml_encode ( $val, is_int ( $key ) ? $name_for_numeric_keys : $key );
                        // var_dump ( $tmp );
                        // die ();
                        $tmpDom = new DOMDocument();
                        @$tmpDom->loadXML ( '<root>' . $tmp . '</root>' );
                        foreach ( $tmpDom->getElementsByTagName ( "root" )->item ( 0 )->childNodes ?? [ ] as $tmp2 ) {
                            $tmp3 = $domd->importNode ( $tmp2, true );
                            if ($asoc) {
                                $ele->appendChild ( $tmp3 );
                            } else {
                                $root->appendChild ( $tmp3 );
                            }
                        }
                        unset ( $tmp, $tmp2, $tmp3, $tmpDom );
                        if (! $asoc) {
                            // echo 'REMOVING';die();
                            // $ele->parentNode->removeChild($ele);
                            continue;
                        }
                    } else {
                        $ele->textContent = $val;
                    }
                }
                $root->appendChild ( $ele );
            }
            $domd->preserveWhiteSpace = false;
            $domd->formatOutput = true;
            $ret = trim ( $domd->saveXML ( $root ) );
            assert ( 0 === strpos ( $ret, '<root>' ) );
            assert ( $endsWith ( $ret, '</root>' ) );
            $ret = trim ( substr ( $ret, strlen ( '<root>' ), - strlen ( '</root>' ) ) );
            // seems to be a bug with formatOutput on DOMDocuments that have used importNode with $deep=true..
            $ret = $formatXML ( $ret );
            return $ret;
        }
    

    【讨论】:

    • 有点晚了,但是值得注意的是这里不包含doctype或者根元素,从而变成了格式不好的XML,可以将return $ret;替换成return '&lt;?xml version="1.0" encoding="UTF-8"?&gt;&lt;root&gt;' . $ret . '&lt;/root&gt;';
    • “一年多之后,”我非常感谢您——以及随后的 Ben——分享了这段代码。它工作得很好。非常感谢你“救了我的培根”。 :-)
    【解决方案5】:

    我的贡献:

    function xml_encode(mixed $value=null, string $key="root", SimpleXMLElement $parent=null){
        if(is_object($value)) $value = (array) $value;
        if(!is_array($value)){
            if($parent === null){   
                if(is_numeric($key)) $key = 'item';             
                if($value===null) $node = new SimpleXMLElement("<$key />");
                else              $node = new SimpleXMLElement("<$key>$value</$key>");
            }
            else{
                $parent->addChild($key, $value);
                $node = $parent;
            }
        }
        else{
            $array_numeric = false;
            if($parent === null){ 
                if(empty($value)) $node = new SimpleXMLElement("<$key />");
                else              $node = new SimpleXMLElement("<$key></$key>");
            }
            else{
                if(!isset($value[0])) $node = $parent->addChild($key);
                else{
                    $array_numeric = true;
                    $node = $parent;
                }
            }
            foreach( $value as $k => $v ) {
                if($array_numeric) xml_encode($v, $key, $node);
                else xml_encode($v, $k, $node);
            }
        }       
        return $node;
    }
    

    简单示例:

       $a = "hello";
       $xml_element = xml_encode($a,'a');
       echo $xml_element->asXML();
    

    空示例:

       $xml_element = xml_encode(null,'example');
       echo $xml_element->asXML();
    

    复杂示例:

       $w = new stdClass();
       $w->special = true;
       $w->name = 'Birthday Susan';
        
       $v = new stdClass();
       $v->name = 'John';
       $v->surname = 'Smith';
       $v->hobbies = array('soccer','cinema');
       $v->job = 'policeman';
       $v->events = new stdClass();
       $v->events->tomorrow = false;
       $v->events->yesterday = true;
       $v->events->list = array($v->hobbies, $w);
        
       $xml_element = xml_encode($v,'oembed');
       echo $xml_element->asXML();
    

    【讨论】:

      【解决方案6】:

      这在大多数情况下对我有用:

      $str = htmlentities($str , ENT_XML1);
      

      文档: http://php.net/manual/en/function.htmlentities.php

      【讨论】:

      • 不支持数组,也不创建 xml 文件,它只是对单个字符串进行 xml 编码(将 转换为 >< 等)
      • 我恭敬地同意这样的观点,即此响应与 OP 的情况确实无关,尽管它完全适合其预期的情况。但是,无论如何,谢谢。
      • 如果你的 XML 结构已经生成,这其实是很方便的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-26
      • 2015-09-01
      相关资源
      最近更新 更多