GWT permite fácil acesso aos servlets do lado do servidor programados na linguagem Java e os dados são passados de forma transparente, nos bastidores, entre cliente e servidor. No entanto, à medida que trabalha com GWT, não está limitado a se comunicar com esses servlets e você pode trocar dados livremente com todos os tipos de serviços da Web. Em muitos casos (para serviços simples), essas transferências podem ser feitas com texto simples, mas sempre que os dados forem estruturados ou simplesmente mais complicados (pense em RSS, por exemplo), as chances são que XML os representará.
Este artigo examina um aplicativo GWT simples e dois serviços da Web PHP, mostrando diversas maneiras diferentes de produzir e consumir documentos XML. Este artigo não tem a intenção de ser um tutorial ou um manual completo, mas ser, na verdade, um conjunto de ponteiros para que você possa começar mais rapidamente a trabalhar com XML como uma ponte entre GWT e PHP por conta própria.
Para mostrar como é possível usar XML como uma ponte entre PHP e GWT, forneço um aplicativo simples baseado em dados de países/regiões/cidades. Verificando o código e criação do banco de dados na Lista 1, é possível ver que:
- Países têm um código exclusivo (por exemplo, UY para Uruguai) e um nome.
- Países são divididos em regiões, identificadas com um código (exclusivo dentro do país) e têm um nome.
- Regiões têm cidades, que têm um nome (ASCII puro), um nome acentuado (que pode conter caracteres estrangeiros), uma população (ou 0 se desconhecida), uma latitude e uma longitude. O nome da cidade pode aparecer em diferentes regiões do mesmo país.
Listing 1. Database creation code
CREATE DATABASE world
DEFAULT CHARACTER SET latin1
COLLATE latin1_general_ci;
USE world;
CREATE TABLE countries (
countryCode char(2) NOT NULL,
countryName varchar(50) NOT NULL,
PRIMARY KEY (countryCode)
KEY countryName (countryName)
);
CREATE TABLE regions (
countryCode char(2) NOT NULL,
regionCode char(2) NOT NULL,
regionName varchar(50) NOT NULL,
PRIMARY KEY (countryCode,regionCode),
KEY regionName (regionName)
);
CREATE TABLE cities (
countryCode char(2) NOT NULL,
cityName varchar(50) NOT NULL,
cityAccentedName varchar(50) NOT NULL,
regionCode char(2) NOT NULL,
population bigint(20) NOT NULL,
latitude float(10,7) NOT NULL,
longitude float(10,7) NOT NULL,
KEY `INDEX` (countryCode,regionCode,cityName),
KEY cityName (cityName),
KEY cityAccentedName (cityAccentedName)
);
|
Criei um projeto GWT simples com apenas um formulário e dois serviços da Web PHP. (Consulte Downloads para obter o código de origem integral.) Ao iniciar o aplicativo, verá a janela simples da Figura 1.
Figura 1. O Formulário Vazio
O formulário GWT permite inserir uma parte de um nome de cidade e chama um serviço PHP para obter todas as cidades que correspondem a o que foi digitado. As cidades são exibidas em uma grade e é possível editar os campos de população, latitude e longitude. Os dados editados podem ser enviados de volta a um segundo serviço da Web PHP, que atualiza o banco de dados. Todas as transferências de dados são feitas em XML. Como 2009 marca 200 anos do nascimento de Charles Darwin e 150 anos de seu livro A Origem das Espécies , poderia procurar cidades com DARWIN em seus nomes; consulte a Figura 2 para obter os resultados.
Figura 2. Uma Procura por Cidades que Incluem "Darwin" em seus Nomes
Apenas para referência, trabalhei com:
- GWT versão 1.5.3
- PHP versão 5.2.8
- Servidor de banco de dados MySQL® versão 5.0.67
- Apache versão 2.2.10 sob OpenSUSE® versão 11.1
Instalei todo o software com instalação padrão, mas GWT precisava de uma etapa extra de configuração para que eu pudesse testar a conexão GWT-PHP; verifique a barra lateral O Problema SOP para ver a razão. Para desativar verificações same-origin policy (SOP) no navegador interno do GWT, edite o arquivo ./mozilla-1.7.12/greprefs/all.js em seu diretório do GWT e inclua as linhas da Lista 2 no final desse arquivo:
Listing 2. Configuration changes for the internal GWT browser
pref("capability.policy.default.XMLHttpRequest.abort", "allAccess");
pref("capability.policy.default.XMLHttpRequest.getAllResponseHeaders","allAccess");
pref("capability.policy.default.XMLHttpRequest.getResponseHeader","allAccess");
pref("capability.policy.default.XMLHttpRequest.open", "allAccess");
pref("capability.policy.default.XMLHttpRequest.send", "allAccess");
pref("capability.policy.default.XMLHttpRequest.setRequestHeader","allAccess");
pref("capability.policy.default.XMLHttpRequest.onreadystatechange","allAccess");
pref("capability.policy.default.XMLHttpRequest.readyState", "allAccess");
pref("capability.policy.default.XMLHttpRequest.responseText","allAccess");
pref("capability.policy.default.XMLHttpRequest.responseXML","allAccess");
pref("capability.policy.default.XMLHttpRequest.status", "allAccess");
pref("capability.policy.default.XMLHttpRequest.statusText", "allAccess");
|
Sempre que atualizar GWT, será necessário fazer essa mudança novamente. Além disso, observe que, sem fazer isso, pode ser que seja gravado código que falha no modo Hospedado, mas é executado corretamente no modo Compilado; após a mudança, pode haver código executado no modo Hospedado, mas que falha no modo Compilado, fique ligado!
Esse aplicativo simplesmente define um formulário simples, com alguns rótulos, uma caixa de texto, dois botões de comando e uma grade para os resultados. Sempre que clicar em Obter Cidades, o aplicativo chama um serviço PHP para obter um documento XML com todas as cidades que correspondem ao que foi digitado na caixa de texto. A Lista 3 mostra um XML de amostra (um tanto quanto abreviado) que é enviado p serviço PHP para o aplicativo GWT. O código XML produzido deve ilustrar diversos recursos XML e é, portanto, muito mais longo do que seria para um aplicativo real. Geralmente, um serviço XML bem projetado usa menos tags e mais atributos, evita deslocamento e é um documento mais curto.
Listing 3. The XML document produced when searching for "tokyo"
<?xml version="1.0" encoding="UTF-8"?>
<cities>
<city name="tokyo">
<country code="JP" name="Japan"/>
<region code="40" name="Tokyo"/>
<coords>
<lat>35.6850014</lat>
<lon>139.7513885</lon>
</coords>
<pop>31480498</pop>
</city>
<city name="tokyo">
<country code="PG" name="Papua New Guinea"/>
<region code="01" name="Central"/>
<coords>
<lat>-8.3999996</lat>
<lon>147.1499939</lon>
</coords>
</city>
<city name="tokyojitori">
<country code="KR" name="Korea, Republic of"/>
<region code="16" name="Cholla-namdo"/>
<coords>
<lat>34.2380562</lat>
<lon>125.9394455</lon>
</coords>
</city>
</cities>
|
Há duas versões do próprio serviço PHP —getcities1.php e getcities2.php—cada um dos quais mostra diferentes maneiras de produzir XML.
De longe, a maneira mais simples de produzir XML é simplesmente imprimir o texto apropriado de forma sequencial ou construir uma cadeia de caracteres, em seguida, emiti-lo usando
echo.
O tipo de conteúdo deve ser configurado para
text/xml de forma que seja reconhecido corretamente. Lembre-se também de incluir uma linha de descrição apropriada que especifica a versão XML e a codificação de dados.
Será necessário escapar cadeias de caracteres de forma que não incluam caracteres menor que (<), maior que (>) ou e comercial (&); a maneira mais fácil é usar a função PHP
htmlspecialchars() . A codificação é fácil, como a parte da
Lista 4 mostra. Observe que deslocamento e quebras de linhas não são realmente necessários, apesar de facilitarem a leitura do código.
Listing 4. The simplest method to produce XML from a PHP service
...
header("Content-type: text/xml");
...
echo '<?xml version="1.0" encoding="UTF-8"?>'."\n";
echo '<cities>'."\n";
...
while ($row= mysql_fetch_assoc($result)) {
echo ' <city name="'.htmlspecialchars($row['cityName']).'">'."\n";
echo ' <country code="'.$row['countryCode'].'" ';
echo 'name="'.htmlentities($row['countryName']).'"/>'."\n";
echo ' <region code="'.$row['regionCode'].'" ';
echo 'name="'.htmlentities($row['regionName']).'"/>'."\n";
echo ' <coords>'."\n";
echo ' <lat>'.$row['latitude'].'</lat>'."\n";
echo ' <lon>'.$row['longitude'].'</lon>'."\n";
echo ' </coords>'."\n";
if ($row['population']>0) {
echo ' <pop>'.$row['population'].'</pop>'."\n";
}
echo ' </city>'."\n";
}
echo '</cities>'."\n";
|
Um segundo método (e não muito mais longo) para produzir código XML é usando
XMLWriter. (Uma classe companheira,
XMLReader, permite processamento de XML.) Pode esquecer sobre escapar caracteres, pois isso é feito automaticamente.
Apesar de parecer conter mais palavras do que o método
echo() acima, pode ser argumentado que essa abordagem cria um código mais compreensível.
Observe especialmente o uso do protocolo
php://output para que o texto seja emitido como com o comando
echo . (Consulte a
Lista 5.)
Listing 5. XMLWriter provides simple methods to build up an XML document one element at a time
...
$writer= new XMLWriter();
$writer->openURI('php://output')
$writer->startDocument('1.0', 'UTF-8');
$writer->startElement("cities");
while ($row= mysql_fetch_assoc($result)) {
$writer->startElement("city");
$writer->writeAttribute("name", $row['cityName']);
$writer->startElement("country");
$writer->writeAttribute("code", $row['countryCode']);
$writer->writeAttribute("name", $row['countryName']);
$writer->endElement();
$writer->startElement("region");
$writer->writeAttribute("code", $row['regionCode']);
$writer->writeAttribute("name", $row['regionName']);
$writer->endElement();
$writer->startElement("coords");
$writer->writeElement("lat", $row['latitude']);
$writer->writeElement("lon", $row['longitude']);
$writer->endElement();
if ($row['population']>0) {
$writer->writeElement("pop", $row['population']);
}
$writer->endElement(); // city
}
$writer->endElement(); // cities
...
|
Se quiser fazer experiências com mais métodos de produção de XML, PHP certamente tem muito a oferecer. Por exemplo, é possível usar SimpleXML; ser;a usado posteriormente para ler XML, mas também pode ser usado para criação de documento XML. Além disso, você também pode dar uma olhada na estrutura PEAR, que inclui diversas classes para fácil geração de XML. (Consulte Recursos para obter links para informações adicionais.)
GWT fornece somente XMLParser (no pacote com.google.gwt.xml.client
) para leitura e gravação e XML. Use o método parse()
para criar um Document, em seguida, use
getDocumentElement() para obter seu elemento raiz; em seguida, estará pronto para começar a percorrer o XML.
Um ponto importante é que o método removeWhitespace()
deve ser usado para remover espaço em branco de seu documento. Analisadores de navegador às vezes criam nós de texto vazios correspondentes a guias ou quebras de linha e, caso não sejam removidos, sei processo encontrará elementos irrelevantes inesperados, que podem afetar sua lógica (consulte
Lista 6). Outro ponto: Se esperar seções CDATA, seria necessário verificar se seu navegador aceita o método
supportsCDATASection() ; do contrário, essas seções produzirão nós de texto, em vez disso.
Verifique a documentação de GWT (consulte
Recursos) para saber mais sobre isso.
Listing 6. XMLParser provides for both XML reading and creation in GWT
protected void loadCities(final String xmlCities) {
...
final Document xmlDoc= XMLParser.parse(xmlCities);
final Element root= xmlDoc.getDocumentElement();
XMLParser.removeWhitespace(xmlDoc);
final NodeList cities= root.getElementsByTagName("city");
for (int i= 0; i < cities.getLength(); i++) {
final Element city= (Element)cities.item(i);
// show city.getAttributeNode("name").getValue()
final Element country= (Element)city.getElementsByTagName("country").item(0);
// show country.getAttributeNode("code").getValue()
// show country.getAttributeNode("name").getValue()
...
final Element population= (Element)city.getElementsByTagName("pop").item(0);
if (population != null) {
// show population.getFirstChild().getNodeValue()
}
final Element coords= (Element)city.getElementsByTagName("coords").item(0);
final Element lat= (Element)coords.getElementsByTagName("lat").item(0);
// show lat.getFirstChild().getNodeValue()
...
}
...
|
É possível obter elementos repetidos (como city neste exemplo) usando o método
getElementsByTagName() e percorrendo a array resultante.
Uma alternativa é usar o método
getFirstChild() , em seguida, percorrer os demais elementos no mesmo nível com
getNextSibling().
Obter atributos requer, primeiramente, o método getAttributeNode() , em seguida, o método
getValue() . Há métodos que processam seções CDATA, comentários e todos os componentes XML possíveis.
O aplicativo GWT permite que os usuários editem os campos de população, latitude e longitude,em seguida, enviem os dados das cidades de volta ao servidor para atualizar o banco de dados. Dois algoritmos são mostrados: um simples, construindo a cadeia de caracteres XML por partes e um algoritmo baseado em XMLParser que usa métodos específicos para criar a estrutura desejada.
O algoritmo mais simples é mostrado no método getCities1() .
Um objeto String ou
StringBuffer pode ser usado para construir o XML. Usei o primeiro, pois torna o código mais claro; mas, em termos de desempenho, a segunda opção é provavelmente melhor.
Os mesmos problemas de escape de caractere visto na versão PHP estão aqui, portanto, use o método
Html.htmlspecialchars()
para corrigir isso. (Consulte
Lista 7, que foi ligeiramente modificada por questão de clareza.)
Listing 7. Building XML piece by piece is simple using strings
protected String getCities1() {
String result= "";
result+= "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
result+= "<cities>\n";
for (all rows in the grid) {
// get cityName, countryCode, regionCode, pop, lat, and lon, from the grid
result+= " <city name=\"" + Html.htmlspecialchars(cityName) + "\">\n";
result+= " <country code=\"" + countryCode + "\"/>\n";
result+= " <region code=\"" + regionCode + "\"/>\n";
if (!pop.equals("0") && !pop.isEmpty()) {
result+= " <pop>" + pop + "</pop>\n";
}
result+= " <coords>\n";
result+= " <lat>" + lat + "</lat>\n";
result+= " <lon>" + lon + "</lon>\n";
result+= " </coords>\n";
result+= "</city>\n";
}
result+= "</cities>\n";
return result;
}
|
O outro algoritmo simples para criação de XML é o método createDocument()
da classe XMLParser . Em um estilo fortemente remanescente das funções SimpleXML em PHP, primeiro, cria-se um documento vazio, em seguida, inclui-se elementos nele.
É possível criar todos os tipos de nós, assim como configurar valores de atributos.
Por fim, o método toString() Java padrão produz uma representação do objeto; é necessário incluir apenas a linha de versão e codificação inicial e terá sua cadeia de caracteres necessária.
(Consulte Lista 8, que foi modificada e resumida por questão de clareza.)
Listing 8. The XMLParser methods for XML creation are similar to SimpleXML's methods in PHP
protected String getCities2() {
Document xml= XMLParser.createDocument();
Element cities= xml.createElement("cities");
xml.appendChild(cities);
for (all rows in the grid) {
// get cityName, countryCode, regionCode, pop, lat, and lon, from the grid
Element city= xml.createElement("city");
city.setAttribute("name", cityName);
Element country= xml.createElement("country");
country.setAttribute("code", countryCode);
city.appendChild(country);
...
if (!pop.equals("0") && !pop.isEmpty()) {
Element popEl= xml.createElement("pop");
Text popText= xml.createTextNode(pop);
popEl.appendChild(popText);
city.appendChild(popEl);
}
Element coords= xml.createElement("coords");
Element lat= xml.createElement("lat");
Text latText= xml.createTextNode(lat);
lat.appendChild(latText);
coords.appendChild(lat);
...
city.appendChild(coords);
cities.appendChild(city);
}
return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + xml.toString();
}
|
Processar XML em PHP é um velho problema e há diversas soluções.
No entanto, na minha opinião, nenhuma chega perto de SimpleXML em termos de clareza e concisão.
Basicamente, cria-se um objeto PHP alimentando o documento XML ao método
simplexml_load_string() , em seguida, atravesse o resultado usando operadores PHP padrão.
Atributos tornam-se elementos de arrays (consulte como o código do país é lido na
Lista 9, por exemplo) e elementos podem ser acessados como uma array (usando o método
children() ) ou diretamente, como atributos do objeto.
Listing 9. SimpleXML is by far the easiest method of XML processing in PHP
$xml_str= $_POST["xmldata"];
$xml_obj= simplexml_load_string($xml_str);
...
foreach($xml_obj->children() as $city) {
$name= addslashes($city['name']);
$country= $city->country['code'];
$region= $city->region['code'];
$pop= $city->pop;
$lat= $city->coords->lat;
$lon= $city->coords->lon;
mysql_query("REPLACE INTO cities ".
"(cityName, countryCode, regionCode, population, latitude, longitude) VALUES (".
"'{$name}', '{$country}', '{$region}', '{$pop}', '{$lat}', '{$lon}')");
}
|
Há muitas outras maneiras de processar XML com PHP. Verifique a seção Recursos para obter links.
Só arranhei a superfície das diversas maneiras que XML pode ser usado como uma ponte entre GWT e PHP, mas os métodos fornecidos devem suficientes para fornecer um ponto de partida. O ponto principal a se lembrar é que GWT não está limitado a usar seu próprio método RPC e também pode existir felizmente com XML, produzindo e consumindo esses documentos com facilidade.
| Descrição | Nome | Tamanho | Método de download |
|---|---|---|---|
| Java source code for this article | java_source_code.zip | 4KB | HTTP |
| PHP source code for this article | php_source_code.zip | 4KB | HTTP |
Informações sobre métodos de download
Aprender
- Aprenda mais sobre XML no site de XML do W3C: Aprenda mais com muita documentação, incluindo a versão mais recente (5ª edição) da recomendação do padrão XML.
- XML processing in PHP: Explore diversos métodos—especialmente, SimpleXML, XMLReader e XMLWriter, conforme usados neste artigo.
XMLParserEstude a documentação de GWT.- JSON.org: Interessado em JSON como uma alternativa para XML? Localize recursos para as linguagens de programação mais modernas, incluindo a linguagem Java e PHP.
- A política de mesma origem: Aprenda mais e verifique a solução original para o problema SOP e leia algumas considerações extras sobre isso.
- Certificação em XML da IBM: Descubra como é possível se tornar um Desenvolvedor Certificado pela IBM em XML e tecnologias relacionadas.
- Biblioteca Técnica de XML: Consulte a Zona de XML do developerWorks para obter uma ampla gama de artigos técnicos e dicas, tutoriais, padrões e IBM Redbooks.
-
Eventos Técnicos e Webcasts do developerWorks: Permaneça atualizado com a tecnologia nessas sessões.
- A livrarias de tecnologia: Navegue para obter livros sobre estes e outros tópicos técnicos.
- developerWorks podcasts: Ouça entrevistas e discussões interessantes para desenvolvedores de software.
Obter produtos e tecnologias
- O Google Web Toolkit: Faça download e avalie as amostras de código incluídas neste artigo.
- A estrutura PEAR: Verifique a ocorrência de componentes PHP reutilizáveis.
- De MaxMind, atabela de cidades gratuita: Faça download e também localize links para os dados dos países e regiões.
- versões de avaliação do produto IBM: Faça download ou explore as avaliações on-line no IBM SOA Sandbox e obtenha ferramentas de desenvolvimento de aplicativos e produtos de middleware do
DB2®, Lotus®, Rational®, Tivoli®e WebSphere®.
Discutir
- Fóruns de Discussão da Zona XML: Participe de qualquer uma das diversas discussões relacionadas a XML.
- blogs do developerWorks: Verifique esses blogs e envolva-se com a comunidade do developerWorks.

Federico Kereki é um engenheiro de sistemas uruguaio com mais de 20 anos de experiência desenvolvendo sistemas, realizando trabalho de consultoria e ensinando nas universidades. Atualmente, trabalha com uma boa mistura de acrônimos: SOA, GWT, Ajax, PHP e, é claro, FLOSS! É possível contatar Frederico em fkereki@gmail.com.