[Desenvolvimento] Como ler dados de documentos XML usando LINQ como forma de consulta

5

xml_51Olá pessoal, tudo bom?

Uma dúvida recorrente dos DEVs Windows Phone é sobre a “leitura” de dados a partir de documentos XML e em especial aqueles que são oriundos de webservices ou chamadas REST, apesar de isso ser basicamente a mesma coisa quando os arquivos XML são locais à APP.

Para exemplificar esse post vou utilizar o retorno XML do webservice https://wcf-concursos.azurewebsites.net/Consulta.svc/xml/professor-etec, que devolve a seguinte estrutura de dados:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 
<ArrayOfProcessoSeletivo xmlns="https://schemas.datacontract.org/2004/07/wcf_dados.Modelo" xmlns:i="https://www.w3.org/2001/XMLSchema-instance">
 <ProcessoSeletivo>
   <Cidade>Adamantina</Cidade>
   <DataFimInscricao>2015-01-27T00:00:00</DataFimInscricao>
   <Link>https://cpssitevm.cloudapp.net/dgps/selecoespublicas/ProcessoSeletivo/055/055/01/2015/055-01-2015-ps-27-01-2015.pdf</Link>
   <NomeUnidade>Escola Técnica Estadual Professor Eudécio Luiz Vicente</NomeUnidade>
   <NumeroAviso>055/01/2015</NumeroAviso>
   <Unidade>55</Unidade>
 </ProcessoSeletivo>
 <ProcessoSeletivo>
   <Cidade>Assis</Cidade>
   <DataFimInscricao>2015-02-11T00:00:00</DataFimInscricao>
   <Link>https://cpssitevm.cloudapp.net/dgps/selecoespublicas/ProcessoSeletivo/095/095/02/2015/095-02-2015-ps.pdf</Link>
   <NomeUnidade>Escola Técnica Estadual Pedro D'Arcádia Neto</NomeUnidade>
   <NumeroAviso>095/02/2015</NumeroAviso>
   <Unidade>95</Unidade>
 </ProcessoSeletivo>
......

De posse da estrutura do XML, uma das primeiras coisas a observar é se o documento possui o atributo xmlns. Caso possua, será necessário utilizarmos a classe XNamespace para referenciar seus elementos filhos, situação que nesse exemplo iremos observar.

Declarando uma classe para representar os dados que se deseja obter do documento XML

Para facilitar o trabalho de recuperação dos dados do documento XML, indico a criação de uma classe para representação das informações desejadas. No exemplo, a classe (Escola.cs) será utilizada como base para montar uma lista com todos os nomes de escolas e cidades representadas na estrutura do XML.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
namespace LeituraXML
{
  public class Escola
  {
     private string _cidade;
     public string Cidade
     {
       get { return _cidade; }
       set { _cidade = value; }
     }
 
     private string _nomeEscola;
     public string NomeEscola
     {
       get { return _nomeEscola; }
       set { _nomeEscola = value; }
     }
  }
}

Montando o layout da aplicação XAML

Abaixo demonstro o trecho de código do documento XAML responsável por montar a interface da aplicação. Em especial observe o elemento ListBox e seu respectivo DataTemplate. Reparem que os mesmos coincidem com a estrutura da classe Escola.cs demonstrada acima.

exemplo-xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
...
<StackPanel x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
  <TextBlock Text="Lista de Escolas" Style="{StaticResource PhoneTextAccentStyle}" />
  <TextBlock Text="Fazendo download dos dados. Aguarde..."
             Margin="0,50,0,0" Name="txbAguarde"
             HorizontalAlignment="Center" />
  <ProgressBar IsIndeterminate="True" Name="pgbDownload" />
 
  <ListBox Name="lbEscolas" Height="Auto" MaxHeight="570">
    <ListBox.ItemTemplate>
      <DataTemplate>
        <StackPanel Orientation="Vertical">
          <TextBlock FontSize="30" Text="{Binding NomeEscola}" />
          <TextBlock Text="{Binding Cidade}" />
        </StackPanel>
      </DataTemplate>
    </ListBox.ItemTemplate>
  </ListBox>
</StackPanel>
...
...

Obtendo o documento XML e recuperando seus dados a partir de uma consulta LINQ

Como o documento XML que iremos tratar nesse exemplo é oriundo de uma URL, utilizaremos a classe WebClient para realizar o download do mesmo. Para mais detalhes sobre o uso do WebClient, acesse o post Classe WebClient para download de conteúdo da web no formato de dados binários ou strings.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
...
namespace LeituraXML
{
  public partial class MainPage : PhoneApplicationPage
  {
    //Declaração de um WebClient para download do arquivo XML resultante da chamada REST
    WebClient wc = new WebClient();
 
    // Construtor
    public MainPage()
    {
      InitializeComponent();
 
      //Toda vez que o WebClient atualiza seu status de download o método DownloadProgressChanged será executado
      wc.DownloadProgressChanged += wc_DownloadProgressChanged;
      //Ao terminar o download do conteúdo o método DownloadStringCompleted será executado
      wc.DownloadStringCompleted += wc_DownloadStringCompleted;
      //O método DownloadStringAsync inicia o download do conteúdo especificado pela Uri
      wc.DownloadStringAsync(new Uri("https://wcf-concursos.azurewebsites.net/Consulta.svc/xml/professor-etec"), "conteudo");
    }
 
    void wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
    {
      //Esse if é utilizado para ter certeza que iremos processar apenas o conteúdo específico do WebClient em questão
      if (e.UserState == "conteudo")
         //O código abaixo exibe no TextBlock txtAguarde o andamento do download do documento XML
         txbAguarde.Text = e.BytesReceived.ToString() + "/" + e.TotalBytesToReceive.ToString();
    }
 
    void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
    {
      //Desligando o ProgressBar
      pgbDownload.IsIndeterminate = false;
      //Caso não tenha ocorrido nenhum problema ou o processo tenha sido cancelado
      if (e.Error == null && !e.Cancelled)
      {
        //Retirando o status de progressão do download da tela
        pgbDownload.Visibility = System.Windows.Visibility.Collapsed;
        txbAguarde.Visibility = System.Windows.Visibility.Collapsed;
 
        /****************************************************************
         * DECLARAÇÃO DOS ELEMENTOS NECESSÁRIOS PARA RECUPERAÇÃO DOS DADOS
         * REPARE QUE OS DADOS DO DOCUMENTO ESTÃO NO OBJETO dados E QUE
         * DECLARAMOS UM OBJETO ns PARA REPRESENTAÇÃO DO NAMESPACE DO
         * DOCUMENTO XML. O NAMESPACE NÃO SERIA NECESSÁRIO SE O DOCUMENTO
         * XML NÃO TIVESSE O ATRIBUTO xmlns EM SUA DECLARAÇÃO.
        */
        XElement dados = XElement.Parse(e.Result);
        XNamespace ns = "https://schemas.datacontract.org/2004/07/wcf_dados.Modelo";
 
        //Recuperando os dados desejados via consulta LINQ
        var escolas = (from d in dados.Descendants(ns + "ProcessoSeletivo")
                      orderby d.Element(ns + "Cidade").Value
                      select new Escola
                          {
                            NomeEscola = d.Element(ns + "NomeUnidade").Value,
                            Cidade = d.Element(ns + "Cidade").Value
                          }).ToList();
        //Indicando a origem dos dados para o ListBox
        lbEscolas.ItemsSource = escolas;
      }
      //Tratamento de erros
      else
        txbAguarde.Text = e.Error.InnerException.ToString();
    }
...
...

Espero ter ajudado e aproveito para agradecer meus ex-alunos e colegas Renan D. Buarraj e Lucas Azambuja pelas dicas e pelo webservice.

Grande abraço,

Eduardo Henrique Rizo (@eduardorizo)

MCP

Posts Relacionados: 

Fonte: Blog do Eduardo H. Rizo

Share.

About Author

Bacharel em Ciência da Computação pela FIPP/Unoeste, Pós-Graduado em Desenvolvimento de Sistemas Web, Segurança da Informação e Avaliação do Ensino e da Aprendizagem, Professor universitário e responsável pelo setor de desenvolvimento de sistemas web da Universidade do Oeste Paulista. MCP e MCPS pela Microsoft e nas horas vagas dedica um pouco do seu tempo escrevendo posts técnicos sobre desenvolvimento de sistemas web, windows phone, gerenciamento de servidores e outros assuntos para a comunidade.

  • Matheus De Sousa Bernardo

    JSON não é melhor que XML?

    • Eduardo Henrique Rizo

      Depende da aplicação Matheus…

      • Matheus De Sousa Bernardo

        Tem como exemplificar. pelo o que eu tinha entendido. JSON ler mais rápido.

        • Eduardo Henrique Rizo

          Matheus, JSON dentre outras coisas também pode ser entendido como uma forma para troca de dados entre aplicações e C# também conta com classes para serialização e deserializaçao do conteúdo e nos enquanto DEVs que estamos consumindo esses dados devemos estar preparados para quaisquer situações. De qualquer forma vou bolar um outro post para tratar de JSON e WP. OK?

          • Matheus De Sousa Bernardo

            Claro, por isso fico agradecido pelo post. agregou ao meu conhecimento, estou apenas começando no desenvolvimento mobile. e quanto mais conhecimento melhor. Obrigado Eduardo!