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:
5 TextBox : txtCodigoProduto, txtNomeProduto, txtPreco, txtEstoque e txtDescricao
1 Button : btnLocalizar , Text = Localizar
1 LisbBox : lbProdutos
4 Button : btnSalvar, btnNovo, btnCarregar e btnListarProdutos
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: