VB.NET  2005 - Lendo XML com a classe XMLReader


Dentre as inúmeras novidades da nova versão da ADO.NET o suporte básico a XML  agora é oferecido também pelo objeto DataTable,  antes isto era um previlégio do DataSet. O DataTable agora possui os seguintes métodos ReadXml , ReadXmlSchema, WriteXml e WriteXmlSchema.

O SQL Server 2005 suporta XML nativamente. Sabendo disto podemos usar este recurso para obter registros de uma fonte de dados. O resultado de uma declaração SELECT pode ser retornado como XML pelo uso da cláusula FOR XML AUTO.

Para retornar XML diretamente do SQL Server podemos usar o método ExecuteXmlReader do objeto SQLCommand. Este método retorna um objeto System.Xml.XmlReader contendo o XML retornado pelo SQL Server.

Assim o método ExecuteXmlReader carrega um objeto System.Xml.XmlReader com o fluxo de dados.  Lembrando que XmlReader é uma classe abstrata com implementações concretas de XmlTextReader, XmlNodeReader e XmlValidatingReader. (Uma classe abstrata não pode ser instanciada)

Os métodos ExecuteReader e ExecuteXmlReader são capazes de retornar várias linhas e colunas a um DataReader e XmlReader, e,  este recurso que vou mostrar neste artigo.

Como exemplo para este artigo estarei usando o VB 2005 Express Edition , o SQL Server 2005 Express Edition e o banco de dados Cadastro.mdf criado em artigos anteriores.

Nota: Para saber como criar o banco de dados no SQL Server 2005 leia o artigo : ADO.NET 2.0  - Usando SqlDataReader com múltiplos ResultSets.

A string de conexão com o banco de dados usada será armazenada usando o recurso My.Settings conforme os seguintes passos:

  1. Clique com o botão direito sobre My Project na janela Solution Explorer e selecione Open.
  2. Na janela a seguir selecione Settings e informe um nome para a string de conexão e para a string SQL na coluna Name. Eu usei os nomes connSQL. Salve a operação. Pronto ! já podemos recuperar esta informação a partir de My.Settings em tempo de execução.

Apresentando a classe XmlReader

A classe XmlReader fornece uma acesso somente-leitura e somente-para-frente de um fluxo de dados Xml e esta em conformidade com as recomendações do W3C Extensible Markup Language (XML) 1.0.

No fluxo de dados XML o nó atual refere-se ao nó no qual o leitor(reader) esta posicionado sendo que o leitor é avançado usando qualquer um dos métodos de leitura e propriedades que refletem o valor do nó atual

Embora, como já foi mencionado, a plataforma .NET forneça as implementações concretas para a classe XmlReader através das classes XmlTextReader, XmlNodeReader e XmlValidatingReader, com a nova versão 2.0 da plataforma a recomendação é criar instâncias de XmlReader usando o método Create,

A classe XmlReader suporta a leitura da dados XML a partir de um arquivo ou fluxo de dados. Ela define métodos e propriedades que nos permitem se mover através dos dados e ler o conteúdo de um nó.

De forma geral a classe XmlReader oferece os seguintes recursos:

Nota: Para saber mais sobre conceitos XML leia o artigo: XML - eXtensible Markup Language - Introdução

Na versão 2.0 do Microsoft .NET Framework apresenta a classe XmlReader com as seguintes novas características:

Criando o projeto no VB 2005

Crie um novo projeto no VB 2005 do tipo Windows Application com o nome de XmlAdoNet e altere o nome do formulário principal, form1.vb, para frmXml.vb. A seguir inclua no formulário um controle TextBox com nome de txtXml e um controle Button com nome de btnGeraXml.

No controle txtXml defina a propriedade ScrollBars como Vertical e a propriedade Multiline como True.

A defina as seguintes importações no projeto:

Imports System.data.SqlClient
Imports
System.xml

Abaixo temos uma visão do formulário principal do projeto:

A seguir no evento Click do botão de comando - Gera Xml - inclua o seguinte código :

Private Sub btnGeraXml_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGeraXml.Click

    AbrirXmlReader()

End Sub

Por último inclua o código abaixo referente a função AbrirXmlReader():

Private Sub AbrirXmlReader()
 

'Define e abre um objeto SqlConnection usando a conexão armazenada em my.Settings

Dim conCadastro As SqlConnection = New SqlConnection(My.Settings.connSQL)


Try

 'abre a conexão com o banco de dados

 conCadastro.Open()

 'Define o SqlCommand

 Dim strSQL As String = "SELECT * FROM Clientes FOR XML AUTO, Elements"

 Dim cmdXml As SqlCommand = New SqlCommand(strSQL, conCadastro)

 cmdXml.CommandType = CommandType.Text


 'executa o método ExecuteXmlReader

 Dim xrClientes As XmlReader = cmdXml.ExecuteXmlReader

 With xrClientes

  .Read()

  'percorre o XML gerado
 

  Do While .ReadState <> Xml.ReadState.EndOfFile

       txtXml.Text += .ReadOuterXml

  Loop

  'Formata o resultado para exibição no TextBox

  txtXml.Text = Replace(txtXml.Text, "><", ">" + vbCrLf + "<")

  .Close()

 End With

Catch ex As Exception

  MsgBox(ex.Message)

Finally

  conCadastro.Close()

End Try

End Sub

Vamos agora aos detalhes do código:   

O que eu estou fazendo ?

  1. Abrindo uma conexão com o banco de dados Cadastro.mdf do SQL Server 2005
  2. Definindo um objeto Command que irá selecionar todos os registros da tabela Clientes
  3. Gerando um DataReader do tipo XmlReader
  4. Percorrendo um XML gerado usando os métodos do XMLReader
  5. Exibindo o resultado na caixa de texto

O que vale a pena destacar ?

1-  O método SqlCommand.ExecuteXmlReader envia o comando de texto (CommandText) para a conexão(Connection) e constrói um objeto XmlReader.

A propriedade Commandtext especifica uma instrução Transact-SQL com uma cláusula FOR XML válida mas pode também especificar uma instrução que retorna dados no formato texto contendo XMl válido. No nosso exemplo a instrução usada é : "SELECT * FROM Clientes FOR XML AUTO, Elements"

Enquanto o XmlReader esta em uso a conexão associada estará ocupada servindo ao XmlReader. Enquanto estiver neste estado nenhuma outra operação poder ser realizada na conexão (SqlConnection) a não ser fechá-la. Isto ocorrerá até que o método Close for chamado.

2-  Quando um XmlReader é criado e iniciado , não há informação disponível, por este motivo , você precisa chamar o método Read para ler o primeiro do XML.

O método Read lê o próximo Nó do fluxo de dados XML, e , retorna true se o nó foi lido com sucesso, ou false se não há mais nenhum nó para ler.

3- A propriedade ReadState da classe XmlReader obtém o estado do leitor. Os valores possíveis são:

Nome Descrição
Closed O método Close foi chamado.
EndOfFile O fim do arquivo foi alcançado com sucesso.
Error Ocorre um erro que impede a operação de leitura de continuar.
Initial O método Read não foi chamado ainda.
Interactive O método Read foi chamado.

4- O método ReadOuterXml da classe XmlReader lê o conteúdo , incluindo as marcas, representando o nó e todos os seus filhos. Este método é similar o método ReadInnerXml exceto por não retornar as tags de início e fim. Este método verifica se o XML esta bem formado.

Este método manipula os elementos e atributos da seguinte forma:

Tipo do Nó Posição antes da chamada fragmento XML Valor Retornado Posição após a chamada
Element No item1 tag início <item1>text1</item1><item2>text2</item2> <item1>text1</item1> No item2 tag Inicio
Attribute No attr1 nó atributo <item attr1="val1" attr2="val2">text</item> attr1="val1" Permanece no atributo attr1

5- A função Replace retorna uma string na qual uma substring especificada foi substituída por outra substring.

Sintaxe : Replace(expression, find, replacewith[, start[, count[, compare]]])

No código usamos : Replace(txtXml.Text, "><", ">" + vbCrLf + "<")   para inserir um vbcrlf entre as marcas <>.

Executando o projeto teremos o resultado abaixo para os dados da tabela Clientes:

Palavras finais:

O método ExecuteXmlReader retorna uma implementação concreta da classe abstrata XmlReader.

Você precisa executar o método Read para mover para o primeiro elemento do grupo no fluxo de dados XML seguido por uma invocação do método ReadOuterXml para cada elemento do grupo que representa uma linha no conjunto de registros.

O método ExecuteXmlReader não suporta a enumeração CommandBehavior , desta forma você precisa fechar a conexão explicitamente via método Close.

O provedor OledbCommand não suporta o método ExecuteXmlReader . (A Microsoft quer que você use o SQL Server.)

Lembrete: Quem avisa amigo é, então...  "Para aplicações de produção as consultas usando FOR XML AUTO causam um impacto no desempenho que deve ser considerado pois o servidor precisará  gerar o fluxo XML, e muitos bytes a mais terão que trafegar na rede, além disto o cliente deverá tratar o fluxo XML para um formato adequado."

Bom estudo e até o próximo artigo VB.NET...

Referências:

XmlReader Class - http://msdn2.microsoft.com/en-us/library/ms288592.aspx


José Carlos Macoratti

1