Lendo e gravando SDT’s em arquivos físicos

Buenas mi amigos!!!

Demorei um pouco, mas estou de volta para felicidade de alguns e infelicidade de nenhuns… hehehehe

Hoje queria falar rapidamente sobre SDT’s e XML’s

À partir da versão 8.0 do GeneXus, foi implementado o SDT (link para o release notes aqui)…

SDT? Super Dupper Tuppleware??? Simples Didático e Tal??? Não… nada disso… significa Structured Data Types, tipos de dados estruturados… Lembram do struct da linguagem C? Pois é, bem parecido, porém bem mais robusto e simples de ser utilizado.

Imagine um simples XML com a estrutura:

<Clientes>
<Cliente>
<Id>1</Id>
<Nome>Asdrubal </Nome>
<Telefone>3333-3131</Telefone>
</Cliente>
<Cliente>
<Id>2</Id>
<Nome>Pafúncio</Nome>
<Telefone>3332-3232</Telefone>
</Cliente>
</Clientes>

Até a versão 8.0 não se tinha como representar essa estrutura, em memóra, exceto com um vetor (ou matriz em casos um poucos mais complexos). O que tornava sua operação complicada…

Porém na versão 8.0 pode-se trabalhar com o conceito de SDT, ou seja uma variável (qualquer) estruturada da forma que quisermos.

Então, poderia-se representar essa estrutura através de duas variáveis SDT no genexus, porque duas? Simples, pois uma variável guardará a coleção de todos os clientes (no nosso exemplo só temos 2, mas poderiam-se ter vários…) e outra que será utilizada para navegar em cada item dessa coleção de clientes, simplificando, acessaria as propriedades ID, Nome e Telefone de cada cliente da coleção.

Temos então a variável &Clientes_Col, sendo do tipo de dados SDTClientes e a variável &Cliente_Item sendo do tipo de dados SDTClientes.Item (o nome item é configurável no momento da criação da SDT).

À partir daqui vou dividir em dois subtópicos (Gravando em um SDT e Lendo em um SDT).

  1. Gravando em um SDT. Diante das estruturas e das variáveis acima, seria fazer isso:
     //Adiciono estaticamente os valores a cada uma das propriedades
     &Cliente_Item.ID = 1
     &Cliente_Item.Nome = 'Asdrubal'
     &Cliente_Item.Telefone = '3333-3131'
     //Adiciono esse item dentro da minha coleção de clientes
     &Clientes_Col.Add(&Cliente_Item)
     //Instancio (ou crio) uma nova variável de clientes para o próximo item...
     //Notar que após o comando New, é utilizado uma string disponível no menu Inserir/Structured Data Type juntamente com '(' e ')'
     &Cliente_Item = New SDTClientes.Item()
     //Adiciono o segundo cliente, também estaticamente
     &Cliente_Item.ID = 2
     &Cliente_Item.Nome = 'Pafúncio'
     &Cliente_Item.Telefone = '3332-3232'
     //Existe uma alternativa que também funciona, e tem o mesmo efeito das linhas onde é adicionado o item à coleção e a criação de uma nova instância do item
     //(últimas duas linhas antes do segundo item) que é:
     &Clientes_Col.Add(&Cliente_Item.Clone())
    //Essa linha adiciona na coleção uma cópia do item &Cliente_Item
    //Porém costumo usar a primeira alternativa por tornar-se mais intuitiva para quem lê

    Pronto, isso bastaria para popular meu SDT com dois clientes, conforme a estrutura XML do início…

    Você pode estar se perguntando.. Peraí, eu instancio um novo item após a adição desse item à coleção??? E o primeiro item? onde foi instanciado…

    É amigo, lembre-se, estamos utilizando GeneXus e não uma linguagem tradicional… O primeiro item já está “instanciado”, porém sem valores, e é por esses motivo que não instanciei um novo item ao final da 2ª adição, pois não vou precisar de outro item, da mesma forma que se eu acessar, após todos esses comandos, a variável &Cliente_Item ainda vou ter o valor do último item, em memória, sim, essa é a grande diferença de se adicionar com o método Add(&Variavel) + New Item() e Add(&Variavel.Clone()) , ou seja, quando utiliza-se add(&item) + new é criada uma nova instância da variável de item, perdendo-se seus valores das propriedades atuais.

  2. Lendo em um SDT. Diante das estruturas gravadas acima, vou utilizar as mesmas variáveis somente para simplificação, com exceção das variáveis &Cliente_ID, &Cliente_Nome e &Cliente_Tel que utilizei somente para demontração:
    //A sintaxe é For Each <Item SDT> in <Coleção SDT>
    For Each &Cliente_Item in &Clientes_Col
        &Cliente_ID = &Cliente_Item.ID
        &Cliente_Nome = &Cliente_Item.Nome
        &Cliente_Tel = &Cliente_Item.Telefone
    EndFor

    A leitura é infinitamente mais simples que a gravação, certo?

    Como diria meu professor de Cálculo B: Daqui pra frente é trivial…

  3. Bacana, super supimpa, mais que demais… só que isso todos que trabalham com genexus já estão carecas de saber… certo???

    Porém a questão é… E se e quiser gravar esse SDT em um arquivo… e… lê-lo de um arquivo??

    A resposta é… Bom… O SDT não foi feito para isso, mas você pode fazer…

    É, mas os SDT’s não tem métodos para abrir e fechar, nem ler ou gravar em arquivo…

    A resposta é… Sim, eles não tem… mas para isso existem outros tipos de dados que trabalham com XML… XML Reader e XML Writer… Calma gente… é bem mais simples do que parece…

    Vou separar novamente em dois tópicos… Gravando um SDT em arquivo, e Lendo um SDT em Arquivo…

  4. Gravando um SDT em arquivo
    //Para esse tópico e para o próximo, utilizarei a variável &XML (Varchar de 100.000 posições)...
    //A variável &Writer é do tipo Xml Writer.
    //Carrego a variável &XML com o conteúdo do SDT (em forma de XML)
    &XML = &Clientes_Col.ToXml()
    //Abro o arquivo para escrita
    &Writer.Open('arquivo.xml')
    //Escrevo o conteúdo da variável &XML
    &Writer.WriteRawText(&XML)
    //Ou: &Writer.WriteRaeText(&Clientes_Col.ToXml())
    //Fecho o arquivo
    &Writer.Close()
  5. Lendo um SDT à partir de um arquivo
    //Para esse tópico utilizarei duass novas variáveis: uma chamada &Reader do tipo de dados XMLReader, e outra chamada &Erro, numérica de 2 posições.
    //Abro o arquivo .xml
    &Reader.Open('arquivo.xml')
    //Verifico se não aconteceu algum erro (arquivo inexistente, arquivo em uso, etc.)
    &Erro = &Reader.ErrCode
    
    If &Erro = 0 //zero
     	//Aqui sim, efetuo a leitura do arquivo inteiro para a variável &XML
    	&XML = &Reader.ReadRawXML()
    	//Populo o SDT à partir da variável &XML
    	&Clientes_Col.FromXML(&XML)
    	//Sim, eu poderia fazer os dois comandos em uma linha somente:
    	//&Clientes_Col.FromXml(&Reader.ReadRawXML())
    	//Por motivos de facilidade de entendimento utilizei uma variável auxiliar...
    	//Fecho o arquivo
    	&Reader.Close()
    Else
    	Msg("Ocorreu um erro ao abrir o arquivo.")
    Endif

Bom, espero ter contribuído mais um pouquinho…

Um abraço e até a próxima…

Anúncios

2 comentários sobre “Lendo e gravando SDT’s em arquivos físicos

  1. Uma pequena contribuição, Descobri após muito tentar

    No item 4. Lendo um SDT à partir de um arquivo

    após a linha:
    &Reader.Open(‘arquivo.xml)
    colocar a linha:
    &Reader.Read()

    e depois continua normal…
    &Erro = &Reader.ErrCode…

    1. Rodinei,

      Obrigado pela contribuição.

      Talvez o comportamento da rotina seja diferente de versão para versão do Gx.

      Quando criei esse post, foi baseado em uma rotina já existente, que já funcionava. Mas era em GeneXus 9.0

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s