Analisar XML em array associativo (com suporte a CDATA)

Vários dias atrás, tentei analisar um arquivo XML em uma matriz associativa. Com o uso de implexml_load_fileou simplexml_load_string, combinado com json_decodee json_encodeparece funcionar perfeitamente.
Dê uma olhada na seguinte função:

/**
*
@param SimpleXMLElement $xml
* @return mixed

*/

function toAssocArray($xml) {
$string
= json_encode($xml);
$array
= json_decode($string, true);
return $array;
}

Embora pareça bastante útil, há uma limitação em relação ao <! CDATA […]> .
Considere o seguinte xml:

<?xml version="1.0" encoding="utf-8"?>
<sample>
<sample1>foo<!CDATA[bar]></sample1>
<sample2><!CDATA[foobar]></sample2>
</sample>

Se usarmos toAssocArray, o valor de sample1 será “foobar”, como esperado. Mas se dermos uma olhada no valor de sample2 , notaremos que ele contém um array vazio – o conteúdo real “foobar” é perdido.

Para nos livrarmos desse comportamento, temos que remover o <! CDATA [..]> e filtrar seu valor (porque normalmente você armazena dados que poderiam ser interpretados como XML / HTML, mas não deveriam).
Portanto, temos que usar preg_replace_callbackna string XML junto com uma função de filtro personalizada, antes de analisá-la em um SimpleXMLElement e, finalmente, em um array associativo.

Isso tem uma desvantagem: se quisermos obter o XML de um arquivo, temos que usar em file_get_contentsvez de simplexml_load_file, porque simplexml_load_fileretornará um SimpleXMLElement, no qual não podemos aplicar nosso filtro.

Portanto, estas são nossas funções finais:

/**
*
@param SimpleXMLElement $xml
* @return mixed

*/

function toAssocArray($xml) {
$string
= json_encode($xml);
$array
= json_decode($string, true);
return $array;
}
/**
*
@param string $xml
* @return SimpleXMLElement

*/

function betterxml_load_string($xml) {
$string
= preg_replace_callback('/<![CDATA[(.*)]]>/', 'cdata_filter', $xml);
$xml
= simplexml_load_string($string);
return $xml;
}
/**
*
@param array $matches
* @return string

*/

function cdata_filter($matches) {
$converted
= htmlspecialchars($matches[1];
$trimmed
= trim($converted);
return $trimmed;
}

E nós o usamos da seguinte maneira:

$xml = file_get_contents('some/xml/file.xml');
$assoc
= toAssocArray($xml);

echo $assoc
['sample1'];