Existem muitas técnicas para ler e escrever XML com PHP. Este artigo fornece três métodos para leitura de XML: usando uma biblioteca DOM, usando um analisador SAX e usando expressões regulares. Escrever XML usando modelos de texto DOM e PHP também é abordado.
Ler e escrever Extensible Markup Language (XML) em PHP pode parecer um pouco assustador. Na verdade, XML e todas as suas tecnologias relacionadas podem ser assustadoras, mas ler e escrever XML em PHP não precisa ser uma tarefa assustadora. Primeiro, você precisa aprender um pouco sobre XML – o que é e o que você pode fazer com ele. Então, você precisa aprender a ler e escrever XML em PHP, e há muitas maneiras de fazer isso.
Este artigo fornece uma breve introdução ao XML e explica como ler e escrever XML com PHP.
O que é XML?
XML é um formato de armazenamento de dados. Não define quais dados são salvos, nem define o formato dos dados. XML simplesmente define tags e os atributos dessas tags. A marcação XML bem formada é assim:
<nome>Jack Herrington</nome>
Esta tag <name> contém algum texto: Jack Herrington.
A marcação XML sem texto fica assim:
<energizar/>
Há mais de uma maneira de escrever algo em XML. Por exemplo, esta tag forma a mesma saída da tag anterior:
<powerUp></powerUp>
Você também pode adicionar atributos a tags XML. Por exemplo, esta tag <name> contém o primeiro e o último atributos:
<nome primeiro="Jack" último="Herrington" />
Caracteres especiais também podem ser codificados em XML. Por exemplo, o símbolo & pode ser codificado assim:
&
Um arquivo XML contendo tags e atributos estará bem formado se for formatado como no exemplo, o que significa que as tags são simétricas e os caracteres estão codificados corretamente. A Listagem 1 é um exemplo de XML bem formado.
Listagem 1. Exemplo de lista de livros XML
<livros>
<livro>
<autor>Jack Herrington</autor>
<title>PHP Hacks</title>
<editora>O'Reilly</editora>
</livro>
<livro>
<autor>Jack Herrington</autor>
<title>Podcasting Hacks</title>
<editora>O'Reilly</editora>
</livro>
</livros>
|
O XML na Listagem 1 contém uma lista de livros. A tag pai <books> contém um conjunto de tags <book>, cada uma contendo tags <author>, <title> e <publisher>.
Um documento XML está correto quando sua estrutura de marcação e conteúdo são verificados por um arquivo de esquema externo. Os arquivos de esquema podem ser especificados em diferentes formatos. Para este artigo, tudo o que é necessário é um XML bem formado.
Se você acha que o XML se parece muito com a linguagem de marcação de hipertexto (HTML), você está certo. XML e HTML são linguagens baseadas em marcação e têm muitas semelhanças. Entretanto, é importante ressaltar que embora um documento XML possa ser HTML bem formado, nem todos os documentos HTML são XML bem formados. A tag de nova linha (br) é um bom exemplo da diferença entre XML e HTML. Esta tag de nova linha é HTML bem formado, mas não XML bem formado:
<p>Este é um parágrafo<br>
Com uma quebra de linha</p>
Esta tag de nova linha é XML e HTML bem formados:
<p>Este é um parágrafo<br />
Com uma quebra de linha</p>
Se você deseja escrever HTML como XML bem formado, siga o padrão Extensible Hypertext Markup Language (XHTML) do comitê W3C (consulte Recursos ). Todos os navegadores modernos podem renderizar XHTML. Além disso, você pode usar ferramentas XML para ler XHTML e localizar os dados no documento, o que é muito mais fácil do que analisar HTML.
Leia XML usando a biblioteca DOM
A maneira mais fácil de ler arquivos XML bem formados é usar a biblioteca Document Object Model (DOM) compilada em algumas instalações PHP. A biblioteca DOM lê todo o documento XML na memória e o representa como uma árvore de nós, conforme mostrado na Figura 1.
Figura 1. Árvore XML DOM para livro XML
O nó books no topo da árvore possui duas tags filhas de livros. Em cada livro existem vários nós: autor, editora e título. Os nós autor, editor e título possuem nós filhos de texto que contêm texto.
O código que lê o arquivo XML do livro e exibe o conteúdo utilizando o DOM é mostrado na Listagem 2.
Listagem 2. Lendo XML de livro usando DOM
<?php
$doc = new DOMDocument();
$doc->carregar( 'livros.xml' );
$livros = $doc->getElementsByTagName( "livro");
foreach($livros as $livro)
{
$autores = $book->getElementsByTagName( "autor" );
$autor = $autores->item(0)->nodeValue;
$publishers = $book->getElementsByTagName( "publisher" );
$publisher = $publishers->item(0)->nodeValue;
$títulos = $book->getElementsByTagName( "título");
$título = $títulos->item(0)->nodeValue;
echo "$título - $autor - $editorn";
}
?>
|
O script primeiro cria um novo objeto DOMdocument e carrega o XML do livro nesse objeto usando o método load. Posteriormente, o script usa o método getElementsByName para obter uma lista de todos os elementos com o nome especificado.
No loop do nó do livro, o script usa o método getElementsByName para obter o nodeValue do autor, do editor e das tags de título. nodeValue é o texto no nó. O script então exibe esses valores.
Você pode executar scripts PHP na linha de comando assim:
%phpe1.php
Hacks de PHP - Jack Herrington - O'Reilly
Dicas para podcasting - Jack Herrington - O'Reilly
%
Como você pode ver, cada bloco de livro gera uma linha. Este é um bom começo. Mas e se você não tiver acesso à biblioteca XML DOM?
Leia XML com analisador SAX
Outra maneira de ler XML é usar um analisador XML Simple API (SAX). A maioria das instalações do PHP inclui um analisador SAX. O analisador SAX é executado em um modelo de retorno de chamada. Cada vez que uma tag é aberta ou fechada, ou cada vez que o analisador vê o texto, a função definida pelo usuário é chamada de volta com informações sobre o nó ou texto.
A vantagem do analisador SAX é que ele é realmente leve. O analisador não mantém o conteúdo na memória por longos períodos de tempo, portanto pode ser usado para arquivos muito grandes. A desvantagem é que escrever retornos de chamada do analisador SAX é muito complicado. A Listagem 3 mostra o código que usa SAX para ler um arquivo XML de livro e exibir o conteúdo.
Listagem 3. Lendo livro XML com analisador SAX
<?php
$g_livros = array();
$g_elem = nulo;
função startElement($parser, $nome, $attrs)
{
globais $g_books, $g_elem;
if ($nome == 'LIVRO') $g_books []= array();
$g_elem = $nome;
}
função endElement($parser, $nome)
{
global$g_elem;
$g_elem = nulo;
}
função textData($parser, $text)
{
globais $g_books, $g_elem;
if ($g_elem == 'AUTOR' ||
$g_elem == 'EDITOR' ||
$g_elem == 'TÍTULO' )
{
$g_books[ contagem( $g_books ) - 1][ $g_elem ] = $texto;
}
}
$parser = xml_parser_create();
xml_set_element_handler($parser, "startElement", "endElement");
xml_set_character_data_handler($parser, "textData");
$f = fopen( 'livros.xml', 'r' );
while( $dados = fread( $f, 4096 ) )
{
xml_parse($parser, $dados);
}
xml_parser_free($parser);
foreach($g_books as $book)
{
echo $livro['TÍTULO']." - ".$livro['AUTOR']." - ";
echo $livro['PUBLISHER']."n";
}
?>
|
O script primeiro configura o array g_books, que contém todos os livros e informações de livros na memória, e a variável g_elem contém o nome da tag que o script está processando atualmente. O script então define a função de retorno de chamada. Neste exemplo, as funções de retorno de chamada são startElement, endElement e textData. Ao abrir e fechar a marca, chame as funções startElement e endElement respectivamente. TextData é chamado no texto entre as tags de abertura e fechamento.
Neste exemplo, a tag startElement procura a tag book para iniciar um novo elemento na matriz book. A função textData então analisa o elemento atual para ver se é uma tag de editor, título ou autor. Nesse caso, a função coloca o texto atual no livro atual.
Para permitir que a análise continue, o script cria um analisador usando a função xml_parser_create. Em seguida, defina o identificador de retorno de chamada. Depois, o script lê o arquivo e envia partes do arquivo para o analisador. Após a leitura do arquivo, a função xml_parser_free remove o analisador. O final do script exibe o conteúdo do array g_books.
Como você pode ver, isso é muito mais difícil do que escrever a mesma funcionalidade no DOM. E se não houver biblioteca DOM e nem biblioteca SAX? Existem alternativas?
Analisar XML com expressões regulares
Tenho certeza de que alguns engenheiros irão me criticar por mencionar esse método, mas é possível analisar XML com expressões regulares. A Listagem 4 mostra um exemplo de uso da função preg_ para ler um arquivo de livro.
Listagem 4. Lendo XML com expressões regulares
<?php
$xml = "";
$f = fopen( 'livros.xml', 'r' );
while($dados = fread($f, 4096)) {$xml.=$dados};
ffechar($f);
preg_match_all( "/<livro>(.*?)</livro>/s",
$xml, $bookblocks);
foreach($bookblocks[1] como $block)
{
preg_match_all( "/<autor>(.*?)</autor>/",
$bloco, $autor);
preg_match_all( "/<título>(.*?)</título>/",
$bloco, $título);
preg_match_all( "/<editora>(.*?)</editora>/",
$bloco, $editor);
echo($título[1][0]." - ".$autor[1][0]." - ".
$editor[1][0]."n" );
}
?>
|
Observe como esse código é curto. Inicialmente, ele lê o arquivo em uma string grande. Em seguida, use uma função regex para ler cada item do livro. Por fim, use um loop foreach para percorrer cada bloco de livro e extrair o autor, o título e a editora.
Então, onde estão as falhas? O problema de usar código de expressão regular para ler XML é que ele não verifica primeiro se o XML está bem formado. Isso significa que não há como saber se o XML está bem formado antes de lê-lo. Além disso, alguns XML bem formados podem não corresponder à expressão regular e, portanto, deverão ser modificados posteriormente.
Eu nunca recomendo usar expressões regulares para ler XML, mas às vezes é a melhor maneira de compatibilidade porque as funções de expressões regulares estão sempre disponíveis. Não use expressões regulares para ler XML diretamente do usuário porque você não tem controle sobre o formato ou a estrutura desse XML. Você deve sempre usar uma biblioteca DOM ou um analisador SAX para ler XML do usuário. Escrevendo XML usando DOM
Ler XML é apenas parte da equação. Como escrever XML? A melhor maneira de escrever XML é usar o DOM. A Listagem 5 mostra como o DOM constrói o arquivo XML do livro.
Listagem 5. Escrevendo XML de livro usando DOM
<?php
$livros = array();
$livros[] = array(
'título' => 'Hacks de PHP',
'autor' => 'Jack Herrington',
'editor' => "O'Reilly"
);
$livros[] = array(
'title' => 'Hacks de Podcasting',
'autor' => 'Jack Herrington',
'editor' => "O'Reilly"
);
$doc = new DOMDocument();
$doc->formatOutput = true;
$r = $doc->createElement( "livros" );
$doc->appendChild( $r );
foreach($livros as $livro)
{
$b = $doc->createElement( "livro" );
$autor = $doc->createElement( "autor" );
$autor->appendChild(
$doc->createTextNode( $book['autor'] )
);
$b->appendChild( $autor );
$título = $doc->createElement( "título" );
$título->appendChild(
$doc->createTextNode( $book['title'] )
);
$b->appendChild($título);
$publisher = $doc->createElement( "publisher" );
$publisher->appendChild(
$doc->createTextNode( $book['publisher'] )
);
$b->appendChild( $publisher );
$r->appendChild( $b );
}
echo $doc->saveXML();
?>
|
Na parte superior do script, o array books é carregado com alguns livros de amostra. Esses dados podem vir do usuário ou do banco de dados.
Após o carregamento dos livros de amostra, o script cria um novo DOMDocument e adiciona o nó de livros raiz a ele. O script então cria nós para o autor, título e editor de cada livro e adiciona nós de texto a cada nó. A etapa final para cada nó de livro é adicioná-lo novamente aos livros do nó raiz.
No final do script, use o método saveXML para enviar o XML para o console. (Você também pode usar o método save para criar um arquivo XML.) A saída do script é mostrada na Listagem 6.
Listagem 6. Saída do script de construção do DOM
%phpe4.php
<?xml versão="1.0"?>
<livros>
<livro>
<autor>Jack Herrington</autor>
<title>PHP Hacks</title>
<editora>O'Reilly</editora>
</livro>
<livro>
<autor>Jack Herrington</autor>
<title>Podcasting Hacks</title>
<editora>O'Reilly</editora>
</livro>
</livros>
%
|
O verdadeiro valor de usar o DOM é que o XML que ele cria está sempre bem formado. Mas e se você não conseguir criar XML usando o DOM?
Escrevendo XML em PHP
Se o DOM não estiver disponível, o XML pode ser escrito usando modelos de texto do PHP. A Listagem 7 mostra como o PHP constrói o arquivo XML do livro.
Listagem 7. Escrevendo XML de livro em PHP
<?php
$livros = array();
$livros[] = array(
'título' => 'Hacks de PHP',
'autor' => 'Jack Herrington',
'editor' => "O'Reilly"
);
$livros[] = array(
'title' => 'Hacks de Podcasting',
'autor' => 'Jack Herrington',
'editor' => "O'Reilly"
);
?>
<livros>
<?php
foreach($livros as $livro)
{
?>
<livro>
<título><?php echo( $livro['título'] ?></título>);
<autor><?php echo( $livro['autor'] ?>);
</autor>
<editora><?php echo( $book['editora'] ?>);
</editora>
</livro>
<?php
}
?>
</livros>
|
A parte superior do script é semelhante a um script DOM. A parte inferior do script abre a tag books e, em seguida, percorre cada livro, criando a tag book e todas as tags internas de título, autor e editora.
O problema com esta abordagem é a codificação das entidades. Para garantir que as entidades sejam codificadas corretamente, a função htmlentities deve ser chamada em cada item, conforme mostrado na Listagem 8.
Listagem 8. Codificando entidades usando a função htmlentities
<livros>
<?php
foreach($livros as $livro)
{
$título = htmlentidades( $livro['título'], ENT_QUOTES );
$autor = htmlentities( $livro['autor'], ENT_QUOTES );
$publisher = htmlentities( $book['publisher'], ENT_QUOTES );
?>
<livro>
<título><?php echo( $título ?></título>
<autor><?php echo( $autor ?> </autor>
<editor><?php echo( $editor ?>
</editora>
</livro>
<?php
}
?>
</livros>
|
É aqui que escrever XML em PHP básico se torna irritante. Você acha que criou um XML perfeito, mas assim que tenta usar os dados, descobre que alguns elementos estão codificados incorretamente.
Conclusão
Sempre há muito exagero e confusão em torno do XML. No entanto, não é tão difícil quanto você pensa - especialmente em uma linguagem tão boa quanto o PHP. Depois de compreender e implementar o XML corretamente, você encontrará muitas ferramentas poderosas à sua disposição. XPath e XSLT são duas dessas ferramentas que vale a pena estudar.