O PHP oferece várias extensões para analisar documentos XML, mas você ainda tem que escrever um monte de códigos personalizados para validar e extrair dados da XML analisada.
Leia este artigo para aprender como usar essa classe parser XML para validar e extrair os dados de análise de documentos XML com uma quantidade mínima de código que requer apenas uma única chamada para a classe. Nessa primeira parte do artigo, vamos ver os tópicos: “XML é chato, mas ainda precisamos lidar com ela”, “Suporte a XML PHP” e “Solução da classe XML Parser para validar e extrair dados em uma única chamada”. Na segunda parte veremos a “Implementação de regras de validação personalizadas” e a “Conclusão”.
O XML é chato, mas ainda precisamos lidar com ele
Ele é um formato que foi criado na década de 1990 com o objetivo de ser usado em aplicativos que precisam trocar informações em um formato que seja legível e é independente de sistemas operacionais. O XML foi como HTML, que todo mundo conhecia, mas impõe regras de estrutura mais rígidas.
Muitos formatos de dados foram criados em torno de XML., no entanto, ele ainda é chato para se escrever manualmente. Pessoalmente, uma das coisas que eu acho mais dolorosa é ter que escrever cada nome da marca duas vezes: uma para a abertura de uma marca e outra para fechar a tag.
Alguns anos atrás houve uma tentativa de definir uma nova especificação para o eventual XML 2.0. Essa tentativa parece ter morrido. Lembro-me que propus que as tags tivessem um fechamento curto, para evitar a repetição do nome da marca. Seria assim:
<tag> dados </>
A proposta foi rejeitada. Parece que os organizadores não tinham interesse em evitar um dos pontos de dor do XML. Por causa disso, eu não ficaria surpreso se XML 2.0 estivesse realmente morto.
Hoje em dia, os desenvolvedores tendem a usar formatos mais simples, como o YAML e JSON para a troca de dados em um formato legível. Dez anos atrás, eles teriam usado o XML ao invés deles.
Apesar da mudança na mentalidade dos desenvolvedores, de vez em quando ainda temos que lidar com o XML por algum motivo. Por exemplo, há alguns anos eu precisava desenvolver um cliente e um servidor do protocolo OpenIDx. Isso é um protocolo single sign-on, ou seja, ele te permite entrar em vários sites usando a mesma conta. Ele foi usado para permitir que os usuários entrem no site JSClasses com a mesma conta que você usa no site PHPClasses.
Já o OpenID é outra história. Um projeto do protocolo que é um saco para implementar, mas vou deixar isso para um artigo futuro, depois que eu publicar as classes OpenID que desenvolvi. O que importa é que o OpenID usa o protocolo XRDS, que se destina a permitir que os clientes descubram os endereços e os recursos suportados pelos servidores que precisam de acesso. O XRDS também é baseado em XML.
Outra situação em que XML pode ser mais adequado do que outros formatos mais simples é quando você precisa representar certas entidades que não mapeiam para os tipos de dados utilizados em sua linguagem de programação. Caso contrário, provavelmente o JSON seria uma escolha melhor.
Por exemplo, quando você precisa representar modelos com marcadores especiais, você pode usar tags especiais de XML para representar os espaços reservados. Esta não é uma situação comum, mas às vezes você pode precisar lidar com isso e o XML ainda pode ser uma boa opção.
Suporte PHP para XML
Hoje em dia, o PHP possui muitas extensões para lidar com XML – chega a ser difícil descobrir qual delas usar para cada finalidade. Existem várias extensões para analisar XML, mas os aplicativos não precisam só analisar os documentos. Eles também precisam determinar se os documentos são válidos de acordo com o que é esperado, bem como extrair dados de documentos.
E quando eu digo que você precisa determinar se o documento é válido, eu não quero só descobrir se o documento está bem feito, mas também se os valores no documento são válidos de acordo com regras específicas de aplicação.
A extensão DOMDocument fornece funções para validação de documentos XML com base em um DTD ou em uma definição RelaxNG (outro formato XML). Ter que escrever um DTD ou um formato XML para validar é como lidar com mais chatisse ainda! Isso é certamente algo que os desenvolvedores (ou qualquer outra pessoa) iriam aproveitar.
Para a extração de dados de documentos XML, o Expat original de extensão parser baseado em XML tem a função xml_parse_into_structfunction, que retorna um array com os elementos do documento XML. Essa não é uma maneira muito simples para extrair dados de documentos XML.
As extensões PHP XML mais recentes podem retornar os documentos XML como objetos aninhados. Embora esta seja uma maneira mais útil para procurar dados em documentos XML, você ainda tem que escrever um monte de código personalizado para processar os documentos no formato XML que você precisa.
A extensão DOMDocument fornece suporte XPath e isso significa que você pode pesquisar e extrair valores do documento caso você possa antecipar sua localização no documento. Isso geralmente torna as coisas ainda mais complicadas do que elas são. Ela também não evita a necessidade de escrever um código personalizado para validar e extrair dados de seus documentos XML.
Solução da classe XML Parser para validar e extrair dados em uma chamada única
Este parser XML de desenvolvimento de classe começou há muito tempo atrás, ainda em 1999, apenas três dias depois da existência da extensão Expatparser, baseada em PHP XML.
O que ele faz é analisar um documento XML e construir um único array associativo que contém todos os elementos do documento. Ele não constrói uma estrutura de dados hierárquicos de elementos alinhados, como algumas abordagens fazem, porque isso torna impossível acessar qualquer elemento da página imediatamente.
Essa classe usa uma abordagem que consiste na codificação do caminho de cada elemento como uma string de números separados por vírgulas. Os números são da ordem de um elemento dentro do elemento pai. Assim, o elemento de tag raíz tem o caminho ‘0 ‘. O primeiro elemento filho da tag raiz tem o caminho ‘0, 0 ‘. O caminho do segundo elemento filho é ‘0, 1 ‘, e assim por diante.
Ao longo dos anos, eu usei esta classe para analisar vários tipos de formatos XML. Eu tinha sempre que escrever um código personalizado para atravessar este array de estrutura do documento XML, validar os dados como eu esperava que fosse no formato correto, e extrair os valores de dados.
Esta ainda é uma abordagem tediosa, mas, felizmente, eu percebi que não existia um padrão no código que escrevi em torno desta classe parser para validar e extrair dados de todos os formatos XML que tentei. Portanto, decidi criar uma solução mais genérica para fazer tudo isso em uma chamada única.
Esta solução consiste em passar um array com os meta-dados sobre a estrutura do documento XML que eu esperava. Eu o passei para uma função da classe e, se o documento for válido, a função retorna um array com todos os dados do documento extraído. Não tem jeito de ser mais simples do que isso.
Deixa eu te dar um exemplo prático. Vamos dizer que você quer analisar um arquivo XML simples, chamado person.xml, com um formato como este:
<person> <name>Some Name</name> <address>Address line 1</address> <address>Address line 2</address> <age>33</age> </person>
Para processar esse documento XML, você precisa implementar dois passos simples: análise e extração dos dados.
A análise é simples. Você só precisa chamar a função da classe chamada ParseFile. Você também pode usar a função ParseData para analisar um documento XML a partir de uma string.
$file_name = 'person.xml'; $parser = new xml_parser_class; $error = $parser->ParseFile($file_name); if(strlen($error)) die('Error while parsing the file '.$file_name.': '.$error);
A validação e extração dos dados do documento XML são feitas em uma chamada única. Você precisa passar um array que define a estrutura do XML que você espera a partir da tag raíz.
$types = array( 'person'=>array( 'type'=>'hash', 'types'=>array( 'name'=>array( 'type'=>'text' ), 'address'=>array( 'type'=>'text', 'maximum'=>'*' ), 'age'=>array( 'type'=>'integer', 'minimumvalue'=>'18' ) ) ) );
Vou explicar isso mais detalhadamente:
$types = array( 'person'=>array(
Você vai querer retornar tags com elementos child como arrays associativas, por isso é necessário definir o “type” de parâmetro para a tag raíz para ‘hash’.
'type'=>'hash',
O parâmetro “types” deve ser especificado para definir os tipos de tags de elemento child.
'types'=>array(
Para cada tag de elemento child, é necessário que haja uma entrada que define o tipo de elemento, bem como outros parâmetros de tipos específicos. Vários tipos básicos built-in são suportados: ïnteger”, “text”, “darte” e “decimal”. Os tipos de ‘hash’ e ‘array’ representam formas alternativas para retornar tagschildtag pai.
Um tipo especial chamado ‘hash’ pode ser utilizado para retornar o caminho do elemento, em vez de o seu valor.
'name'=>array( 'type'=>'text' ),
Um elemento tagchild aparece várias vezes dentro de sua tag pai. Os parâmetros “mínimum” e “maximum” falam para a classe quantas vezes a tag pode aparecer. O padrão mínimo e tempos máximos é 1. Um mínimo de 0 significa que a tag é opcional. Um máximo de ‘*’ significa que não há máximo.
'address'=>array( 'type'=>'text', 'maximum'=>'*' ),
Cada tipo pode ter parâmetros específicos. No caso da tag “age”, eu posso exigir que o valor mínimo seja 18.
'age'=>array( 'type'=>'integer', 'minimumvalue'=>'18' ) ) ) );
Agora você só precisa chamar a função ExtractElementData para validar e extrair os dados analisados de uma só vez.
$start_element_path = ''; // start from the root element $type_of_document = 'person'; // used just in error messages $hash = true; // return the results in an associative array $error = $parser->ExtractElementData( $start_element_path, $type_of_document, $types, $hash, $person); if(strlen($error)) { die('Error while extracting parsed data from the file '. $file_name.': '.$error); } var_dump($person); Este script dá saída a algo assim: array(1) { ["person"]=> array(3) { ["name"]=> string(9) "Some Name" ["address"]=> array(2) { [0]=> string(9) "Address line 1" [1]=> string(9) "Address line 2" } ["age"]=> int(33) } }
Como você pode ver, é muito fácil definir a estrutura XML que você deseja analisar e extrair dados do documento. Você pode definir estruturas mais complexas dando suporte à configuração de tags alinhadas do parâmetro “type” para “hash” e definir parâmetros de tagschild usando o parâmetro “tipos” na definição da tag que possui tagschild.
Agora, até a segunda parte do nosso artigo!
***
Artigo original disponível em: http://www.phpclasses.org/blog/package/4/post/1-Processing-XML-with-a-single-PHP-call.html