XML - Consultando com XElement e LINQ to XML (revisão)


 No artigo de hoje vamos revisar os conceitos sobre como realizar consultas em documentos XML usando XElement e LINQ to XML.

Eu não vou me ater à teoria visto que já tratei deste assunto em diversos artigos que você pode consultar nas referências.

Na verdade este artigo fornece exemplos de consultas em documentos XML usando XElement demonstrando o uso deste recurso e dos métodos de extensão LINQ e consultas de expressão LINQ.

Existem muitas formas (até demais...) de consultar e analisar XML e usar XDocument e XElement é preferível ao uso do XMLdocument.

Outra abordagem seria usar XPath que é muito poderosa e não é específico da plataforma .NET mas a sintaxe usadas nas expressões de consulta exigem um esforço maior.

A classe System.Xml.Linq.XElement é uma fonte de dados válido para consultas LINQ. A seqüência básica para consultar um documento XML pode ser resumida assim:

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 seleçã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.

Na verdade a quantidade de opções para realizar consultas em documentos XML acaba confundindo o iniciante e usar apenas XElement é uma forma poderosa e simples de realizar consultas.

Recursos usados :

Criando o projeto exemplo no VS 2013 Community

Abra o VS 2013 Community e clique em New Project;

A seguir selecione Visual VB .NET -> Windows Forms Application;

Informe o nome Consultas_XML_XElement e clique no botão OK;

 No formulário padrão form1.cs inclua a partir da ToolBox os seguintes controles:

Defina o seguinte leiaute no formulário form1.vb:

Vamos criar nosso documento XML no qual iremos realizar as consultas.

No menu PROJECT clique em Add New Item e a seguir clique em Data e selecione XML File;

Informe o nome Livros.xml para criar o arquivo no projeto :

A seguir inclua o seguinte código para o arquivo Livros.xml :

Nota: Este arquivo foi obtido no site da Microsoft em : https://msdn.microsoft.com/en-us/library/ms762271%28v=vs.85%29.aspx e parcialmente traduzido e alterado.

<?xml version="1.0" encoding="UTF-8"?>
<catalogo>
  <livro id="bk101">
    <autor>Gambardella, Matthew</autor>
    <titulo>XML Developer's Guide</titulo>
    <genero>Computer</genero>
    <preco>44.95</preco>
    <data_publicacao>2000-10-01</data_publicacao>
    <descricao>
      An in-depth look at creating applications
      with XML.
    </descricao>
    <tags>
      <tag>XML</tag>
    </tags>
  </livro>
  <livro id="bk102">
    <autor>Ralls, Kim</autor>
    <titulo>Midnight Rain</titulo>
    <genero>Fantasy</genero>
    <preco>5.95</preco>
    <data_publicacao>2000-12-16</data_publicacao>
    <descricao>
      A former architect battles corporate zombies,
      an evil sorceress, and her own childhood to become queen
      of the world.
    </descricao>
    <tags>
      <tag>zombies</tag>
      <tag>sorcery</tag>
    </tags>
  </livro>
  <livro id="bk103">
    <autor>Corets, Eva</autor>
    <titulo>Maeve Ascendant</titulo>
    <genero>Fantasy</genero>
    <preco>5.95</preco>
    <data_publicacao>2000-11-17</data_publicacao>
    <descricao>
      After the collapse of a nanotechnology
      society in England, the young survivors lay the
      foundation for a new society.
    </descricao>
    <tags>
      <tag>England</tag>
      <tag>society</tag>
    </tags>
  </livro>
  <livro id="bk104">
    <autor>Corets, Eva</autor>
    <titulo>Oberon's Legacy</titulo>
    <genero>Fantasy</genero>
    <preco>5.95</preco>
    <data_publicacao>2001-03-10</data_publicacao>
    <descricao>
      In post-apocalypse England, the mysterious
      agent known only as Oberon helps to create a new life
      for the inhabitants of London. Sequel to Maeve
      Ascendant.
    </descricao>
    <tags>
      <tag>England</tag>
      <tag>sequel</tag>
    </tags>
  </livro>
  <livro id="bk105">
    <autor>Corets, Eva</autor>
    <titulo>The Sundered Grail</titulo>
    <genero>Fantasy</genero>
    <preco>5.95</preco>
    <data_publicacao>2001-09-10</data_publicacao>
    <descricao>
      The two daughters of Maeve, half-sisters,
      battle one another for control of England. Sequel to
      Oberon's Legacy.
    </descricao>
    <tags>
      <tag>England</tag>
    </tags>
  </livro>
  <livro id="bk106">
    <autor>Randall, Cynthia</autor>
    <titulo>Lover Birds</titulo>
    <genero>Romance</genero>
    <preco>4.95</preco>
    <data_publicacao>2000-09-02</data_publicacao>
    <descricao>
      When Carla meets Paul at an ornithology
      conference, tempers fly as feathers get ruffled.
    </descricao>
    <tags>
      <tag>conference</tag>
      <tag>love</tag>
    </tags>
  </livro>
  <livro id="bk107">
    <autor>Thurman, Paula</autor>
    <titulo>Splish Splash</titulo>
    <genero>Romance</genero>
    <preco>4.95</preco>
    <data_publicacao>2000-11-02</data_publicacao>
    <descricao>
      A deep sea diver finds true love twenty
      thousand leagues beneath the sea.
    </descricao>
    <tags>
      <tag>love</tag>
      <tag>sea</tag>
    </tags>
  </livro>
  <livro id="bk108">
    <autor>Knorr, Stefan</autor>
    <titulo>Creepy Crawlies</titulo>
    <genero>Horror</genero>
    <preco>4.95</preco>
    <data_publicacao>2000-12-06</data_publicacao>
    <descricao>
      An anthology of horror stories about roaches,
      centipedes, scorpionsand other insects.
    </descricao>
    <tags>
      <tag>insects</tag>
    </tags>
  </livro>
  <livro id="bk109">
    <autor>Kress, Peter</autor>
    <titulo>Paradox Lost</titulo>
    <genero>Science Fiction</genero>
    <preco>6.95</preco>
    <data_publicacao>2000-11-02</data_publicacao>
    <descricao>
      After an inadvertant trip through a Heisenberg
      Uncertainty Device, James Salway discovers the problems
      of being quantum.
    </descricao>
    <tags>
      <tag>Heisenberg</tag>
      <tag>quantum</tag>
    </tags>
  </livro>
  <livro id="bk110">
    <autor>O'Brien, Tim</autor>
    <titulo>Microsoft .NET: The Programming Bible</titulo>
    <genero>Computer</genero>
    <preco>36.95</preco>
    <data_publicacao>2000-12-09</data_publicacao>
    <descricao>
      Microsoft's .NET initiative is explored in
      detail in this deep programmer's reference.
    </descricao>
    <tags>
      <tag>Microsoft</tag>
      <tag>NET</tag>
    </tags>
  </livro>
  <livro id="bk111">
    <autor>O'Brien, Tim</autor>
    <titulo>MSXML3: A Comprehensive Guide</titulo>
    <genero>Computer</genero>
    <preco>36.95</preco>
    <data_publicacao>2000-12-01</data_publicacao>
    <descricao>
      The Microsoft MSXML3 parser is covered in
      detail, with attention to XML DOM interfaces, XSLT processing,
      SAX and more.
    </descricao>
    <tags>
      <tag>Microsoft</tag>
      <tag>XML</tag>
      <tag>XSLT</tag>
    </tags>
  </livro>
  <livro id="bk112">
    <autor>Galos, Mike</autor>
    <titulo>Visual Studio 7: A Comprehensive Guide</titulo>
    <genero>Computer</genero>
    <preco>49.95</preco>
    <data_publicacao>2001-04-16</data_publicacao>
    <descricao>
      Microsoft Visual Studio 7 is explored in depth,
      looking at how Visual Basic, Visual C++, C#, and ASP+ are
      integrated into a comprehensive development
      environment.
    </descricao>
    <tags>
      <tag>Microsoft</tag>
      <tag>NET</tag>
    </tags>
  </livro>
</catalogo>

Este será o arquivo sobre o qual iremos realizar as nossas consultas.

Vamos agora definir os namespaces usados no formulário:

imports System.Xml
imports
System.Xml.Linq
imports
System.Windows.Forms
imports
System.IO

A seguir vamos definir a variável raiz do tipo XElement no início do formulário que será usada no projeto:

Dim raiz As XElement

A primeira coisa que temos que fazer é carregar o arquivo XML exibindo no controle TextBox - txtXML. Para isso temos no evento botão - Carregar Arquivo XML - o código abaixo:

Botão Carregar Arquivo XML

  Private Sub btnCarregarArquivoXML_Click(sender As Object, e As EventArgs) Handles btnCarregarArquivoXML.Click
        Dim dialogo As 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 Then
            Try
                raiz = XElement.Load(dialogo.FileName)
                'carrega o XML no TextBox
                txtXML.Text = raiz.ToString()
            Catch ex As Exception
                MessageBox.Show("Erro : " + ex.Message)
            End Try
        Else
            MessageBox.Show("Informe o nome do arquivo XML a carregar.", "XML", MessageBoxButtons.OK, MessageBoxIcon.Information)
        End If
    End Sub

Neste código estamos usando uma caixa de diálogo OpenFileDialog para que o usuário possa selecionar o arquivo XML. Definimos a pasta inicial como sendo c:\dados e usamos o método Load de XElement para carregar o arquivo.

A partir de agora podemos realizar consultas usando a variável raiz que conterá o arquivo XML.

Vamos começar com exibindo o resultado e o código para cada consulta associado ao evento Click do respectivo botão de comando:

- Exibir Informação de Livros

 Private Sub btnLivros_Click(sender As Object, e As EventArgs) Handles btnLivros.Click
        Try
            Dim livros As IEnumerable(Of XElement) = raiz.Elements
            lbResultado.Items.Clear()
            For Each livro In livros
                lbResultado.Items.Add(livro)    'saida XML
            Next
        Catch ex As Exception
            MessageBox.Show("Erro : " + ex.Message, "XML Livros", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
End Sub

- Exibir Títulos dos livros

   Private Sub btnTitulos_Click(sender As Object, e As EventArgs) Handles btnTitulos.Click
        Try
            Dim livros As IEnumerable(Of XElement) = raiz.Elements
            lbResultado.Items.Clear()
            For Each livro In livros
                lbResultado.Items.Add(livro.Element("titulo").Value)
            Next
        Catch ex As Exception
            MessageBox.Show("Erro : " + ex.Message, "XML Livros", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub

- Exibir Título, Autor e Preço dos livros

Private Sub btnTituloAutor_Click(sender As Object, e As EventArgs) Handles btnTituloAutor.Click
        Try
            Dim livros As IEnumerable(Of XElement) = raiz.Elements
            lbResultado.Items.Clear()
            For Each livro In livros
                lbResultado.Items.Add(livro.Element("titulo").Value + vbTab + "  Autor =>" + livro.Element("autor").Value + vbTab + " Preço " + livro.Element("preco").Value)
            Next
        Catch ex As Exception
            MessageBox.Show("Erro : " + ex.Message, "XML Livros", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
 End Sub

- Usando Take e OrderBy, Filtrando e ordenando

  Private Sub btnTakeOrderBy_Click(sender As Object, e As EventArgs) Handles btnTakeOrderBy.Click
        Try
            Dim livros As IEnumerable(Of XElement) = raiz.Elements
          Dim filtro = livros.Take(4).OrderBy(Function(x) x.Element("titulo").Value)
            lbResultado.Items.Clear()
            lbResultado.Items.Add("Os primeiros 4 livros ordenados por titulo: ")
            For Each livro In filtro
                lbResultado.Items.Add(livro.Element("titulo").Value)
            Next
        Catch ex As Exception
            MessageBox.Show("Erro : " + ex.Message, "XML Livros", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
 End Sub

- Consulta Expressão Filtrando por genero

  Private Sub btnConsultaExpressao_Click(sender As Object, e As EventArgs) Handles btnConsultaExpressao.Click
        Try
            Dim livros As IEnumerable(Of XElement) = raiz.Elements
           Dim filtro = From liv In livros
                            Where CStr(liv.Element("genero")) = "Computer"
                            Select liv
            lbResultado.Items.Clear()
            lbResultado.Items.Add("Exibindo somente os livros do genero Computer : ")
            For Each livro In filtro
                lbResultado.Items.Add(livro.Element("titulo").Value + vbTab + "  Autor =>" + livro.Element("autor").Value)
            Next
        Catch ex As Exception
            MessageBox.Show("Erro : " + ex.Message, "XML Livros", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
 End Sub

- Selecionar por atributo

Private Sub btnSelecionarAtributo_Click(sender As Object, e As EventArgs) Handles btnSelecionarAtributo.Click
        Try
            Dim livros As IEnumerable(Of XElement) = raiz.Elements
          Dim filtro = From liv In livros
                           Where CStr(liv.Attribute("id")) Like "bk#1#"
                           Select liv
            lbResultado.Items.Clear()
            lbResultado.Items.Add("Selecionado por atributo 'id' igual a (#1#) ")
            For Each livro In filtro
                lbResultado.Items.Add(livro.Element("titulo").Value + vbTab + "  Autor =>" + livro.Element("autor").Value + vbTab + "Preço = " + livro.Element("preco").Value)
            Next
        Catch ex As Exception
            MessageBox.Show("Erro : " + ex.Message, "XML Livros", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
 End Sub

- Exibir tags Aninhadas

 Private Sub btnTagsAninhadas_Click(sender As Object, e As EventArgs) Handles btnTagsAninhadas.Click
        Try
            Dim livros As IEnumerable(Of XElement) = raiz.Elements
          Dim filtro = From liv In livros
                           Where liv.Element("tags").Elements("tag").Count(Function(x) x.Value = "Microsoft") > 0
                           Select liv
            lbResultado.Items.Clear()
            lbResultado.Items.Add("Selecionado tags aninhadas : Livros/Microsoft  ")
            For Each livro In filtro
                lbResultado.Items.Add(livro.Element("titulo").Value + vbTab + "Preço = " + livro.Element("preco").Value)
            Next
        Catch ex As Exception
            MessageBox.Show("Erro : " + ex.Message, "XML Livros", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
End Sub

- Listando Tags Únicas usando Let, OrderBy, Distinct

 Private Sub btnTagsUnicas_Click(sender As Object, e As EventArgs) Handles btnTagsUnicas.Click
        Try
            Dim livros As IEnumerable(Of XElement) = raiz.Elements
            Dim filtro = From tag In livros.Descendants("tags").Elements("tag")
                             Let x = tag.Value
                             Order By x
                             Select x
                             Distinct
            lbResultado.Items.Clear()
            lbResultado.Items.Add("Selecionado tags Únicas e ordenadas ")
            For Each tg In filtro
                lbResultado.Items.Add(tg)
            Next
        Catch ex As Exception
            MessageBox.Show("Erro : " + ex.Message, "XML Livros", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub

- Agrupamento e Contagem usando Group By e Count

Private Sub btnAgrupamentoContagem_Click(sender As Object, e As EventArgs) Handles btnAgrupamentoContagem.Click
        Try
            Dim livros As IEnumerable(Of XElement) = raiz.Elements
           Dim filtro = From liv In livros
                             Group By Genero = liv.Element("genero").Value
                             Into LivrosGeneros = Group, Count = Group
            lbResultado.Items.Clear()
            lbResultado.Items.Add("Agrupando generos e contando o total: ")
            For Each grp In filtro
                lbResultado.Items.Add(grp.Genero.ToString + " Total => " + grp.LivrosGeneros.Count.ToString())
            Next
        Catch ex As Exception
            MessageBox.Show("Erro : " + ex.Message, "XML Livros", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
End Sub

Executando o projeto e escolhendo um texto para converter temos o seguinte resultado:

O exemplo funciona bem para arquivos textos pequenos mas você pode incrementar o projeto estendendo suas funcionalidades.

Pegue o projeto completo aqui:  Consultas_XML_XElement.zip

Disse Jesus : "Uma geração má e adúltera pede um sinal, e nenhum sinal lhe será dado, senão o sinal do profeta Jonas. E, deixando-os, retirou-se."
Mateus 16:4

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

  Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter

Referências:


José Carlos Macoratti