VB .NET - Realizando operações com LINQ To XML


O assunto hoje é sobre XML (eXtensible Markup Language) e posso dizer que vi o XML nascer, crescer e aparecer pois meados da década de 1990, o World Wide Web Consortium (W3C) começou a trabalhar em uma linguagem de marcação que combinasse a flexibilidade da SGML (Standard Generalized Markup Language) com a simplicidade da HTML surgindo daí o XML.

Atualmente XML é uma recomendação da W3C para gerar linguagens de marcação para necessidades especiais. Seu propósito principal é a facilidade de compartilhamento de informações através da internet.

Para uma introdução básica em XML veja o meu artigo : XML – Introdução - Macoratti.net

Neste artigo o foco será o LINQ to XML que é um provedor de dados LINQ que é implementado no namespace System.Xml.LINQ a partir da versão 3.5 da plataforma .NET. Ele fornece um modelo de programação que permite ler, construir e escrever dados XML. Você pode usar LINQ To XML para realizar consultas LINQ sobre dados no formato XML que podem ser retornados do arquivo de sistemas, de uma URL HTTP remota, de um web service ou partir de qualquer XML em memória existente.

O LINQ To XML fornece mais recursos e facilidades para tratar com XML do que a API presente no namespace System.XML(XmlReader/XmlWriter) da versão anterior da plataforma .NET, sendo também mais eficiente, por usar menos memória, que a API DOM do XmlDocument fornece.

Vamos dar um enfoque prático mostrando como realizar algumas tarefas para tratar XML com LINQ to XML ao estilo "Como fazer..".

Para acompanhar os exemplos você vai precisar dos seguintes recursos:

Preparando o ambiente de trabalho

Abra o Visual Studio 2012 Express for desktop e clique em New Project;

Selecione a linguagem Visual Basic e o template Windows -> Windows Forms Application; informe o nome LINQ_To_XML_Operacoes e clique no botão OK;

Vamos criar agora o arquivo XML que será usado em nossa solução.

No menu PROJECT clique Add New Item e selecione o item Data->XML File e informe o nome Funcionarios.xml;

A seguir digite ou copie o conteúdo abaixo para este arquivo:

<?xml version="1.0" encoding="utf-8" ?>
<Funcionarios>
  <Funcionario>
    <FunciId>1</FunciId>
    <Nome>Macoratti</Nome>
    <Sexo>Masculino</Sexo>
    <Fone Tipo="Residencial">23-555-0124</Fone>
    <Fone Tipo="Comercial">21-555-0545</Fone>
    <Endereco>
      <Local>Rua Projetada 100</Local>
      <Cidade>Santos</Cidade>
      <Estado>SP</Estado>
      <Cep>10100-520</Cep>
      <Pais>Brasil</Pais>
    </Endereco>
  </Funcionario>
  <Funcionario>
    <FunciId>2</FunciId>
    <Nome>Janice</Nome>
    <Sexo>Feminino</Sexo>
    <Fone Tipo="Residencial">11-555-0763</Fone>
    <Fone Tipo="Comercial">11-555-0567</Fone>
    <Endereco>
      <Local>Rua XV de Novembro 230</Local>
      <Cidade>Sao Paulo</Cidade>
      <Estado>SP</Estado>
      <Cep>01200-200</Cep>
      <Pais>Brasil</Pais>
    </Endereco>
  </Funcionario>
  <Funcionario>
    <FunciId>3</FunciId>
    <Nome>Jessica</Nome>
    <Sexo>Feminino</Sexo>
    <Fone Tipo="Residencial">16-555-0231</Fone>
    <Fone Tipo="Comercial">16-555-0442</Fone>
    <Endereco>
      <Local>Av. Equador 109</Local>
      <Cidade>Lins</Cidade>
      <Estado>SP</Estado>
      <Cep>14052-500</Cep>
      <Pais>Brasil</Pais>
    </Endereco>
  </Funcionario>
  <Funcionario>
    <FunciId>4</FunciId>
    <Nome>Jefferson</Nome>
    <Sexo>Masculino</Sexo>
    <Fone Tipo="Residencial">17-555-0122</Fone>
    <Fone Tipo="Comercial">17-555-0154</Fone>
    <Endereco>
      <Local>Trav. Jorge Amado 901</Local>
      <Cidade>Americana</Cidade>
      <Estado>SP</Estado>
      <Cep>13052-520</Cep>
      <Pais>Brasil</Pais>
    </Endereco>
  </Funcionario>
</Funcionarios>

No formulário Form1.vb vamos incluir um controle TextBox com name igual a txtXML, Multiline=True e ScrollBars=Both, para exibir os resultados e a medida que formos realizando as operações vamos incluir botões de controles onde no evento Click teremos o código.

Então ao trabalho...

1- Como ler um arquivo XML usando LINQ to XML

Há duas maneiras de fazer isso:

Ambas as classes contêm o método Load que aceita um arquivo, uma URL ou um XMLReader e permite que o XML seja carregado.

A principal diferença entre as duas classes é que um XDocument pode conter uma declaração XML, um XML Document Type (DTD) e instruções de processamento. Além disso, um XDocument contém uma raiz XElement.

a-) usando a classe XElement
 Private Sub btnLerXML_XElement_Click(sender As Object, e As EventArgs) Handles btnLerXML_XElement.Click
        Dim xelement As XElement = xelement.Load("..\..\Funcionarios.xml")
        Dim funcionarios As IEnumerable(Of XElement) = xelement.Elements()
        ' Le o arquivo XML inteiro
        For Each funcionario In funcionarios
            txtXML.Text = txtXML.Text & funcionario.ToString & vbCrLf
        Next funcionario
    End Sub

b-) usando a classe XDocument

Private Sub btnLerXMLXDocument_Click(sender As Object, e As EventArgs) Handles btnLerXMLXDocument.Click
        Dim xdocument As XDocument = xdocument.Load("..\..\Funcionarios.xml")
        Dim funcionarios As IEnumerable(Of XElement) = xdocument.Elements()
        For Each funcionario In funcionarios
            txtXML.Text = txtXML.Text & funcionario.ToString & vbCrLf
        Next funcionario
    End Sub

2- Como acessar um único elemento usando LINQ to XML

Vamos acessar o nome de todos os funcionários e exibi-los.

Usando a classe XElement que representa um XML

O método de extensão IEnumerable(Of Element) retorna uma coleção de
atributos de cada elemento na coleção fonte (XElement)

 Private Sub btnLerElemento_Click(sender As Object, e As EventArgs) Handles btnLerElemento.Click

        Dim xelement As XElement = xelement.Load("..\..\Funcionarios.xml")
        Dim funcionarios As IEnumerable(Of XElement) = xelement.Elements()

        txtXML.Text = "Lista de Todos os Funcionários :" & vbCrLf
        For Each funcionario In funcionarios
            txtXML.Text = txtXML.Text & funcionario.Element("Nome").Value & vbCrLf
        Next funcionario

    End Sub

3- Como acessar múltiplos elementos usando LINQ to XML

Vamos acessar o nome de todos os funcionários e também o sexo e o ID de cada um deles e exibi-los.

Usando a classe XElement que representa um XML

O método de extensão IEnumerable(Of Element) retorna uma coleção de
atributos de cada elemento na coleção fonte (XElement)

 Private Sub btnAcessarMultiplosElementos_Click(sender As Object, e As EventArgs) Handles btnAcessarMultiplosElementos.Click
     
       Dim xelement As XElement = xelement.Load("..\..\Funcionarios.xml")
       Dim funcionarios As IEnumerable(Of XElement) = xelement.Elements()

        txtXML.Text = "Lista de todos os funcinários com nome, sexo e id :" & vbCrLf
        For Each funcionario In funcionarios
            txtXML.Text = txtXML.Text & funcionario.Element("Nome").Value & " " & funcionario.Element("Sexo").Value & " " 
& funcionario.Element("FunciId").Value & vbCrLf
        Next funcionario
    End Sub

4- Como acessar elementos a partir de um atributo específico usando LINQ to XML

Vamos acessar os detalhes de todos os funcionários do sexo feminino.

Usando a classe XElement que representa um XML
Private Sub btnElementoAtributo_Click(sender As Object, e As EventArgs) Handles btnElementoAtributo.Click
        Dim xelement As XElement = xelement.Load("..\..\Funcionarios.xml")

        Dim funcionarias = _
                           From funci In xelement.Elements("Funcionario") _
                           Where CStr(funci.Element("Sexo")) = "Feminino" _
                           Select funci

        txtXML.Text = "Detalhes das funcionárias:" & vbCrLf
        For Each funcionaria As XElement In funcionarias
            txtXML.Text = txtXML.Text & funcionaria.ToString()
        Next funcionaria
    End Sub

5- Como encontrar um elemento no interior de outro elemento usando LINQ to XML

Vamos acessar os detalhes de todos os funcionários que moram na cidade de Santos.

Usando a classe XElement que representa um XML
Private Sub btnAcharElemento_Click(sender As Object, e As EventArgs) Handles btnAcharElemento.Click
        Dim xelement As XElement = xelement.Load("..\..\Funcionarios.xml")

        Dim enderecos = _
                                  From endereco In xelement.Elements("Funcionario") _
                                  Where CStr(endereco.Element("Endereco").Element("Cidade")) = "Santos" _
                                  Select endereco

        txtXML.Text = "Funcionarios que residem em Santos"
        For Each funci As XElement In enderecos
            txtXML.Text = txtXML.Text & funci.ToString
        Next funci
    End Sub

6- Ordenar elementos usando LINQ to XML

Vamos ordenar os ceps em ordem ascendente.

Usando a classe XElement que representa um XML
Private Sub btnOrdenarElementos_Click(sender As Object, e As EventArgs) Handles btnOrdenarElementos.Click

        Dim xelement As XElement = xelement.Load("..\..\Funcionarios.xml")

        Dim codigos As IEnumerable(Of String) = _
                                            From codigo In xelement.Elements("Funcionario") _
                                            Let cep = CStr(codigo.Element("Endereco").Element("Cep")) _
                                            Order By cep _
                                            Select cep

        txtXML.Text = "Lista ceps Ordenados " & vbCrLf

        For Each codigopostal As String In codigos
            txtXML.Text = txtXML.Text & codigopostal.ToString & vbCrLf
        Next codigopostal
    End Sub

7- Criar e salvar um documento XML para um XMLWriter ou para o disco usando LINQ to XML

A classe XDocument representa um documento XML

O método Save serializa o documento XML para o disco

  Private Sub btnCriaSalvaXML_Click(sender As Object, e As EventArgs) Handles btnCriaSalvaXML.Click

        Dim xDoc As New XDocument(New XDeclaration("1.0", "utf-8", Nothing), _
        New XElement("Funcionarios", _
        New XElement("Funcionario", _
        New XComment("Somente 3 elementos pois é demo"), _
        New XElement("FunciId", "5"), _
        New XElement("Nome", "Miriam"), _
        New XElement("Sexo", "Feminino"))))

        Dim sw As New StringWriter()
        Dim xWrite As XmlWriter = XmlWriter.Create(sw)
        xDoc.Save(xWrite)
        xWrite.Close()

        ' Salva para o disco
        xDoc.Save("C:\dados\MacoratiXML.xml")
        txtXML.Text = "Arquivo salvo."
    End Sub
Arquivo gerado no disco:
<?xml version="1.0" encoding="utf-16"?>
<Funcionarios>
  <Funcionario>
    <!--Somente 3 elementos pois é demo-->
    <FunciId>5</FunciId>
    <Nome>Miriam</Nome>
    <Sexo>Feminino</Sexo>
  </Funcionario>
</Funcionarios>

8- Encontrando um elemento baseado em uma condição com LINQ To XML

Vamos localizar os endereços para o CEP "01200-200":

a-) usando a classe XElement
Private Sub btnProcurarElemento_Click(sender As Object, e As EventArgs) Handles btnProcurarElemento.Click
        Dim xelement As XElement = xelement.Load("..\..\Funcionarios.xml")
        Dim enderecos = From endereco In xelement.Elements("Funcionario")
	                        Where endereco.Element("Endereco").Element("Cep") = "01200-200"
           	             Select endereco

        txtXML.Text = "Numero de endereços localizados : " & enderecos.Count & vbCrLf

        For Each endere As XElement In enderecos
            txtXML.Text = txtXML.Text & endere.ToString & vbCrLf
        Next endere

    End Sub

9- Incluir um novo elemento em tempo de execução

Incluindo um novo elemento : FunciId, Nome e Sexo.

a-) usando a classe XElement
 Private Sub btnNovoElemento_Click(sender As Object, e As EventArgs) Handles btnNovoElemento.Click
        Dim xEle As XElement = XElement.Load("..\..\Funcionarios.xml")

        xEle.Add(New XElement("Funcionario", _
	                              New XElement("FunciId", 5), _
	                              New XElement("Nome", "Maria Rita"), _
	                              New XElement("Sexo", "Feminino")))

        txtXML.Text = "Novo elemento incluido " & vbCrLf
        txtXML.Text = txtXML.Text & xEle.ToString
    End Sub

9- Incluir um atributo para um elemento em tempo de execução

Incluindo um novo atributo : Fone Tipo="Residencial".

a-) usando a classe XElement
 Private Sub btnNovoElemento_Click(sender As Object, e As EventArgs) Handles btnNovoElemento.Click
        Dim xEle As XElement = XElement.Load("..\..\Funcionarios.xml")

        xEle.Add(New XElement("Employee", _
	                              New XElement("FunciId", 5), _
           	                   New XElement("Fone", "23-555-4224", _
                                         New XAttribute("Tipo", "Residencial"))))

        txtXML.Text = "Novo atributo incluido " & vbCrLf
        txtXML.Text = txtXML.Text & xEle.ToString
    End Sub

10- Substituindo o conteúdo de um Element/Elements usando LINQ To XML

Substituindo o valor do Element Pais de "Brasil" para "Republica Federativa do Brasil"

a-) usando a classe XElement
 Private Sub btnNovoElemento_Click(sender As Object, e As EventArgs) Handles btnNovoElemento.Click
      Private Sub btnSubstituirElemento_Click(sender As Object, e As EventArgs) Handles btnSubstituirElemento.Click
        Dim xEle As XElement = XElement.Load("..\..\Funcionarios.xml")

        Dim paises = xEle.Elements("Funcionario").Elements("Endereco").Elements("Pais").ToList()

        For Each cEle As XElement In paises
            cEle.ReplaceNodes("República Federativa do Brasil")
        Next cEle

        txtXML.Text = "Novo(s) Elemento(s) substituido(s) " & vbCrLf
        txtXML.Text = txtXML.Text & xEle.ToString
    End Sub
    End Sub

11- Deletando um Elemento com base em uma condição usando LINQ To XML

Deletando o Elemento "Endereco"

a-) usando a classe XElement
 Private Sub btnDeletaElemento_Click(sender As Object, e As EventArgs) Handles btnDeletaElemento.Click
        Dim xEle As XElement = XElement.Load("..\..\Funcionarios.xml")

        Dim ende = xEle.Elements("Funcionario").ToList()

        For Each addEle As XElement In ende
            addEle.SetElementValue("Endereco", Nothing)
        Next addEle

        txtXML.Text = txtXML.Text & xEle.ToString
    End Sub

12- Removendo um atributo de mais de um Elemento usando LINQ To XML

Remover o atributo "Tipo" do Elemento Fone.

a-) usando a classe XElement
Private Sub btnRemoverAtributo_Click(sender As Object, e As EventArgs) Handles btnRemoverAtributo.Click
        Dim xEle As XElement = XElement.Load("..\..\Funcionarios.xml")

        Dim fone = xEle.Elements("Funcionario").Elements("Fone").ToList()
        For Each pEle As XElement In fone
            pEle.RemoveAttributes()
        Next pEle

        txtXML.Text = txtXML.Text & xEle.ToString

    End Sub

13- Removendo um número de Elementos usando LINQ To XML

Removendo os dois últimos elementos:

a-) usando a classe XElement
    Dim xEle As XElement = XElement.Load("..\..\Funcionarios.xml")

        Dim funcis = xEle.Descendants("Funcionario")
        funcis.Reverse().Take(2).Remove()

        txtXML.Text = txtXML.Text & xEle.ToString

    End Sub

E assim mostramos como podemos realizar diversas tarefas em um documento XML usando LINQ To XML. Lembre-se que para persistir qualquer alteração realizada devemos usar o método Save() como mostramos o item 7.

Pegue o projeto completo aqui: LINQ_To_XML_Operacoes.zip

João 6:38 Porque eu desci do céu, não para fazer a minha vontade, mas a vontade daquele que me enviou.

João 6:39 E a vontade do que me enviou é esta: Que eu não perca nenhum de todos aqueles que me deu, mas que eu o ressuscite no último dia.

João 6:40 Porquanto esta é a vontade de meu Pai: Que todo aquele que vê o Filho e crê nele, tenha a vida eterna; e eu o ressuscitarei no último dia.

             Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter

Referências:


José Carlos Macoratti