C# - Salvando, Lendo e consultando informações em um arquivo XML (revisão)


 Neste artigo eu vou recordar como podemos salvar, ler e consultar informações em um arquivo XML usando a linguagem C# usando o Visual Studio 2013 for Windows Desktop.

Nem sempre você vai precisar de um banco de dados relacional para guardar informações.

Os bancos de dados relacionais são uma das melhores opções quando o objetivo é armazenar e recuperar informações, mas existem situações na qual você pode usar outro recurso para este objetivo.

Se o seu caso não requer a utilização de um banco de dados, considere armazenar informações em arquivos XML. Eles são simples e fáceis de tratar e utilizar, usando os recursos da plataforma .NET.

As perspectivas do armazenamento de dados no formato XML são surpreendentes, e, até mesmo os Data WareHouses já estão armazenando informações no formato XML.

Um data warehouse (ou armazém de dados, ou depósito de dados no Brasil) é um sistema de computação utilizado para armazenar informações relativas às atividades de uma organização em bancos de dados, de forma consolidada. O desenho da base de dados favorece os relatórios, a análise de grandes volumes de dados e a obtenção de informações estratégicas que podem facilitar a tomada de decisão. (http://pt.wikipedia.org/wiki/Data_Warehouse)

Os namespaces System.Xml , System.Xml.Linq e System.Data.Linq fornecem um arsenal de classes que podemos usar para tratar informações em arquivos XML e neste projeto iremos usar algumas dessas classes.

Recursos usados:

Criando o projeto no Visual Studio 2013 Express for Windows Desktop

Abra o VS Express 2013 for Windows Desktop e clique em New Project;

A seguir selecione a linguagem Visual C# e o template Windows Forms Application;

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

Vamos agora criar uma pasta chamada Dados em nosso projeto para conter nosso arquivo XML chamado Produtos.xml.

Selecione o projeto e no menu PROJECT clique em New Folder informando o nome Dados;

A seguir clique com o botão direito do mouse sobre a pasta Dados e a seguir clique em Add New Item;

Selecione o template XML File e informe o nome Produtos.xml e defina a seguinte estrutura para o arquivo XML:

Vamos criar também uma classe chamada Produto que irá representar um produto. Para isso selecione a pasta Dados e no menu PROJECT clique em Add Class;

Selecione o template Class e informe o nome Produto.cs digitando a seguir o código abaixo nesta classe:

public class Produto
{
        public int Codigo { get; set; }
        public string Nome { get; set; }
        public decimal Preco { get; set; }
        public int Estoque { get; set; }
        public string Descricao { get; set; }
 }

A seguir selecione o  formulário padrão form1.vb e inclua, a partir da ToolBox, os seguintes controles:

Disponha os controles no formulário conforme a figura abaixo:

Vamos agora implementar as funcionalidades do nosso projeto.

Iniciando com a definindo dos namespaces usados no projeto:

using System;
using System.Data;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Linq;
using XML_BD.Dados;
using System.Linq;

E coma definição da variável caminho que retorna o caminho do diretório base que o resolvedor do Assembly usa para sondar os assemblies.

No nosso exemplo o retorno será : = "C:\\_csharp\\XML_BD\\XML_BD\\bin\\Debug\\"

String caminho = AppDomain.CurrentDomain.BaseDirectory;
Vamos usar essa variável para obter o caminho do arquivo Produtos.xml na pasta Dados do projeto usando o método estático CaminhoDadosXML() cujo código vemos abaixo:
public static string CaminhoDadosXML(string caminho)
 {
       if (caminho.IndexOf("\\bin\\Debug") != 0)
       {
           caminho = caminho.Replace("\\bin\\Debug", "");
      }
     return caminho;
 }

O retorno será o caminho : "C:\\_csharp\\XML_BD\\XML_BD\"

Quando o formulário é carregado o evento Load do mesmo é executado e neste momento desabilitamos o botão Salvar:

 private void Form1_Load(object sender, EventArgs e)
 {
            btnSalvar.Enabled = false;
 }

1 - Criando um novo elemento <Produto> no XML

Para criar um novo item no arquivo XML o usuário deve clicar no botão Novo cujo código é visto a seguir:

private void btnNovo_Click(object sender, EventArgs e)
 {
            LimparTextBox(this);
            btnSalvar.Enabled = true;
            txtCodigoProduto.Text = Convert.ToString(GetRandomNumber(1, 9999));
            txtNomeProduto.Focus();
 }

Este código limpa todos os controles TextBox do formulário e habilita o botão Salvar. A seguir é gerado um número aleatório para o código do projeto e o foco é posto na caixa de texto txtNomeProduto.

A seguir temos o código da rotina LimparTextBox() que limpa os controles TextBox:

 void LimparTextBox(Control con)
 {
      foreach (Control c in con.Controls)
      {
                if (c is TextBox)
                    ((TextBox)c).Clear();
                else
                    LimparTextBox(c);
     }
 }

E abaixo o código da rotina GetRandomNumber() que gera um número aleatório:

        private static readonly Random getrandom = new Random();
        private static readonly object syncLock = new object();
        public static int GetRandomNumber(int min, int max)
        {
            lock (syncLock)
            { // sincroniza
                return getrandom.Next(min, max);
            }
        }

2 - Salvando os dados do novo elemento <Produto> no XML

Após digitar os dados no formulário o usuário deverá clica no botão Salvar para persistir as informações do produto no arquivo Produtos.xml.

O código do evento Click do botão Salvar é dado a seguir:

private void btnSalvar_Click(object sender, EventArgs e)
 {
       try
       {
                using (DataSet dsResultado = new DataSet())
                {
                    dsResultado.ReadXml(CaminhoDadosXML(caminho) + @"Dados\Produtos.xml");
                    if (dsResultado.Tables.Count == 0)
                    {
                        //cria uma instância do Produto e atribui valores às propriedades
                        Produto oProduto = new Produto();
                        oProduto.Codigo = Convert.ToInt32(txtCodigoProduto.Text);
                        oProduto.Nome = txtNomeProduto.Text;
                        oProduto.Preco = Convert.ToDecimal(txtPreco.Text);
                        oProduto.Estoque = Convert.ToInt32(txtEstoque.Text);
                        oProduto.Descricao = txtDescricao.Text;
                        XmlTextWriter writer = new XmlTextWriter(CaminhoDadosXML(caminho) + @"Dados\Produtos.xml", System.Text.Encoding.UTF8);
                        writer.WriteStartDocument(true);
                        writer.Formatting = Formatting.Indented;
                        writer.Indentation = 2;
                        writer.WriteStartElement("Produtos");
                        writer.WriteStartElement("Produto");
                        writer.WriteStartElement("Codigo");
                        writer.WriteString(oProduto.Codigo.ToString());
                        writer.WriteEndElement();
                        writer.WriteStartElement("Nome");
                        writer.WriteString(oProduto.Nome);
                        writer.WriteEndElement();
                        writer.WriteStartElement("Preco");
                        writer.WriteString(oProduto.Preco.ToString());
                        writer.WriteEndElement();
                        writer.WriteStartElement("Estoque");
                        writer.WriteString(oProduto.Estoque.ToString());
                        writer.WriteEndElement();
                        writer.WriteStartElement("Descricao");
                        writer.WriteString(oProduto.Descricao);
                        writer.WriteEndElement();
                        writer.WriteEndElement();
                        writer.WriteEndDocument();
                        writer.Close();
                        dsResultado.ReadXml(CaminhoDadosXML(caminho) + @"Dados\Produtos.xml");
                    }
                    else
                    {
                        //inclui os dados no DataSet
                        dsResultado.Tables[0].Rows.Add(dsResultado.Tables[0].NewRow());
                        dsResultado.Tables[0].Rows[dsResultado.Tables[0].Rows.Count - 1]["Codigo"] = txtCodigoProduto.Text;
                        dsResultado.Tables[0].Rows[dsResultado.Tables[0].Rows.Count - 1]["Nome"] = txtNomeProduto.Text.ToUpper();
                        dsResultado.Tables[0].Rows[dsResultado.Tables[0].Rows.Count - 1]["Preco"] = txtPreco.Text;
                        dsResultado.Tables[0].Rows[dsResultado.Tables[0].Rows.Count - 1]["Estoque"] = txtEstoque.Text;
                        dsResultado.Tables[0].Rows[dsResultado.Tables[0].Rows.Count - 1]["Descricao"] = txtDescricao.Text;
                        dsResultado.AcceptChanges();
                        //--  Escreve para o arquivo XML final usando o método Write
                        dsResultado.WriteXml(CaminhoDadosXML(caminho) + @"Dados\Produtos.xml", XmlWriteMode.IgnoreSchema);
                    }
                    //exibe os dados no datagridivew 
                    dgvDados.DataSource = dsResultado.Tables[0];
                    MessageBox.Show("Dados salvos com sucesso.");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Erro " + ex.Message, "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error);
       }
   }

Este código usa o método ReadXml() do objeto DataSet para ler os dados do arquivo XML e a seguir usa a classe XmlTextWriter para escrever no arquivo XML os dados informados pelo usuário no formulário.

A classe XmlTextWriter fornece uma maneira rápida de gerar streams ou arquivos contendo dados XML em conformidade com a W3C Extensible Markup Language (XML) 1.0. Ela contém diversos métodos e propriedades que vão fazer todo o trabalho pesado para você na prática.

Para usar esta classe basta você usar os namespace System.Xml e criar um novo objeto XmlTextWriter; em seguida basta ir incluindo os elementos Xml que você deseja criar. A classe comporta métodos para incluir cada tipo de elemento em um arquivo XML. A seguir temos alguns destes métodos:

Método Descrição
WriterStartDocument Escreve a declaração XML indicativa da versão XML  (version  "1.0")
WriteEndDocument Fecha qualquer elemento ou atributo aberto.
Close Fecha o stream.
WriteDocType Escreve a declaração DOCTYPE com o nome especificado e atributos opcionais.
WriterStartElement Escreve tag de inicio definida.
WriteEndElement Fecha um elemento.
WriteFullEndElement Fecha um elemento.
WriteElementString Escreve um elemento contendo um valor string.
WriteStartAttribute Escreve o início de um atributo.
WriteEndAttribute Fecha a chamada anterior de WriteStarttAttribute.
WriterString Escreve uma string.
WriteAttributes Escreve um atributo com um valor específico..
WriteCData Escreve um bloco <![CDATA[...]]> contendo o texto especificado..
WriteComment Escreve um comentário <!--...--> contendo o texto especificado.
WriteWhitespace Escreve um espaço.
WriteProcessingInstruction Escreve uma instrução de processamento com um espaço entre o nome e o texto seguido de <?name text?>.

3 - Carregando dados do XML e exibindo no DataGridView

Para carregar dados do arquivo XML e exibir no controle DataGridView - dgvDados - o usuário clicar no botão Carregar - que tem o código abaixo:

 private void btnCarregar_Click(object sender, EventArgs e)
 {
            GetDados();
 }

Neste código apenas chamamos a rotina GetDados() que possui o código a seguir:

public void GetDados()
 {
            try
            {
                DataSet dsResultado = new DataSet();
                dsResultado.ReadXml(CaminhoDadosXML(caminho) +  @"Dados\Produtos.xml");
                if (dsResultado.Tables.Count != 0)
                {
                    if (dsResultado.Tables[0].Rows.Count > 0)
                    {
                        dgvDados.DataSource = dsResultado.Tables[0];
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
   }

Neste código usamos o método ReadXML() do DataSet para obter os dados do arquivo Produtos.xml e preencher o DataSet exibindo-o a seguir no DataGridView.

4 - Obtendo uma lista de Produtos e exibindo no ListBox

Para obter uma lista de produtos e exibir os dados desejados no controle ListBox o usuário clica no botão - Listar Produtos - cujo código vemos abaixo:

 private void btnListarProdutos_Click(object sender, EventArgs e)
   {
       XDocument doc = XDocument.Load((CaminhoDadosXML(caminho) +  @"Dados\Produtos.xml"));
       var prods = from p in doc.Descendants("Produto")
                        select new
                        {
                            NomeProduto = p.Element("Nome").Value,
                            PrecoProduto = p.Element("Preco").Value,
                        };
            foreach (var p in prods)
            {
                lbProdutos.Items.Add( p.NomeProduto + " " + p.PrecoProduto);
            }
 }

O código realiza uma consulta LINQ no arquivo XML obtendo os elementos <Produto> e extrai as informações do Nome e Preço exibindo-as no ListBox.

5 - Localizando um produto pelo código e exibindo no formulário

Podemos localizar um produto pelo seu código clicando no botão Localizar() que tem o seguinte código:

private void btnLocalizarProduto_Click(object sender, EventArgs e)
  {
            // cria a consulta
        var prods = from p in XElement.Load((CaminhoDadosXML(caminho) + @"Dados\Produtos.xml")).Elements("Produto")
                        where p.Element("Codigo").Value == txtCodigoProduto.Text
                        select new
                        {
                            NomeProduto = p.Element("Nome").Value,
                            PrecoProduto = p.Element("Preco").Value,
                            EstoqueProduto = p.Element("Estoque").Value,
                            DescricaoProduto = p.Element("Descricao").Value,
                        };
            // Executa a consulta
            foreach (var produto in prods)
            {
               txtNomeProduto.Text = produto.NomeProduto;
                txtPreco.Text = produto.PrecoProduto;
                txtEstoque.Text = produto.EstoqueProduto;
                txtDescricao.Text = produto.DescricaoProduto;
            } 
  }

Este código realiza um consulta LINQ pelo elemento <Codigo> usando o valor do código do produto informado. A seguir extrai as informações e exibe nas caixas de texto do formulário.

6 - Selecionando uma linha do DataGridView e exibindo os valores no formulário

Após carregar o controle DataGridView com dados do arquivo Produtos.xml podemos selecionar uma linha específica e exibir os seus detalhes nas caixas de texto do formulário.

Para isso usamos o evento CellClick do DataGridView obtendo os valores das células da linha selecionada e exibindo-os nas caixas de texto. O código é dado a seguir:

 private void dgvDados_CellClick(object sender, DataGridViewCellEventArgs e)
 {
            try
            {
                //obtem o valor das células do grid
                txtCodigoProduto.Text  = dgvDados.CurrentRow.Cells[0].Value.ToString();
                txtNomeProduto.Text = dgvDados.CurrentRow.Cells[1].Value.ToString();
                txtPreco.Text = dgvDados.CurrentRow.Cells[2].Value.ToString();
                txtEstoque.Text = dgvDados.CurrentRow.Cells[3].Value.ToString();
                txtDescricao.Text  = dgvDados.CurrentRow.Cells[4].Value.ToString();
            }
            catch
            { }
  }

Executando o projeto, incluindo algumas informações, carregando e listando os produtos teremos o seguinte resultado:

Pegue o projeto completo aqui: XML_BD.zip

    Porque nem mesmo seus irmãos criam nele.
    Disse-lhes, pois, Jesus: Ainda não é chegado o meu tempo, mas o vosso tempo sempre está pronto.
    O mundo não vos pode odiar, mas ele me odeia a mim, porquanto dele testifico que as suas obras são más.
   
João 7:5-7

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