Lendo Arquivos XML Através de XML Literals

26/07/2011

Uma característica muito interessante porém pouco utilizada no VB.Net são os XML Literals. Pegando carona na idéia do Linq, a equipe do VB.Net introduziu o XML Literals como forma de simplificar/flexibilizar a manipulação de dados XML em memória ou peristidos com uma sintaxe mais direta e que pode ser associada ao Linq to XML. Na sintaxe do XML Literals o XML é manipulado como se estivéssemos digitando diretamente XML ao invés de código que gere XML. Para entendermos melhor como isso funciona, vamos considerar um arquivo XML com a seguinte estrutura:


<?xml version="1.0" encoding="utf-8" ?>
<som>
<producoes>
<album nome="Nothing Safe" artista="Alice in Chains" ano="1999">
    <selo>Sony Music Distribution</selo>
</album>
<album nome="Return of the Killer A's: The Best of Anthrax" artista="Anthrax" ano="1999">
    <selo>Beyond</selo>
</album>
<album nome="Starfish" artista="The Church" ano="1988">
    <selo>Arista</selo>
</album>
<album nome="Collective Soul" artista="Collective Soul" ano="1995">
    <selo>Atlantic</selo>
</album>
</producoes>
</som>

Para trabalharmos esse arquivo em memória teremos que carregá-lo, mas ao invés de recorrermos ao System.Xml para isso, vamos usar XML Literals através do namespace System.Xml.Linq:

Dim xmlDoc As XDocument = XDocument.Load("C:\Som.xml")

A partir daí para ler elementos do arquivo, usamos XML Literals. Por exemplo, para identificar todos os selos presentes no arquivo podemos montar o código assim:

Debug.WriteLine("Selos:")
For Each xeAlbum As XElement In xmlDoc...<producoes >.<album>
    Debug.WriteLine(xeAlbum...<selo>.Value)
Next

No trecho acima, xmlDoc...<producoes> se refere à todos os elementos producoes que sejam descendentes do elemento raiz, enquanto .<album> representa um elemento album descendente de <producoes>. Percorremos então todos os albums de <producoes> lendo o valor do elemento <selo>. Agora considere o trecho abaixo:

Debug.WriteLine("Albuns:")
For Each xeAlbum As XElement In xmlDoc...<producoes>.<album>
    Debug.WriteLine(xeAlbum.@nome)
Next

Aqui a idéia é obter o nome de cada album. Como os nomes estão representados por atributos, utilizamos o caracter @ como em @nome para ler o valor do atributo. Se o objetivo for obter dados genéricos sobre os elementos, isso também é possível. Aqui obtemos o total de albuns existentes no arquivo:

Dim intAlbums As Integer = xmlDoc...<producoes>.<album>.Count

Linq to XML e XML Literals

O XML Literals incorpora os recursos do Linq de forma a simplificar ainda mais a leitura dos dados. Por exemplo, podemos localizar todos os albuns produzidos em um determinado ano usando expressões Lambda:

Dim enumAno = xmlDoc...<producoes>.<album>.Where(Function(a) a.@ano = 1999)
For Each xeAlbum In enumAno
    Debug.WriteLine(xeAlbum.@nome)
Next

Ou claúsulas Linq, como neste exemplo para localizar um album especifico trazendo seu nome e artista:

Dim xeItem = (From b In xmlDoc...<album> _
Where b.@nome.ToString.Contains("Starfish")).FirstOrDefault
Debug.WriteLine(String.Format("{0} - {1}", xeItem.@nome, xeItem.@artista))

Repare que em ambos os exemplos as variáveis são por inferência, do tipo IEnumerable(Of XElement) e XElement, o que desfaz a necessidade de declararmos o tipo do objeto. Na verdade, esse recurso pode ser desligado a nível de projeto ou módulo através da cláusula Option Infer Off, embora não seja exatamente necessário.

Vimos como ler dados em XML na memória utilizando Linq to XML e XML Literals. Para saber como criar aqrquivos XML usando XML Literals, leia o próximo artigo sobre o assunto.