XDocument - Manipulando arquivos XML no .NET
Veja neste artigo uma breve introdução ao XML e como usar o mesmo no .NET, veremos como manipula documentos com este formato. Usaremos a classe XDocument para fazer esta manipulação, faremos um pequeno exemplo de como é a estrutura de um XML e logo na sequencia iremos ver como consumir este mesmo XML usando uma aplicação.
Você não gostou da qualidade deste conteúdo?
(opcional) Você gostaria de comentar o que não lhe agradou?
Um dos formatos de arquivos mais utilizados para armazenamento de informações é, sem dúvidas, o XML, por ser um padrão compatível com a maioria das linguagens comerciais da atualidade. Um exemplo comum disso é a Nota Fiscal Eletrônica, onde os dados são enviados e recebidos neste formato, seguindo o padrão especificado pelos órgãos competentes.
O .NET Framework, como boa ferramenta que é, nos fornece uma série de recursos para trabalhar com esse tipo de arquivo, permitindo importar, exportar e consultar informações no formato XML de forma simples.
Apesar de existir mais de uma classe para esse fim, veremos neste artigo como utilizar a classe XDocument, contida no namespace System.Linq.Xml, para importar, consultar e alterar um arquivo XML de estrutura previamente conhecida.
A Listagem 1 exibe o conteúdo do arquivo pessoas.xml, utilizado nos exemplos deste artigo.
Listagem 1: Arquivo pessoas
<?xml version="1.0" encoding="UTF-8"?> <pessoas> <pessoa id="1" nome="João"/> <pessoa id="2" nome="Maria"/> <pessoa id="3" nome="José"/> </pessoas>
A estrutura é bastante simples, uma vez que objetivo deste artigo é apenas apresentar os principais métodos e propriedades da class supracitada.
Vamos então criar uma aplicação Windows forms e configurar o form principal de forma igual ou semelhante ao que ilustra a Figura 1.

Figura 1: Layout do form principal
Temos um DataGridView (dgvDados) e dois TextBoxes (txtID e txtNome) que serão utilizados para exibição e alteração dos dados.
O botão salvar funcionará da seguinte forma: caso o campo txtID contenha o ID de uma pessoa já cadastrada, o nome desta será alterado, caso contrário, um novo registro será adicionado à lista.
Para manipularmos os itens do arquivo de forma mais clara, usaremos uma classe Pessoa, conforme mostra a Listagem 2.
Listagem 2: Classe Pessoa
class Pessoa
{
string id;
string nome;
public string Id
{
get { return id; }
set { id = value; }
}
public string Nome
{
get { return nome; }
set { nome = value; }
}
}
Temos apenas dois campos simples, da mesma forma que no arquivo XML.
Carregando o XML
Carregar o XML é, sem dúvida, a parte mais simples deste artigo. A classe XDocument dispõe de várias formas para realizar esta ação, das quais utilizaremos uma, carregando o documento a partir de seu nome. Primeiramente devemos declarar um objeto XDocument como global, seguindo o exemplo da Listagem 3. Este objeto será instanciado no evento Load do form, visto mais adiante.Listagem 3: Declaração do objeto XDocument
XDocument doc;
Escreveremos então um método para carregar este arquivo e montar uma lista de Pessoas e exibir essa lista no grid. Devemos, em seguida, invocar este evento no evento Load do form.
Listagem 4: Carregando XML e exibindo os dados
public void CarregarXML()
{
XDocument doc = XDocument.Load(@"C:\pessoas.xml");
List<Pessoa> pessoas = new List<Pessoa>();
foreach (XElement x in doc.Element("pessoas").Elements())
{
Pessoa p = new Pessoa()
{
Id = x.Attribute("id").Value,
Nome = x.Attribute("nome").Value
};
pessoas.Add(p);
}
dgvDados.DataSource = pessoas;
}
Lemos todos os elementos contidos no elemento “pessoas” do XML e, para cada item lido, utilizamos seus atributos para preencher um objeto do tipo Pessoa e adicioná-lo à lista. Ao fim, definimos esta lista como DataSource do grid dgvDados. Com isso, teremos todos os registros listados no grid, como pode ser visto na Figura 2.

Figura 2: Listados os itens do arquivo XML
O próximo passo é programar o evento SelectionChanged do grid para exibir os dados do registro selecionado nos textboxes. A Listagem 4 apresenta o código utilizado para realizar esta ação.
Listagem 4: Exibição dos dados nos textboxes
private void dgvDados_SelectionChanged(object sender, EventArgs e)
{
if (dgvDados.SelectedRows.Count > 0)
{
txtId.Text = dgvDados.SelectedCells[0].Value.ToString();
txtNome.Text = dgvDados.SelectedCells[1].Value.ToString();
}
}
É importante que os dados sejam exibidos nos textboxes, pois utilizaremos estes valores para programar o evento Click do botão salvar, o que é mostrado na Listagem 5 a seguir.
Alterando e adicionando elementos
Listagem 5: Evento Click do botão Salvar
private void button1_Click(object sender, EventArgs e)
{
if (doc.Element("pessoas").Elements().Where(x => x.Attribute("id").Value.Equals(txtId.Text)).Count() > 0)
{
XElement ele = doc.Element("pessoas").Elements().Where(x => x.Attribute("id").Value.Equals(txtId.Text)).First();
ele.Attribute("nome").SetValue(txtNome.Text);
doc.Save(@"C:\pessoas.xml");
CarregarXML();
}
else
{
XElement ele = new XElement("pessoa");
ele.Add(new XAttribute("id", txtId.Text));
ele.Add(new XAttribute("nome", txtNome.Text));
doc.Element("pessoas").Add(ele);
doc.Save(@"C:\pessoas.xml");
CarregarXML();
}
}
Podemos agora executar a aplicação e testar. Primeiramente selecionando uma linha no grid, alterando o nome e então clicando no botão Salvar. O registro selecionado deve ser alterado e o arquivo salvo. Outro teste pode ser realizado digitando um Id inexistente, um Nome e clicando também no botão Salvar. O registro deve ser adicionado à lista e salvo no arquivo.
Como foi visto, manipular arquivos XML torna-se uma tarefa simples quando utilizamos os recursos fornecidos pelo framework. Com algumas poucas linhas de código autodescritivas, pudemos carregar um arquivo XML, alterar e inserir novos elementos e atributos em sua estrutura e salvá-lo ao fim.
Com isso finalizamos este breve artigo. Espero que o conteúdo possa ser útil.
Até a próxima.
Joel Rodrigues
Técnico em Informática - IFRN Cursando Bacharelado em Ciências e Tecnologia - UFRN Programador .NET/C# e Delphi há mais de 3 anos, já tendo trabalhado com Webservices, WPF, Windows Phone 7 e ASP.NET, possui ainda conhecimentos em HTML, CSS e Javascript (jQuery). Certificado como Microsoft Special...
8 COMENTÁRIOS
Estou acostumado a gerar e ler xml no meu velho sistema legado, em Clipper.
Tanto pra nfe, quanto pra troca de dados com outros sistemas.
Iniciei o desenvolvimento em C# e um primeiro programa já está com sua nova versão gráfica a venda.
Uma das coisas que eu gostaria na nova versão é justamente poder ler os xmls que meu velho sistema já gera automaticamente.
Então lá vai finalmente minha duvida:
Na estrutura abaixo, como seria a leitura de cada campo ? É que o normal nos meus xmls eh ter uma tag para cada campo da tabela.
<?xml version="1.0" encoding="UTF-8"?>
<pessoas>
<pessoa seq="1">
<id>"10"</id>
<nome>"João"</nome>
</pessoa>
<pessoa seq="2">
<id>"13"</id>
<nome>"José"</nome>
</pessoa>
<pessoa seq="3">
<id>"20"</id>
<nome>"Julio"</nome>
</pessoa>
</pessoas>
Obrigado desde já pela resposta.
Bem, repare que quando eu monto a lista de Pessoas, eu atribuo os valores das propriedades do objeto buscando o conteúdo do atributo de cada item. No seu caso, ao invés de um atributo, será outro elemento, certo?
A diferença é pequena, no lugar de x.Attribute("id").Value, você usará x.Element("id").Value.
Teste e veja se consegue. Persistindo a dúvida, pode voltar a me procurar.
Um abraço.
Infelizmente eu só a vi hoje.
Eu acabei fazendo a leitura usando XmlDocument, XmlNodeList e pegando via InnerText.
Depois vou testar da maneira que vc explicou.
Obrigado mais uma vez.
Saudações
Boa sorte em seus projetos.
Estou iniciando c# e estou "apanhando" um pouco para ler a seguinte estrutura:
<table name="load">
<r>
<c name="c0">34224</c>
<c name="c1">MENSAL</c>
<c name="c2">PAUL</c>
<c name="c3">12/3/2013 08:00:00</c>
<c name="c4">PRT</c>
<c name="c5">10</c>
<c name="c6">EA</c>
</r>
<r>
<c name="c0">34225</c>
<c name="c1">BiMESTRAL</c>
<c name="c2">JOHN</c>
<c name="c3">12/3/2013 10:00:00</c>
<c name="c4">PRC</c>
<c name="c5">10</c>
<c name="c6">MP</c>
</r>
<r>
<c name="c0">34226</c>
<c name="c1">ANUAL</c>
<c name="c2">JULLY</c>
<c name="c3">13/3/2013 08:00:00</c>
<c name="c4">PRTR</c>
<c name="c5">10</c>
<c name="c6">GM</c>
</r>
</table>
nesse caso como eu acessaria os valores?
Desde já agradeço a ajuda.
Paulo
Primeiramente desculpe pela demora em responder, mas só agora tive acesso a um computador.
No seu caso, o documento tem o elemento raiz "table" e dentro dele, vários elementos "r". Dentro de cada elemento "r", tem-se vários elementos "c".
Com este código você consegue listar todos os valores:
----------
foreach (XElement r in doc.Element("table").Elements())
{
foreach (XElement c in r.Elements())
{
Console.Write(c.Value + " | ");
}
Console.WriteLine();
}
Console.ReadLine();
----------
Qualquer dúvida, é só falar.
METODO:
public void CarregarXML()
{
XDocument doc = XDocument.Load(@"C:\Exemplo.xml");
List<classFuncionario> funcionarios = new List<classFuncionario>();
foreach (XElement x in doc.Element("funcionarios").Elements())
{
foreach (XElement c in x.Elements())
{
classFuncionario f = new classFuncionario()
{
Id = c.Element("id").Value,
Nome = c.Element("nome").Value
};
funcionarios.Add(f);
}
}
dgvDados.DataSource = funcionarios;
}
Arquivo XML:
<funcionarios>
<funcionario>
<id>1</id>
<nome>Joao da Silva</nome>
<endereco>Rua Dom Pedro</endereco>
<telefone>
<celular>(43)9134-8821</celular>
<fixo>
<residencial>(43)3258-9877</residencial>
<comercial>(43)3354-7865</comercial>
</fixo>
<fax>(43)3354-7864</fax>
</telefone>
<cpf>12365487612</cpf>
<rg>119459874</rg>
<sexo>Masculino</sexo>
<cidade>Londrina</cidade>
<estado>Parana</estado>
<cep>82300000</cep>
<cargo>Mecanico</cargo>
<salario>2.300</salario>
<estcivil>
<casado>
<qtdfilhos>02</qtdfilhos>
</casado>
</estcivil>
<portdeficiencia>Nao</portdeficiencia>
<valeref>400</valeref>
<valetransp>250</valetransp>
<plnsaude>Unimed</plnsaude>
<plnodonto>Indefinido</plnodonto>
</funcionario>
<funcionario>
<id>2</id>
<nome>Pedro Batista</nome>
<endereco>Rua 19 Dezembro</endereco>
<telefone>
<celular>(43)9234-8765</celular>
<fixo>
<residencial>(43)3258-4398</residencial>
<comercial>(43)3233-3245</comercial>
</fixo>
<fax>(43)3334-0987</fax>
</telefone>
<cpf>12365487345</cpf>
<rg>654459874</rg>
<sexo>Masculino</sexo>
<cidade>Cambe</cidade>
<estado>Parana</estado>
<cep>82400000</cep>
<cargo>Eletricista</cargo>
<salario>2.500</salario>
<estcivil>
<solteiro></solteiro>
</estcivil>
<portdeficiencia>Nao</portdeficiencia>
<valeref>400</valeref>
<valetransp>250</valetransp>
<plnsaude>Unimed</plnsaude>
<plnodonto>Indefinido</plnodonto>
</funcionario>
</funcionarios>
Bem, no seu caso, tem um foreach a mais aí. Você precisa percorrer apenas os elementos <funcionario> e dentro de cada um, acessar os elementos filhos com as propriedades. Veja um exemplo (modificado).
----------
foreach (XElement x in doc.Element("funcionarios").Elements())
{
classFuncionario f = new classFuncionario()
{
Id = x.Element("id").Value,
Nome = x.Element("nome").Value
};
funcionarios.Add(f);
}
----------
Qualquer dúvida, é só falar.




