Dev (Back & Front)ARTIGO

Simule a funcionalidade XQuery e XInclude com PHP

Muitos navegadores podem lidar com XML em geral, mas não são,
atualmente, muito bons no suporte a XQuery e XInclude. É preciso uma
solução alternativa para esse problema para construir aplicativos da Web
que combinem e processem dados estruturados em XML de múltiplas
origens. Usar PHP é uma solução.

Este artigo mostrará, primeiramente,
como as páginas da Web podem fornecer extração de dados de XML usando
explicitamente XQuery e XInclude, e depois como realizar um trabalho
semelhante com PHP. Tudo dentro do contexto de um esforço cooperativo
entre centros de jardinagem.

O poder do processamento de dados XML em programação da Web

XInclude e XQuery são ferramentas de XML que ajudam os programadores da
Web a processarem dados dinamicamente. XInclude permite que você lide
com múltiplos arquivos XML como se eles fossem um único arquivo e XQuery
pode processar os dados combinados e prepará-los para inclusão na saída
para exibição de página da Web. Juntas, elas realizam esse serviço de
forma elegante e eficiente com algumas poucas linhas de código.

A maioria dos navegadores pode exibir e processar arquivos XML tanto
diretamente quanto em cooperação com modelos XSL. Em um mundo ideal, os
navegadores entenderiam XQuery e XInclude também de maneira direta. Mas,
nesse momento, eles suportam essas ferramentas somente estabelecendo
demandas irracionais para os usuários como, por exemplo, exigindo que
eles carreguem add-ons experimentais.

Buscar dados de origens
completamente diferentes e combiná-los em um amplo conjunto de dados
para processamento pode ser uma tarefa meticulosa para o programador da
Web.

Através de um exemplo de negócios hipotético, este artigo mostrará
primeiramente a força da
combinação de XQuery e XInclude. Depois você aprenderá como usar PHP
para simular a funcionalidade que a XQuery e a XInclude fornecem.

Mover
todo o processamento de dados para o lado do servidor oferece uma
solução alternativa para suporte limitado de navegador para XQuery e
XInclude. Outro benefício é que o PHP oferece um controle muito maior
sobre a apresentação final da saída.

Acrônimos usados frequentemente

  • HTTP: Protocolo de transporte de Hipertexto
  • W3C: World Wide Web Consortium
  • XHTML: Linguagem de marcação de hipertexto extensível
  • XML: Linguagem de marcação extensível
  • XSL: Extensible Stylesheet Language

Exemplo: cooperação de centro de jardinagem

Imagine que uma cidade possua três centros de jardinagem. Eles
competem uns com os outros, mas fornecem serviços suficientemente
diferentes que podem ser realizados de forma cooperativa ao invés de
antagonicamente. Eles realizam um pouco de pesquisa de mercado para
descobrir como seus clientes compram suas plantas.

Nos negócios de horticultura, as vendas de produtos altamente
perecíveis acontecem em grande volume em um curto período de tempo, e os
clientes podem ser bastante detalhistas em relação ao tipo e qualidade
dos produtos que desejam.

É de grande interesse para os negócios ter
saída de produtos de alta manutenção (por exemplo, aqueles que precisam
ser aguados e livres de pestes) o mais rápido possível e manter uma base
de clientes variável, fornecendo a eles os produtos certos na hora
certa e no lugar certo. Do contrário, os clientes migram para o
concorrente que faz isso.

Pesquisas mostram que os clientes não gostam de ficar ligando para
descobrir onde podem conseguir
suas plantas, e o alto volume de chamadas é também inconveniente
para os negócios.

No início da estação, todos os negócios possuem muitos produtos. Já
mais no final
da estação, apesar de um bom planejamento, os produtos começam a
faltar de forma irregular.

Os clientes
em busca de petúnias podem ter que ligar ou visitar todos os três
centros de jardinagem antes de
encontrarem a cor rosa escuro que estão procurando. Em geral, os
clientes querem saber quem possui qual planta, em qual tamanho de vaso,
em qual quantidade e a que preço.

A configuração proposta

Os três gerentes de TI realizam uma reunião. Eles decidem criar um
Web site em comum, no qual os clientes possam descobrir qual centro de
jardinagem possui plantas específicas em estoque.

Embora os três centros de jardinagem sejam computadorizados, cada um
usa um sistema diferente para armazenar informações. O Apples and Things
usa um sistema de banco de dados Microsoft Access, o Birch Trees
Unlimited usa um sistema Linux com MySQL e o Carnation Tarnation usa
Mac OS X com IBM DB2. De modo geral, eles decidem trabalhar em busca de uma arquitetura
baseada em XML.

O XML é um formato de dados conveniente porque cada um
dos sistemas pode exportar dados atualizados para um arquivo XML que
fica disponível em nuvem. Um arquivo XML principal coleta os dados
individuais das lojas em um lugar central, usando XInclude. Finalmente, a
página principal da Web examina o arquivo principal, extrai os dados
usando XQuery e renderiza a exibição final.

Processamento de XML com XInclude e XQuery

Os gerentes de TI decidem que cada loja produzirá um arquivo XML semelhante ao da listagem 1:

Listagem 1. Arquivo XML da loja

<store><br />  <info><br />    <name>...</name><br />    <address>... </address><br />    <phone>... </phone><br />  </info><br />  <plants><br />    <plant><br />      <name>Petunia</name><br />      <description>Pink, in 4 inch pots</description><br />      <quantity>100</quantity><br />      <price>3.00</price><br />    </plant><br />    <plant><br />      <name>Apple tree 'Spartan'</name><br />      <description></description><br />      <quantity>6</quantity><br />      <price>25.00</price><br />    </plant><br />    ...<br />  </plants><br /></store>

Esse arquivo possui um elemento raiz store e dois elementos filhos. O elemento filho info contém informações sobre a loja em geral. O elemento filho plants contém muitos elementos filhos plant, cada qual contendo mais informações sobre a planta, incluindo nome, descrição, quantidade e preço. Todas as três lojas seguem exatamente esse padrão.

A listagem 2 é a versão de um arquivo XML principal que combina arquivos das três lojas, de modo que eles parecem ser um único arquivo grande, mantendo detalhes sobre os produtos:

Listagem 2. Arquivo XML principal

<?xml version="1.0"><br /><storeData xmlns:xi="http://www.w3.org/2001/XInclude"><br />  <xi:include href="http://path-to-apples.xml"/><br />  <xi:include href="http://path-to-birches.xml"/><br />  <xi:include href="http://path-to-carnations.xml"/><br /></storeData>

Na listagem 2, XInclude é usado para buscar dados de três locais usando HTTP em nuvem. Depois do processamento, ela é semelhante à listagem 3:

Listagem 3. Arquivo XML principal expandido

<?xml version="1.0"><br /><storeData ..."><br />  <store><br />    <info><br />      <name>Apples</name><br />      ...<br />    </info><br />    <plants><br />      ...<br />    </plants><br />  </store><br />  <store><br />    <info><br />      <name>Birches</name><br />      ...<br />    </info><br />    <plants><br />      ...<br />    </plants><br />  </store><br />  ...<br /></storeData>

Na listagem 3, as instruções incluídas da listagem 2 são substituídas pelo conteúdo dos arquivos XML individuais da loja. Cada elemento store é agora um elemento filho do elemento global storeData.

Agora é possível aplicar XQuery ao conjunto de dados combinado, como na listagem 4:

Listagem 4. Aplicação de XQuery

<div>{<br />  for $store in doc("mainXMLfile.xml")/storeData/store<br />  let $plants := $store/plants/plant<br />  return<br />      <div>{<br />        for $plant in $plants<br />            order by $plant/name<br />        return <div>{ concat($plant/quantity," of ",$plant/name," at ",<br />            $store/info/name," for ",$plant/price," each") }</div><br />        }</div><br />}</div>

A listagem 4 requer saída de XHTML com seções div . Iterando através das lojas, ela relata a quantidade, nome, nome da loja e preço de cada planta. A saída é semelhante à listagem 5:

Listagem 5. XHTML gerado

<div><br />    <div><br />        <div>6 of Apple tree 'Spartan' at apples for 25.00 each</div><br />        <div>100 of Petunia at apples for 3.00 each</div><br />    </div><br />    <div><br />        <div>100 of Coleus at birches for 3.00 each</div><br />        <div>6 of Pear tree 'Flemish Beauty' at birches for 25.00 each</div><br />    </div><br />    <div><br />        <div>6 of Orchids at carnation tarnation for 25.00 each</div><br />        <div>100 of Roses at carnation tarnation for 3.00 each</div><br />    </div><br /></div>

É possível verificar essa saída usando qualquer um de uma série de clientes XQuery. Por exemplo, é possível usar o aplicativo de software livre baseado em Java eXist para verificar a saída de vários comandos de XQuery incluindo a consulta da listagem 4 em um banco de dados de teste.

Também é possível usar Zorba, um aplicativo de XQuery independente, para fazer a mesma coisa. Consulte Recursos para obter mais informações sobre esses clientes XQuery. As abordagens de JavaScript também estão disponíveis.

Uma abordagem alternativa para usar XInclude e XQuery em combinação é realizar todas as etapas no lado do servidor. É possível fazer isso com PHP usando as funções fornecidas pela extensão SimpleXML do PHP. O SimpleXML fornece os dados formatados e filtrados diretamente para o navegador em XHTML, reduzindo, portanto, a carga no leitor geral.

Inclusão com PHP

Primeiro pegue a etapa de inclusão que você pode executar com uma simples substituição de cadeia de caractere:

  1. Comece com uma estrutura XML básica vazia.
  2. Insira uma cadeia de caractere para cada uma das lojas.
  3. Busque os arquivos das lojas.
  4. Substitua os nomes das lojas pelos arquivos.

O resultado é um arquivo grande para todas as lojas. Outras maneiras de compilar o arquivo, como usar a função addChild(…) de SimpleXML, também estão disponíveis. No entanto, neste caso, a substituição de cadeia de caractere é mais simples e oferece a validação necessária. A listagem 6 mostra a técnica de substituição de cadeia de caractere:

Listagem 6. Incluir por substituição de cadeia de caractere

<?php<br />// string substitution approach<br />$arr = array("apples","birches","carnations");<br />$myxml = "<?xml version=\"1.0\"?><br /><storeData>";<br />foreach ($arr as $a) { $myxml .= "$a\n"; }<br />$myxml .= "</storeData>";<br />// now process includes<br />foreach ($arr as $a) {<br />  if (!$f = file_get_contents($a.".xml")) {<br />    xml_fallback($a);<br />  } else {<br />    if (!simplexml_load_string($f)) {<br />      xml_fallback($a);<br />    } else {<br />      xml_include($a,$f);<br />    }<br />  }<br />}<br />if (!$xml = simplexml_load_string($myxml)) {<br />  echo "Combined file failed!\n";<br />} else {<br />  echo $xml->asXML;<br />}<br />//<br />// functions<br />//<br />function xml_include($a,$rep) {<br />global $myxml;<br />  $myxml = str_replace($a,$rep,$myxml);<br />}<br />function xml_fallback($a) {<br />global $myxml;<br />  $rep = "<store><info><br />    <name>$a</name><br />  </info></store>";<br />  $myxml = str_replace($a,$rep,$myxml);<br />}<br />?>

A listagem 6 começa declarando uma array que contém os nomes abreviados das lojas e compila esses nomes em um arquivo XML básico. Ela realiza então loops através dos arquivos XML para cada loja, buscando-os como texto simples.

O arquivo pode não estar lá, e, neste caso, será necessário realizar uma ação especial. Se o arquivo estiver lá, teste-o para ver se sozinho ele é um XML válido. Se não for válido, realize uma ação como se o arquivo estivesse perdido, usando a funcionalidade Fallback semelhante de XInclude.

Neste caso, a função xml_fallback() substitui um fragmento XML para manter o arquivo bem formado. Se o arquivo for válido, ele é substituído no arquivo principal por xml_include().

Finalmente, o arquivo XML totalmente montado é testado em relação à sua boa formação. Neste exemplo, como você está testando somente a funcionalidade de inclusão, ao obter sucesso, o processo para e dá saída ao XML para verificação visual. Agora o XML está pronto para processamento de consulta.

Consulta com PHP

Agora é possível processar o XML no código do PHP tanto com um aplicativo de XQuery, como o Zorba, ou usando SimpleXML.

Consulta usando Zorba

Um método interessante de testar o Zorba para PHP é como uma extensão PHP Extension Community Library . (Para obter uma explicação desse método, consulte a seção Recursos ao final do artigo para obter um link para o artigo, “Building XQuery-powered applications with PHP and Zorba”.) Também é possível chamar o Zorba a partir do PHP sem usar uma extensão, usando exec(), como demonstrado no fragmento PHP na listagem 7:

Listagem 7. PHP e Zorba sem usar uma extensão

<?php<br />...<br />function run_zorba($myxquery) {<br />  ...<br />  exec("zorba -i -q '$myxquery'",$array);<br />  ...<br />  $xmlstr = implode("\n",$array);<br />  $xml = simplexml_load_string($xmlstr);<br />  echo $xml->asXML();<br />}<br />?>

Na listagem 7, a função se abre conhecendo a solicitação de XQuery no argumento de cadeia de caractere $myxquery. Ela então usa a função exec() para executar o Zorba. É possível dividi-la em uma bifurcação de processo por segurança.

A função exec() preenche a array $array com a saída do Zorba. As opções -q e -i pedem que uma consulta seja executada e que a saída seja indentada, respectivamente. Esta última opção é particularmente útil na depuração, pois ela torna o código do XML mais legível. Os conteúdos da array são então implodidos em uma longa cadeia de caractere, que é, por sua vez, carregada em um objeto XML e (neste caso de teste) ecoada.

Consulta usando SimpleXML

Embora usar um agente de XQuery como o Zorba seja conveniente, também é possível obter os dados diretamente com SimpleXML, da maneira descrita a seguir.

Nesse ponto, presuma que você tenha a variável $xml da listagem 6 carregada em um objeto XML que está pronto para processamento. A listagem 8 mostra a consulta final dos dados XML:

Listagem 8. Processamento de consulta com SimpleXML

<?php<br />// Query with PHP<br />include 'mainstore2.php';<br />if (!$xml = simplexml_load_string($myxml)) {<br />  die("Cannot read output from XInclude step\n");<br />}<br />// begin output<br />$myout = "\n\n<html><head></head><body>\n";<br />$myout .= "<div>\n";<br />foreach ($xml->store as $store) {<br />  foreach ($store->plants->plant as $plant) {<br />    $myout .= $plant->quantity." of "<br />        .$plant->name." at "<br />        .$store->info->name." for "<br />        .$plant->price<br />        ."\n";<br />  } <br />}<br />$myout .= "</div>\n";<br />$myout .= "</body></html>\n";<br />echo $myout;<br />?>

A listagem 8 começa carregando o equivalente da listagem 6 e verificando mais uma vez se o XML está bem formado. Ela então realiza loops pelas lojas, depois pelas plantas disponíveis em cada loja, e finalmente gera a saída mostrada na listagem 9.

Essa saída é comparável à saída mostrada na listagem 5, da abordagem de XQuery mostrada anteriormente. É possível incluir marcação de XHTML, se necessário.

Listagem 9. Saída para o navegador

<html><head></head><body><br /><div><br />100 of Petunia at apples for 3.00<br />6 of Apple tree 'Spartan' at apples for 25.00<br />100 of Coleus at birches for 3.00<br />6 of Pear tree 'Flemish Beauty' at birches for 25.00<br />100 of Roses at carnation tarnation for 3.00<br />6 of Orchids at carnation tarnation for 25.00<br /></div><br /></body></html> 

É possível estender esse tipo de programação para oferecer aos clientes
do centro de jardinagem a capacidade de filtrar e classificar, com base
em parâmetro de consulta como faixas de preço e nomes, conforme
necessário.

Conclusão

A preocupação do programador é comparar a codificação do PHP usando as bibliotecas
de SimpleXML prontamente disponíveis (por um lado) com PHP e ferramentas
intermediárias fornecidas por bibliotecas especiais de XInclude e XQuery (por outro).

Uma
biblioteca de ferramentas especiais só é valiosa se facilitar a carga
do programador, reduzindo e esclarecendo o código necessário para realizar o trabalho. Neste caso de inclusões, a inserção de dados de outros arquivos é especialmente
direta e não requer muita codificação usando qualquer método.

No caso de consultas, as bibliotecas de XQuery podem substituir vários códigos
que seriam necessários (“para” loops, e assim por diante) com o método PHP+SimpleXML.

No entanto, quanto mais condensado for o código para recuperação de dados, menor a
oportunidade de usar PHP para seus outros recursos. Para dar um exemplo, é possível
reduzir sua consulta a uma linha em XQuery, substituindo 20 linhas de
PHP+SimpleXML.

O custo de oportunidade é que você renunciou a chance de
inserir de forma fácil e clara outras instruções dentre as 20 instruções
separadas. Essa é a troca.

Recursos

Aprender

Obter produtos e tecnologias

  • Zorba: faça o download do Zorba e saiba mais sobre ele.
  • eXist-db: Explore o banco de dados de XML nativo de software livre eXist-db.
  • XQIB – XQuery in the Browser: Faça o download do XQIB, que permite executar código de XQuery em HTML.

Discutir

***

artigo publicado originalmente no developerWorks Brasil, por Colin Beckingham

Colin Beckingham é um pesquisador, escritor e programadorfreelancer que
mora no leste de Ontário, Canadá. Com diplomas da Queen’s University,
Kingston e autor de aplicativos de banco de dados e de
diversos artigos para jornais, revistas e on-line, seus interesse de
pesquisa incluem programação de software livre e aplicativos de controle
de voz em Linux.

é o portal de tecnologia da IBM para profissionais de TI de todo o mundo. Colabore, aprenda a criar aplicativos inovadores e compreenda tecnologias avançadas. Acesse mais artigos e tutoriais em www.ibm.com/developerworks/br

Ver perfil