.NET - Consultado XML com LINQ
A LINQ - Language integrated Query - é um conjunto de recursos introduzidos no .NET Framework 3.5 que permitem a realização de consultas diretamente em base de dados , documentos XML , estrutura de dados , coleção de objetos ,etc. usando uma sintaxe parecida com a linguagem SQL. |
Não importa a origem dos dados pois com LINQ podemos usar praticamente expressões semelhantes para realizar consultas tornando assim trabalho do desenvolvedor mais produtivo.
Neste artigo eu vou mostrar como podemos usar LINQ para consultar uma fonte de dados XML obtendo informações sobre elementos.
Nos exemplos usados neste artigo eu vou tomar como base o arquivo XML denominado Estoque.xml que possui a seguinte estrutura:(Estou mostrando apenas parte do arquivo para não ocupar espaço)
<Produtos> <ProdutoID>355</ProdutoID> <CategoriaID>16</CategoriaID> <ModeloNumero>RU007</ModeloNumero> <ModeloNome>Rain Racer 2000</ModeloNome> <ProdutoImagem>image.gif</ProdutoImagem> <CustoUnitario>1499.99</CustoUnitario> </Produtos> <Produtos> <ProdutoID>356</ProdutoID> <CategoriaID>20</CategoriaID> <ModeloNumero>STKY1</ModeloNumero> <ModeloNome>Edible Tape</ModeloNome> <ProdutoImagem>image.gif</ProdutoImagem> <CustoUnitario>3.99</CustoUnitario> </Produtos> .................. <Categorias> <CategoriaID>14</CategoriaID> <CategoriaNome>Communications</CategoriaNome> </Categorias> <Categorias> <CategoriaID>15</CategoriaID> <CategoriaNome>Deception</CategoriaNome> </Categorias> ...................... <Categorias> <CategoriaID>20</CategoriaID> <CategoriaNome>General</CategoriaNome> </Categorias> </NewDataSet> |
Consultando XML com LINQ
A classe System.Xml.Linq.XElement é
uma fonte de dados válido para consultas LINQ. A seqüência básica
para consultar uma árvore XML pode ser resumida asim:
1.
Inicie uma nova consulta utilizando LINQ usando palavra-chave from, fornecendo um nome
de variável que você vai usar para fazer seleções (por
exemplo, do elemento em root.Elements ()).
2. Identifique as condições para o uso em elementos de selecção
com a qual palavra-chave Where;
3. Indique qual o valor será adicionado ao conjunto de
resultados de cada elemento correspondente usando a palavra chave
de seleção Select;
4. Especifique o caminho em que deseja que os resultados sejam
classificados usando a palavra-chave orderby;
Ao utilizar XElement
como fonte o LINQ, o resultado será um IEnumerable de
XElements, contendo os elementos de sua árvore XML que
correspondem à sua pesquisa.
As LINQ consultas podem ser escritas usando palavras-chaves que foram adicionadas ao C # (from, where, select, etc), ou usando métodos de instância que preencham a mesma finalidade; no caso de XElement, você deve chamar o método de instância Elements para obter um IEnumerable <XElement> para usar como base para suas consultas.
Para selecionar um elemento, você pode usar as propriedades e métodos da classe XElement. Por exemplo, para encontrar todos os elementos em uma árvore XML que possuem um atributo de cor com valor igual azul, você usuaria:
from element in root.Elements () where (string)element.Attribute ("cor") == "blue" select element;
Para alcançar os mesmos resultados usando métodos de instância faríamos assim:
root.Elements().Where(e => (string)e.Attribute("cor") == "blue").Select(e => e);
O tipo de resultado de uma consulta
LINQ depende de que tipo de elemento que você recupera com a
palavra-chave Select, mas sempre será retornada
uma instância de IEnumerable, que você pode
usar em um loop foreach para executar através
dos elementos combinados, ou como base para mais consultas LINQ.
O exemplo anterior retorna um <XElement>
IEnumerable. Se você usar a palavra-chave Select
para obter um valor que representa uma característica de um
elemento, como um valor de atributo, então o tipo genérico de
IEnumerable será diferente.
No exemplo a seguir vamos carregar
uma árvore XML do arquivo Estoque.xml .
A seguir vamos procurar e selecionar os Elements
que são denominados produtos e que têm um valor
de 16 para o elemento filho CategoriaID,
imprimindo em seguida o valor do elemento filho ModeloNome;
A consulta usada é feita uma vez utilizando as palavras-chave
LINQ e feita novamente usando os métodos de instância e expressões
lambda. Qual você vai
adotar é uma questão de preferência.
Abra o Visual C# 2010 Express Edition e crie um
novo projeto Windows Forms Application com o
nome ConsultaXML_Linq;
A seguir inclua os seguintes controles no formulario form1.cs:
Conforme o leiaute da figura abaixo:
Agora vamos declarar os namespaces usados no formulário:
using
System;
using System.IO;
using System.Xml;
using System.Xml.Linq;
using System.Windows.Forms;
A seguir vamos declarar no início do formulário a variável para receber o nome e caminho do arquivo XML:
string
nomeArquivoXML;
XElement root;
No evento Click do botão que irá abrir a caixa diálogo para selecionar o arquivo insira o código abaixo:
private void btnProcurar_Click(object sender, EventArgs e) { OpenFileDialog dialogo = new OpenFileDialog(); dialogo.Filter ="txt files (*.xml)|*.xml|All files (*.*)|*.*"; dialogo.InitialDirectory = "C:\\dados"; dialogo.Title = "Selecione um arquivo XML"; if (dialogo.ShowDialog() == DialogResult.OK) { txtArquivoXML.Text = dialogo.FileName; } else { txtArquivoXML.Text = ""; } } |
A seguir em cada evento Click de cada botão de comando vamos incluir o código pertinente:
- Botão : Carregar XML - Carrega e exibe o conteúdo do XML no TextBox:
private void btnCarregaXML_Click(object sender, EventArgs e) { if (txtArquivoXML.Text == string.Empty) { MessageBox.Show("Informe o nome do arquivo XML a carregar.", "XML", MessageBoxButtons.OK, MessageBoxIcon.Information); } else { nomeArquivoXML = @txtArquivoXML.Text; try { root = XElement.Load(nomeArquivoXML); txtXML.Text = root.ToString(); //carrega o XML no TextBox txtXML.Text = root.ToString(); } catch (Exception ex) { MessageBox.Show("Erro : " + ex.Message); } } } |
- Botão : Consulta LINQ - Realiza a consulta LINQ no XML usando o critério definido e exibe o resultado no ListBox;
private void btnConsultaLINQ_Click(object sender, EventArgs e) { //consulta linq IEnumerable<string> catEnum = from elem in root.Elements() where (elem.Name == "Produtos" && ((string)elem.Element("CategoriaID")) == "16") select ((string)elem.Element("ModeloNome")); //exibe o resultado no ListBox lsResultado.Items.Clear(); foreach (string stringVal in catEnum) { lsResultado.Items.Add("Categoria 16 item: " + stringVal); } } |
Neste código estamos realizando uma consulta para obter os produtos cuja código da categoria é igual a 16 e exibimos o nome do modelo;
- Botão : Carregar XML - Realiza a consulta LINQ usando métodos de extensão no XML usando o critério definido e exibe o resultado no ListBox;
private void btnMetodosInstancia_Click(object sender, EventArgs e) { //usando métodos de instância IEnumerable<string> catEnum = root.Elements().Where( el => el.Name == "Produtos" && (string)el.Element("CategoriaID") == "20").Select(el => (string)el.Element("ModeloNome")); //exibe o resultado no ListBox lsResultado.Items.Clear(); foreach (string stringVal in catEnum) { lsResultado.Items.Add("Categoria 20 item: " + stringVal); } } |
Neste código estamos realizando uma consulta para obter os produtos cuja código da categoria é igual a 20 e exibimos o nome do modelo;
Executando o projeto iremos obter:
Vejamos a seguir outras consultas a título de exemplo:
1- Consultar os produtos e exibir o seu nome e custo unitário usando a propriedade Descendants;
private void btnQueryLINQ_Click(object sender, EventArgs e) { XDocument xmlDoc = XDocument.Load(nomeArquivoXML); var q = from c in xmlDoc.Descendants("Produtos") select (string)c.Element("ModeloNome") + " -- " + (string)c.Element("CustoUnitario"); foreach (string item in q) { lsResultado.Items.Add("Produtos : " + item); } } |
No código acima estamos usando a propriedade Descendants que acessa os elementos descentes de um elemento particular.
2- Consultar os produtos e exibir o nome e número do modelo para uma categoria particular usando a cláusula Where;
private void btnQueryLINQ1_Click(object sender, EventArgs e) { XDocument xmlDoc = XDocument.Load(nomeArquivoXML); var q = from c in xmlDoc.Descendants("Produtos") where c.Element("CategoriaID").Value == "16" select (string)c.Element("ModeloNome") + " ==>" + (string)c.Element("ModeloNumero"); foreach (string item in q) { lsResultado.Items.Add("Produtos : " + item); } } |
3- No código abaixo definimos um tipo anônimo em tempo de execução com duas propriedades : id e nome que são criadas com a palavra-chave new usada na cláusula Select e as propriedades são definidas no interior do corpo da instrução new { }.
|
A seguir acessamos o novo tipo no laço foreach para exibir os valores dos códigos dos produtos e respectivo nome de modelo para produtos com categoria igual a 20;
private void btnQueryLINQ2_Click(object sender, EventArgs e) { XDocument xmlDoc = XDocument.Load(nomeArquivoXML); var q = from c in xmlDoc.Descendants("Produtos") where c.Element("CategoriaID").Value == "20" select new { id = c.Element("ProdutoID").Value, nome = c.Element("ModeloNome").Value }; foreach (var obj in q) { lsResultado.Items.Add("Produtos : " + obj.id + " -- " + obj.nome); } } |
E dessa forma você viu como o LINQ pode facilitar a sua vida para realizar consultas em fonte de dados XML.
Simples , simples assim...
Pegue o projeto completo aqui: ConsultaXML_Linq.zip
Eu sei é apenas LINQ , mas eu gosto...
Referências: