segunda-feira, 29 de junho de 2009

Número serial para estender licença para o Flash Builder 4 beta

O número serial para estender uma licença do Adobe Flex Builder 3 para o Adobe Flash Builder 4 beta pode ser solicitado gratuitamente para quem tem a primeira licença - mesmo que seja uma licença educacional. Para isso, basta fazer a solicitação na página "Adobe Flash Builder 4 beta extension serial number request", informando o número da licença do Flex Builder 3.

domingo, 14 de junho de 2009

Manipulando XML no Flex com E4X

O Action Script 3 possui um conjunto de classes e funcionalidades para manipular documentos XML, baseados na especificação E4X (ECMAScript for XML) - mais precisamente na "ECMA-357 edition 2". Com isso, fica muito fácil trabalhar com XML, além do código ficar mais legível e fácil de manter.

As duas principais classes utilizadas são XML e XMLList - para utilizá-las, não é necessário importar nenhum pacote, já que elas ficam no core do framework.

Obs.: No ActionScript 2 também existia uma classe chamada XML, que foi renomeada para XMLDocument. As classes legadas do AS2 - XMLDocument, XMLNode e XMLNodeType - ficaram no pacote flash.xml.


Bom, mas em vez de explicar todas as funcionalidades do E4X, vamos diretamente a um exemplo prático comentado.

Vamos supor que temos o seguinte documento XML (XML literal) atribuído à variável "xmlProdutos":
var xmlProdutos: XML = 
 <produtos>
  <produto id="001">
   <nome>Creme Dental Happy</nome>
   <descricao>Tubo de 40g</descricao>
   <preco>3.50<preco>
   </produto>
  <produto id="002">
   <nome>Fio Dental Happy</nome>
   <descricao>50 metros</descricao>
   <preco>4.75<preco>
  </produto>
  <produto id="003">
   <nome>Escova Dental Happy</nome>
   <descricao>Escova de cerdas macias</descricao>
   <preco>3.45<preco>
  </produto>
 </produtos>;

1-) Acessando elementos do XML

Para acessar elementos ou nodos de um XML, é usada a notação "." - assim como se acessa as propriedades de um objeto qualquer. No exemplo dado, o documento "xmlProdutos" - que tem como elemento raiz "produtos" - possui uma lista de elementos filhos chamados "produto". Para retornar a lista de todos os produtos, na forma de XMLList, basta fazer da seguinte forma:
var listaDeProdutos: XMLList = xmlProdutos.produto;

Para obter um elemento específico, é só informar o seu índice (como se acessa um elemento de um array). Por exemplo, para pegar o primeiro "produto" do xmlProdutos:
var produto: XML = xmlProdutos.produto[0];

No XML de exemplo, um elemento "produto" possui três elementos filhos: "nome", "descricao" e "preco". Para obter a descrição do segundo produto, basta fazer:
var descricao: String = xmlProdutos.produto[1].descricao;

E para pegar o "id" de um determinado produto, deve-se usar um "@" - já que o id é um atributo do elemento "produto", e não um elemento filho, como no caso anterior.
var idProduto: String = xmlProdutos.produto[0].@id;

Já para obter a "descrição" de todos os produtos, basta não informar o índice do elemento "produto". O exemplo abaixo imprime no console a descrição de todos os produtos na forma de XMLList.
trace(xmlProdutos.produto.descricao);
No console, sairia assim:
Tubo de 40g
50 metros
Escova de cerdas macias

Para imprimir só o nome dos produtos, basta usar o método "text()":
trace(xmlProdutos.produto.descricao.text());
Obs.: Quando retorna só um elemento, como no caso de "trace(xmlProdutos.produto[0].descricao)", não é necessário utilizar o método "text()".


Outra forma de se obter os elementos de um XML é través da utilização dos métodos child() e attribute() - para obter, respectivamente, um elemento filho ou um atributo. Seguem exemplos com o uso dessa sintaxe:
txtResult.text = xmlProdutos.produto.child("nome");
xmlProdutos.produto.attribute("id");
Obs.: Uma das vantagens de utilizar os métodos child() e attribute(), é que é possível passar para eles uma variável do tipo String como argumento - dessa forma, a variável irá armazenar o nome do elemento ou do atributo e o código poderá ficar mais dinâmico.


Pode-se também buscar determinado elemento em qualquer nível do XML, sem conhecer seus nodos pais, ou quando o elemento tem pais diferentes, com o uso de ".." ou do método descendants(). Por exemplo, para obter a lista dos nomes de todos os produtos, poderia ser feito dessa forma:
var nomes: XMLList = xmlProdutos.produto.nome;
Ou simplesmente assim:
var nomes: XMLList = xmlProdutos..nome;
Ou ainda assim:
xmlProdutos.descendants("nome");

E se for utilizada a sintaxe "*", como no exemplo abaixo, "nome" poderia ter um elemento pai com qualquer nome, mas teria que estar necessariamente no segundo nível (com a sintaxe "..", ou utilizando o método descendants(), o elemento poderia estar em qualquer nível e em diferentes hierarquias dentro do XML).
var nomes: XMLList = xmlProdutos.*.nome;

Pode-se também iterar sobre os elementos de um XML. Se quisermos listar no console, por exemplo, o nome e o preço de todos os produtos, pode-se fazer assim:
for each(var xmlNode: XML in xmlProdutos.produto){
 trace(xmlNode.nome + " - R$" + xmlNode.preco);
}
Nesse caso, a variável xmlNode vai representar o elemento "produto" de cada iteração.

Pode-se ainda iterar sobre os elementos de um XML sem conhecer seus nomes, através do método children(), que retorna um XMLList com os elementos filhos, ou do método attributes(), que retorna um XMLList com os atributos do elemento. No exemplo abaixo, em que foi utilizado o método children() para retornar todos os elementos filhos de cada elemento "produto", a variável "element" vai representar cada um desses filhos em cada iteração - a seguir, é verificado se esse filho é do tipo "nome" ou "preco", através do método localname(), e, em caso positivo, é feito a impressão do valor deles no console.
for each(var element: XML in xmlProdutos.produto.children()){
 if(element.localName() == "nome")
  trace("Nome: " + element);
 else if(element.localName() == "preco")
  trace("Preço: " + element);
}

2-) Pesquisando elementos do XML

Pode-se pesquisar determinados elementos no XML. Por exemplo, para obter o elemento "produto" com o atributo "id" = "001", basta fazer:
var xmlProduto001: XML = xmlProdutos.produto.(@id=="001");

E para obter o "nome" do "produto" com atributo "id" = "002", pode-se fazer:
var nomeProduto002: String = xmlProdutos.produto.(@id=="002").nome;

Já para obter a descricao do "produto" com "nome" = "Creme Dental Happy", basta fazer:
var nomeProduto002: String = xmlProdutos.produto.(nome=="Creme Dental Happy").descricao;

Pode-se também utilizar filtros múltiplos. Por exemplo, para obter os produtos com "nome" = "Creme Dental Happy" e "descricao" = "Tubo de 40g", pode-se fazer assim:
var produto: XML = xmlProdutos.produto.(nome=="Creme Dental Happy" && descricao=="Tubo de 40g");

Também é possível utilizar operadores relacionais. Por exemplo, para obter todos os produtos com o preço menor que R$3,00, pode-se fazer assim:
var xmlProdutosFiltrados: XMLList = xmlProdutos.produto.(preco<3);
E para pegar todos os produtos que contenham a palavra "Dental", pode-se usar a função nativa search. Essa função irá retornar a posição inicial do padrão informado (no caso uma String) - se retornar "-1", significa que o padrão não foi encontrado:
var xmlProdutosFiltrados: XMLList = xmlProdutos.produto.(String(nome).search("Dental")>-1);
Atenção: Se tiver mais de um elemento retornado na pesquisa, vai voltar um XMLList e não um XML (se você não tiver certeza se vai voltar um ou mais elementos, use sempre um XMLList). Pode-se então iterar sobre os elementos do XMLList, assim como se faz com um XML. Exemplo de iteração em um XMLList:
var xmlList: XMLList = xmlProdutos.produto;
for each(var xmlNode:XML in xmlList)
 trace(xmlNode.nome);


3-) Alterando, deletando e incluindo elementos no XML

a) Para alterar ou atribuir um valor:
xmlProdutos.produto[0].descricao = "nova descrição";
b) Para deletar um ou mais elementos:
delete xmlProdutos.produto[0];
c) Para incluir um novo elemento: Supondo que deseja-se incluir um novo "produto", representado pelo XML abaixo:
var novoProduto: XML = 
  <produto id="534">
   <nome>Anti-séptico bucal Happy</nome>
   <descricao>Frasco de 150mL</descricao>
   <preco>6.35</preco>
  </produto>;
Para inserir um elemento no final do documento XML, pode-se utilizar o método appendChild:
xmlProdutos.appendChild(novoProduto);
Para inserir um elemento no final do início do XML, pode-se utilizar o método prependChild:
xmlProdutos.prependChild(novoProduto);
Pode-se ainda passar como parâmetro dos métodos appendChild ou prependChild um XMLList ou até mesmo um XML literal, como no exemplo abaixo:
xmlProdutos.appendChild(<produto id="534"><nome>Anti-séptico Happy</nome><descricao>Anti-séptico bucal Happy - frasco de 150mL</descricao><preco>6.35</preco></produto>);
Na utilização de um XML literal, pode-se também usar binding, através do uso de "{" e "}":
var id: String = "534";
var nome: String = "Anti-séptico Happy";
var descricao: String = "Anti-séptico bucal Happy - frasco de 150mL";
var nome: String = "Anti-séptico Happy";
var preco: Number = 6.35;

xmlProdutos.appendChild(<produto id={id}><nome>{nome}</nome><descricao>{descricao}</descricao><preco>{preco}</preco></produto>);
Pode-se ainda inserir o elemento em uma posição específica do XML. Por exemplo, para inserir o novo produto antes do produto que está na posição 2, pode-se usar o método insertChildBefore:
xmlProdutos.insertChildBefore(xmlProdutos.produto[2], novoProduto);
E para inserir depois do produto que está na posição 1, pode-se usar o método insertChildAfter:
xmlProdutos.insertChildAfter(xmlProdutos.produto[1], novoProduto);

4-) Carregando um arquivo XML Para carregar um arquivo XML externo, pode-se utilizar as classes URLLoader e URLRequest, conforme o exemplo abaixo:
import flash.net.URLLoader
   
private var xmlProdutos: XML;
private var urlLoader: URLLoader;
   
private function carregaXML(): void{
 urlLoader = new URLLoader();
 urlLoader.addEventListener(Event.COMPLETE, onComplete);
 //carrega o arquivo "produtos.xml" de uma url qualquer 
 urlLoader.load(new URLRequest("http://www.inf.ufsc.br/~feco/blog/data/produtos.xml"));
 //ou carrega o arquivo "produtos.xml" presente no diretório dados do mesmo contexto da aplicação (local dos fontes)
 urlLoader.load(new URLRequest("dados/produtos.xml"));
}
   
private function onComplete(evt:Event):void{
 xmlProdutos = new XML(urlLoader.data);
}
Já no MXML, basta utilizar o atributo source:
<mx:XML id="xmlProdutos" source="dados/produtos.xml"/>
Pode-se também utilizar o HTTPService, em vez do URLRequest. No exemplo abaixo, é utilizado o HTTPService do MXML:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" initialize="dataService.send()">

 <mx:Script><![CDATA[
  import mx.rpc.events.ResultEvent;
   
  var xmlProdutos: XML;
   
  private function onResult(event: ResultEvent): void{
   xmlProdutos = XML(event.result);
  }
 ]]></mx:Script>
 
 <mx:HTTPService id="dataService" url="http://www.inf.ufsc.br/~feco/blog/data/produtos.xml" resultFormat="e4x" result="onResult(event)"/>

</mx:Application>

Referências:
AS3 E4X Rundown
Adobe Flex 3.3 Language Reference
Flex Quick Starts: Handling data - Accessing XML data
Ways to use E4X to filter data in ActionScript 3
Working with XML Working with XML, E4X and ActionScript 3


segunda-feira, 1 de junho de 2009

Lançados os betas do Adobe Flash Builder 4 e do Adobe Flash Catalyst

Foi lançada a versão beta do Adobe Flash Builder 4, que substituirá o Adobe Flex Builder 3. Apesar do nome da IDE ter mudado, o nome do framework continua sendo Adobe Flex - a intenção da Adobe foi de criar uma clara distinção entre a a IDE, que é paga, e o framework, que é free.

Dentre as melhorias na IDE, estão:
  1. Melhorias no refactoring, no debugger e no profiler.
  2. Geração automática de getters e setters.
  3. Package Explorer.
  4. Network Monitor (mede tráfego entre o cliente e o servidor).
  5. Suporte a Flex Unit (testes unitários) .

*Mais detalhes em: "What's new in Flash Builder 4 beta".


Vale lembrar que a versão beta do Adobe Flash Builder 4 já trás consigo a nova versão do framework Flex, o Flex 4 SDK (codinome "Gumbo"), que também ainda está em versão beta (a versão final está prevista para o quarto trimestre do ano). Deixarei para abordar as mudanças da nova versão do framework em um post futuro.

Também foi lançada a versão beta do Adobe Flash Catalyst. Com essa ferramenta, que pode trabalhar em conjunto com o Flash Builder, será possível fazer a prototipação e criação de interfaces visuais funcionais (incluindo eventos e efeitos), sem nenhuma codificação. Será possível também fazer a exportação de projetos do Adobe Photoshop® e do Adobe Illustrator®, para serem manipulados e integrados com a codificação da aplicação. Assim, os designers podem trabalhar em conjunto com os desenvolvedores, disponibilizando toda parte visual da aplicação e permitindo que eles se preocupem apenas com o código de negócio.

Dica: nesse link se encontram alguns vídeos com demonstrações do Flash Builder, do Flash Catalyst e do Flex SDK 4.