PHP é à quinta-feira – XML num Objecto

13 Comentários

Mais uma quinta e mais um artigo para os interessados em PHP.
A nível de direitos sobre o código, devo remeter-vos para o meu primeiro artigo desta rubrica aqui

Hoje trago-vos uma função que já me ajudou no passado, num projecto em que só podia trabalhar com PHP4 e tinha de fazer parsing de um ficheiro XML cuja sintaxe era conhecida.


Em PHP4 não existe a função simple_xml_load_string.

Esta função também pode ser usada em PHP5 quando o ficheiro XML não tem atributos, etc. pois usa menos recursos (dado que é menos dinâmica e menos complexa) do que a função que referi em cima.

<?php 

function parseXMLtoObject($xml) {
   $obj = new stdClass();
   $xml = explode("\n",$xml);
   $main_n = '';
   foreach ($xml as $x) {
      $first_n = false;
      $close_n = false;
      if ($x != '') {
         $start_val = (strpos($x,">")+1);
         $end_val = strrpos($x,"<") - $start_val;
         $start_n = (strpos($x,"<")+1);
         $end_n = strpos($x,">") - $start_n;
         $n = strtolower(substr($x,$start_n,$end_n));
         if (substr_count($x,"<") == 1) {
            if (!empty($main_n) && !stristr($n,"/")) {
               $submain_n = $n;
               $first_n = true;
            } else {
               $main_n = $n;
               $submain_n = '';
               $first_n = true;
            }
         }
         if (!empty($submain_n) && stristr($submain_n,"/")) {
            $submain_n = '';
            $first_n = false;
            $close_n = true;
         }
         if (!empty($main_n) && stristr($main_n,"/")) {
            $main_n = '';
            $submain_n = '';
            $first_n = false;
            $close_n = true;
         }
         $value = substr($x,$start_val,$end_val);
         if (!$close_n) {
            if (empty($main_n)) {
               $obj->$n = $value;
            } else {
               if ($first_n) {
                  if (empty($submain_n)) {
                     $obj->$main_n = new stdClass();
                  } else {
                     $obj->$main_n->$submain_n = new stdClass();
                  }
               } else {
                  if (!empty($value)) {
                     if (empty($submain_n)) {
                        $obj->$main_n->$n = $value;
                     } else {
                        $obj->$main_n->$submain_n->$n = $value;
                     }
                  }
               }
            }
         }
      }
   }
   return $obj;
} 

?>

Modo de utilização:

Converter Ficheiro XML $a para Object $o

<?php
$a = “ficheiro.xml”;
$xml = file_get_cont
ents($a);

$o = parseXMLtoObject($xml); 

//-- Agora podem visualizar a estrutura do $o desta forma:
echo “<pre>”;print_r($o);echo “</pre>”;//-- Imprime a estrutura do objecto $o
?>

Qualquer dúvida ou sugestão, estão completamente à vontade.

Partilhar:
Tags:

Comentários

13

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *

  1. Avatar de Vítor M.

    Esta rubrica está a ganhar adeptos e podem esses adeptos (caso queiram) sugerir ao Bruno ou ao Pedro Pinto, alguma atenção especial sobre qualquer função.

    Fica a sugestão.

  2. Avatar de Nuno Peralta

    Olá, pessoal!
    Tenho umas pequenas dúvidas de PHP:
    1 – A função:

    while (list($var1, $var2) = each($array))

    executa as funções “list” e “each” completamente sempre que verifica a condição “while”? Do tipo “for ($c = 0; $c < count($array); $c++)”. Aqui a função “count” é executada sempre.

    2 – Para ficheiros XML muuuuito grandes (passados vários anos, fui adicionando muitos “filhos” a um nó, e o ficheiro ficou com 15 MB, por exemplo!), o PHP irá dar um “Fatal Error” de falta de memória. Como lidar com esses casos?

    3 – Para um sistema de multi-language, o que recomenda usar para o ficheiro de linguagem? : XML? Arrays? Defines? – Quero saber o que é mais rápido.

    4 – Para longos nós de XML, se eu fizer algo do estilo: $lista = (array)$objectoXML; isto converte de maneira muito viável, ou é um pouco pesado para o PHP?

    São dúvidas que eu não consigo encontrar resposta na internet 🙁
    Se alguém me responder, eu ficarei muito grato! 🙂

    Obrigado.
    Nuno Peralta

    1. Avatar de Bruno Bernardino

      2 – Essa forma vai renovando a memória alocada nas variáveis $var1 e $var2, por isso pouco do que poderias fazer nesse caso já está feito, talvez o problema esteja no que fazes dentro desse ciclo e não na sua “declaração” em si. Altera o valor do memory_limit no php.ini para um valor um pouco maior.
      Deduzo que o array $array tenha todas as linhas do ficheiro, logo chegando essa variável a um valor muito grande, pelo que podes considerar uma função que lê o ficheiro linha a linha e não tudo de uma só vez.

      3 – Arrays e/ou Defines são mais rápidos de trabalhar (defines mais rápidos ainda, desde que não estejam sempre a ser declarados), porque não requerem um “acesso” ao disco para ler um ficheiro, mas o XML é muito melhor porque qualquer linguagem acede facilmente a ele. Dependerá do tamanho dos dados, provavelmente. Base de dados também será uma boa aposta

      4 – É um bocado “pesado” usar casts, gastam muitas vezes recursos desnecessários, mas funciona. É uma questão de decidires as tuas prioridades, se um programa rápido e funcional, ou que simplesmente funcione, podendo usar alguns recursos a mais. Pessoalmente prefiro sempre ter o tipo de variável logo definido, e antes de a usar fazer uma verificação do tipo is_array() ou is_object().

      A gratidão é o meu dinheiro espiritual 😉

      1. Avatar de Nuno Peralta

        2 – Bem… vou ter que ir aumentando a variavel do php.ini a cada ano que passa? =/

        3 – Então o melhor é usar Arrays 🙂

        4 – Eu quero programas viáveis, como é óbvio 🙂
        Mas… se eu quero ver a intersecção (array_intersect()) de uma lista em XML, a função só funciona se a lista for uma array… se for objecto tenho mesmo que usar cast, não é? 🙁

        Obrigado pelas suas respostas! 😀

        1. Avatar de Bruno Bernardino

          Trata-me por tu, sff 🙂

          2 – Se a lógica do programa se mantiver (o que necessita de recursos depende directamente do tamanho do ficheiro), terás de aumentar consoante necessitas, sim. Nesse caso, aconselho a mudares de lógica, como expliquei antes.

          3 – Pessoalmente prefiro XML ou base de dados, mas a escolha é tua.

          4 – Não conheço o caso específico, mas parece-me uma hipótese prática.

          1. Avatar de Nuno Peralta

            3 – Pois.. mas o XML será suficientemente viável para ser lido em TODAS as páginas, com muita gente a usar essas páginas? :S
            Mesmo a base de dados, eu não gosto muito de a usar para coisas que podem ser feitas com XML normal… prefiro usá-la só para os usernames e passwords 🙂

            Obrigadão pelas dicas!! Esclareceram-me algumas coisas que andavam a passear na minha cabeça*

          2. Avatar de Bruno Bernardino

            3 – Não deverá ter grandes problemas, mas nesse caso talvez seja preferível a base de dados.

            Tens uma outra solução melhor mas mais trabalhosa.

            Um ficheiro externo que contém defines ou arrays com o que pretendes, mas esse ficheiro a ser gerado dinamicamente (com um cron diário ou assim) para estar actual.

            De nada 🙂

    2. Avatar de Bruno Bernardino

      Não me tinha apercebido do 1 como uma pergunta…

      1 – As duas funções são sempre executadas, não percebo o que queres dizer com “completamente”, mas são executadas 🙂

      1. Avatar de Nuno Peralta

        Bem… o “completamente” é se para cada vez que as linhas dentro do while forem executadas, ele vai ler a array toda, ou se vai fazendo 1 a 1 (e aí executa as linhas para cada 1) até chegar ao final.

        1. Avatar de Bruno Bernardino

          executa um a um, pois lê um apontador e não o array todo.

          Se quiseres ler o array desde o início usando o each(), tens de usar o reset()

          1. Avatar de Nuno Peralta

            Sim, eu sei 🙂 eu uso sempre “reset()” antes do “each()”, para não haver problemas 😀

  3. Avatar de AntonioCS

    Desculpem la estragar a festa, mas onde é que isto é um tutorial?

    Sinceramente acho que seria mais apropriado por isto numa secção de “snippets”, porque basicamente o que tens aqui é uma função (suponho que tenhas sido tu a criar) e pouco mais.

    Vejo pouco atenção a explicar o código e detalhar mais os passos importantes da função.

    Se isto é um tutorial deixa muito a desejar!

  4. Avatar de Shogun
    Shogun

    Gostaria de ver o codigo comentado 🙂