2011-09-30 24 views

Respuesta

8

JSON puede expresar arrays php, enteros, cadenas, etc. de forma nativa. XML no tiene tales conceptos, solo elementos, atributos y texto. Si desea transferir un objeto al pie de la letra, use JSON. Si desea implementar una API compleja, use XML, por ejemplo, php DOM interface.

7

Puede definir su propia función xml_encode() como este el de 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)); 
     } 
    } 
} 
+3

funciona bien, sólo ten cuidado, es demasiado inteligente para su propio bien - si usted tiene un nombre de etiqueta que termina con 's' - que le hará automáticamente una forma singular de la etiqueta y añadir que en su interior .. . (Intente eso, por ejemplo, al hacer kml que tiene una etiqueta de 'coordenadas' que no debe tener ninguna subetiqueta de 'coordenadas') :-P – MortenSickel

1

Aquí está uno para php7.0 +, apuesto a que está lejos de ser óptima , el código no es trivial, y tiene NO probado mucho, pero al menos funciona para mis datos (a diferencia del código de Seph) ...

ejemplo:

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

salida:

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

función: - Editar: corregido un error con la codificación matrices vacías.

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(); 
       $tmp = @DOMDocument::loadXML ('<root>' . $tmp . '</root>'); 
       foreach ($tmp->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); 
       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; 
} 
+1

Un poco tarde, pero vale la pena señalar que esto no incluye un doctype o un elemento raíz, convirtiéndose en XML mal formado, puede reemplazar 'return $ ret;' con 'return ''. $ ret. ''; ' – Ben

Cuestiones relacionadas