Convert XML to PHP array

Asked

Viewed 7,907 times

7

I’m fetching article names by this link:

[http://api.elsevier.com/content/search/index:SCIDIR?query=heart+attack&apiKey=20d0c7953f56925f725afe204869dadb&xml-decode=true&httpAccept=application%2Fxml][1]

You are returning the result in XML, now I need to convert the result into an array. I am using the following function:

$page = file_get_contents("http://api.elsevier.com/content/search/index:SCIDIR?query=heart+attack&apiKey=20d0c7953f56925f725afe204869dadb&xml-decode=true&httpAccept=application%2Fxml");
$xml = simplexml_load_string($page);
$json = json_encode($xml);
$array = json_decode($json,TRUE);
echo "<pre>";
print_r($array);

The problem is that not all fields are passed to the array, for example in the title of the article does not pass to the array. Is there another function that passes all XML fields to the array? I also experienced it as follows but the result is identical:

$xml   = simplexml_load_string($buffer);
$array = json_decode(json_encode((array) $xml), 1);
$array = array($xml->getName() => $array);

2 answers

6


To convert correctly an XML for Array without the need to use JSON, the method below can be used for this.

function xmlToArray($xml, $options = array()) {
    $defaults = array(
        'namespaceSeparator' => ':', // você pode querer que isso seja algo diferente de um cólon
        'attributePrefix' => '@',    // para distinguir entre os nós e os atributos com o mesmo nome
        'alwaysArray' => array(),    // array de tags que devem sempre ser array
        'autoArray' => true,         // só criar arrays para as tags que aparecem mais de uma vez
        'textContent' => '$',        // chave utilizada para o conteúdo do texto de elementos
        'autoText' => true,          // pular chave "textContent" se o nó não tem atributos ou nós filho
        'keySearch' => false,        // pesquisa opcional e substituir na tag e nomes de atributos
        'keyReplace' => false        // substituir valores por valores acima de busca
    );
    $options = array_merge($defaults, $options);
    $namespaces = $xml->getDocNamespaces();
    $namespaces[''] = null; // adiciona namespace base(vazio) 

    // Obtém os atributos de todos os namespaces
    $attributesArray = array();
    foreach ($namespaces as $prefix => $namespace) {
        foreach ($xml->attributes($namespace) as $attributeName => $attribute) {
            // Substituir caracteres no nome do atributo
            if ($options['keySearch']) $attributeName =
                    str_replace($options['keySearch'], $options['keyReplace'], $attributeName);
            $attributeKey = $options['attributePrefix']
                    . ($prefix ? $prefix . $options['namespaceSeparator'] : '')
                    . $attributeName;
            $attributesArray[$attributeKey] = (string)$attribute;
        }
    }

    // Obtém nós filhos de todos os namespaces
    $tagsArray = array();
    foreach ($namespaces as $prefix => $namespace) {
        foreach ($xml->children($namespace) as $childXml) {
            // Recursividade em nós filho
            $childArray = xmlToArray($childXml, $options);
            list($childTagName, $childProperties) = each($childArray);

            // Substituir caracteres no nome da tag
            if ($options['keySearch']) $childTagName =
                    str_replace($options['keySearch'], $options['keyReplace'], $childTagName);
            // Adiciona um prefixo namespace, se houver
            if ($prefix) $childTagName = $prefix . $options['namespaceSeparator'] . $childTagName;

            if (!isset($tagsArray[$childTagName])) {
                // Só entra com esta chave
                // Testa se as tags deste tipo deve ser sempre matrizes, não importa a contagem de elementos
                $tagsArray[$childTagName] =
                        in_array($childTagName, $options['alwaysArray']) || !$options['autoArray']
                        ? array($childProperties) : $childProperties;
            } elseif (
                is_array($tagsArray[$childTagName]) && array_keys($tagsArray[$childTagName])
                === range(0, count($tagsArray[$childTagName]) - 1)
            ) {
                $tagsArray[$childTagName][] = $childProperties;
            } else {
                $tagsArray[$childTagName] = array($tagsArray[$childTagName], $childProperties);
            }
        }
    }

    // Obtém o texto do nó
    $textContentArray = array();
    $plainText = trim((string)$xml);
    if ($plainText !== '') $textContentArray[$options['textContent']] = $plainText;

    $propertiesArray = !$options['autoText'] || $attributesArray || $tagsArray || ($plainText === '')
            ? array_merge($attributesArray, $tagsArray, $textContentArray) : $plainText;

    // Retorna o nó como array
    return array(
        $xml->getName() => $propertiesArray
    );
}

Source

Example of use:

$page = file_get_contents("http://api.elsevier.com/content/search/index:SCIDIR?query=heart+attack&apiKey=20d0c7953f56925f725afe204869dadb&xml-decode=true&httpAccept=application%2Fxml");

$xml = simplexml_load_string($page);
$arrayData = xmlToArray($xml);
echo "<pre>";
print_r($arrayData);

Codepad.Viper-7 Demo

  • Thanks! I’m only having trouble with this solution, everything works ok but how can I count the entries of the array? I am trying to use Count($array['search-Results']) but gives the following error: Cannot use Object of type stdClass as array in

  • 1

    @pc_oc echo count($arrayData['search-results']); seems to work for me.

3

I would not advise doing this gambit with JSON. At simplexml documentation has an example of how to create a array from the XML.

function XML2Array($xmlContent, $out = array()){
    $xmlObject = is_object($xmlContent) ? $xmlContent : simplexml_load_string($xmlContent);
    foreach((array) $xmlObject as $index => $node)
        $out[$index] = ( is_object($node) || is_array($node) ) ? XML2Array( $node ) : $node;
    return $out;
}

$page = file_get_contents("http://api.elsevier.com/content/search/index:SCIDIR?query=heart+attack&apiKey=CHAVEAQUI&xml-decode=true&httpAccept=application%2Fxml");
$array = XML2Array($page);

I put in the Github for future reference.

If you still have problems, you probably have a problem elsewhere, maybe a poorly formed XML.

  • Yeah, I’m sorry, there was something wrong with my code, I was calling the function wrong. Now I put everything ok, but it still gives the same error as the implexml_load_string() expects Parameter 1 to be string, array Given in

  • It is a little strange to give this error because it has no function with this name, it has a function called simplexml_load_string. To file_get_contents returns a string, so the right kind is being passed to XML2Srray and consequently to the simplexml_load_string. I was able to do the controlled test http://ideone.com/kmOZIi

  • @The problem with this code is that within the foreach you accept $Node to be an array (in the ternary equation where you check if there is a need for recursion) however, in the input of the start of the function you just check if it is an object. You can fix this problem of simplexml_load_string basically replacing the condiconal to is_object($xmlContent) || is_array($xmlContent)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.