Arquivo

Arquivo da Categoria ‘Artigos’

Exportando dados de um DataSet para o formato JSON

25, setembro, 2009 4 comentários

Neste artigo serão demonstrados algoritmos para exportação de dados de um DataSet para o formato JSON. Até a versão 2009 do Delphi não há nada nativo para manipulação de arquivos JSON, por isso utilizei uma biblioteca Open Source chamada Delphi JSON Library (http://sourceforge.net/projects/lkjson).

O que é JSON?

JSON (JavaScript Object Notation – Notação de Objetos JavaScript) é uma formatação leve de troca de dados. Para seres humanos, é fácil de ler e escrever. Para máquinas, é fácil de interpretar e gerar. Está baseado em um subconjunto da linguagem de programação JavaScript, Standard ECMA-262 3a Edição -Dezembro – 1999. JSON é em formato texto e completamente independente de linguagem, pois usa convenções que são familiares às linguagens, incluindo C++, C#, Java, JavaScript, Perl, Python, Delphi e muitas outras. Estas propriedades fazem com que JSON seja um formato ideal de troca de dados.

JSON está constituído em duas estruturas:

•             Uma coleção de pares nome/valor. Em várias linguagens, isto é caracterizado como um object, record, struct, hash table, keyed list, ou arrays associativas;

•             Uma lista ordenada de valores. Na maioria das linguagens, isto é caracterizado como um array, vetor, lista ou sequência.

São estruturas de dados universais. Virtualmente, todas as linguagens de programação modernas as suportam, de uma forma ou de outra. É aceitável que um formato de troca de dados que seja independente de linguagem de programação se baseie nessas estruturas.

Em JSON, os dados são apresentados da seguinte forma:

Um objeto é um conjunto desordenado de pares nome/valor. Um objeto começa com { (chave de abertura) e termina com } (chave de fechamento). Cada nome é seguido por : (dois pontos) e os pares nome/valor são seguidos por , (vírgula).

Classes da biblioteca lkjson utilizadas:

TlkJSONobject: Utilizada para o cabeçalho e itens de lista do arquivo JSON;

TlkJSONlist: Utilizada para guardar a lista de valores e nomes dos fields do DataSet.

Implementação da classe manipuladora do arquivo JSON:

unit DataSetToJsonEngine;

interface

uses DB, uLkJSON;

type
  TCustomDataSetToJson = class
  private
    FJsonObjectMain : TlkJSONobject;
    FDataSet: TDataSet;
    procedure SetDataSet(const Value: TDataSet);
    procedure ValidateDataSet;
  public
    property DataSet : TDataSet read FDataSet write SetDataSet;
    constructor Create(const ADataSet : TDataSet);
    destructor Destroy; override;
    function Convert : WideString;
  end;

  TDataSetToJson = class(TCustomDataSetToJson);

implementation

uses SysUtils;

{ TCustomDataSetToJson }

function TCustomDataSetToJson.Convert: WideString;
var
  JsonList : TlkJSONlist;
  JsonDataFieldList : array of TlkJSONobject;
  I, IdxRecord : Integer;
begin
  ValidateDataSet;
  JsonList := TlkJSONlist.Create;
  try
    // Monto o cabeçalho da string Json
    FJsonObjectMain.Add('DataSetName', FDataSet.Name);
    FJsonObjectMain.Add('DataSetCount', FDataSet.RecordCount);
    with FDataSet do
    begin
      First;
      IdxRecord := 0;
      SetLength(JsonDataFieldList, FDataSet.RecordCount);
      // Adiciono os valores e nomes dos fields em uma lista
      while not EOF do
      begin
        JsonDataFieldList[IdxRecord] := TlkJSONobject.Create;
        for I := 0 to FieldCount - 1 do
          JsonDataFieldList[IdxRecord].Add(Fields[I].FieldName, Fields[i].AsString);
        JsonList.Add(JsonDataFieldList[IdxRecord]);
        Next;
        Inc(IdxRecord);
      end;
      // Atribuo a lista no objeto principal do Json
      FJsonObjectMain.Add('DataFieldList', JsonList);
      Result := TlkJSON.GenerateText(FJsonObjectMain);
    end;
  finally
    FreeAndNil(JsonList);
  end;
end;

constructor TCustomDataSetToJson.Create(const ADataSet: TDataSet);
begin
  FDataSet := ADataSet;
  FJsonObjectMain := TlkJSONobject.Create;
end;

destructor TCustomDataSetToJson.Destroy;
begin
  FJsonObjectMain.Free;
  inherited;
end;

procedure TCustomDataSetToJson.SetDataSet(const Value: TDataSet);
begin
  FDataSet := Value;
end;

procedure TCustomDataSetToJson.ValidateDataSet;
begin
  if FDataSet = nil then
    raise Exception.Create('DataSet não atribuído');
  FDataSet.Active := not(FDataSet.Active);
  if FDataSet.IsEmpty then
    raise Exception.Create('DataSet vazio');
end;

end.

Consumindo a classe manipuladora:

Criar um novo form, adicione um botão e um MEMO. No evento OnClick do botão adicione o seguinte código:

procedure TfrmDataSetToJsonMain.Button1Click(Sender: TObject);
var
  JsonEngine : TDataSetToJson;
begin
  JsonEngine := TDataSetToJson.Create(SQLQuery1);
  Memo1.Text := JsonEngine.Convert;
end;

Testando o arquivo JSON gerado:

Neste exemplo o arquivo JSON foi gerando dentro de um campo MEMO, o texto nele contido poderá ser testado em uma ferramenta web, segue link: http://www.thomasfrank.se/downloadableJS/JSONeditor_example.html

Testando arquivo JSON

Testando arquivo JSON

Fontes – Delphi 2009

Os dados exportados nesse exemplo está no banco de dados de exemplo do Firebird 2.1. Utilizei uma conexão DBExpress com o driver da Embarcadero http://groups.google.com/group/dbxfirebird

Este é um pequeno exemplo de como criar arquivos JSON de forma rápida e fácil. No próximo artigo teremos um exemplo de como trocar arquivos JSON via socket com uma aplicação JavaScript.

Padronização de código

13, setembro, 2009 4 comentários

Introdução
Este artigo tem por finalidade definir padrões de desenvolvimento, no que diz respeito a nomenclatura e melhores práticas, aos elementos a serem utilizados nos projetos que utilizarem Delphi para Windows.


1. Estilos de Capitalização

Existem três tipos de convenções de nomenclatura. São eles: Pascal Case, Camel Case e Upper Case. Em todas as convenções se refere ao uso de maiúsculas ou minúsculas nos nomes. Todas se aplicam a nomes formados por várias palavras.

1.1. Pascal Case

A primeira letra do identificador e as primeiras letras das palavras subseqüentes são maiúsculas.
Exemplo:

BackColor

1.2. Camel Case

A primeira letra da primeira palavra é em minúscula, e as demais palavras subseqüentes iniciam com maiúscula.
Exemplo:

backColor

1.3. Upper Case

Todas as letras são maiúsculas. Usada somente para constantes.
Exemplo:

CHAVE_CRIPTOGRAFIA = String(‘#F$%A&DH’);

2. Tabela de Regras de Capitalização

Tipo Estilo Obrigatório
Classes PascalCase TClienteCadastro (Utilizar T no início)
Eventos PascalCase ValueChange
Variáveis PascalCase RedValue
Interface PascalCase IDisposable
Métodos PascalCase ConverteValor()
Nome de Unit PascalCase ClienteCadastroForm.pas
Propriedade PascaCase BackColor
Propriedade Public PascalCase RedValue
Parâmetro de Métodos PascalCase ANomeParametro
Propriedade Protected PascalCase RedValue
Propriedade Private PascalCase DomainUser
Constantes UpperCase CODIGO_SISTEMA
Numeradores camelCase (stAberto, stFechado, stDesconhecido)

3. Padrão de Nomenclatura

Nomear corretamente objetos, componentes, arquivos, pastas, enfim, elementos em geral, é muito importante para um bom entendimento do projeto como um todo. Um simples arquivo nomeado errado, ou sem um padrão definido, pode confundir e prejudicar uma futura manutenção. Portanto, questões importantes devem ser consideradas na nomenclatura do projeto:
· Não utilize notação húngara. A notação é útil somente para nomear componentes e, mesmo assim, quando existe a necessidade de identificação facilitada do mesmo;
· Coloque nomes da forma mais clara possível, visando facilitar a compreensão da finalidade;
· Em nomes compostos, faça combinações entre caracteres maiúsculos e minúsculos para PascalCase;
· Utilize abreviações com responsabilidade, e conforme a necessidade;
· Utilize nomes em português;
· Não utilize espaços, acentos, cedilhas, sublinhas ou caracteres especiais, mesmo que o contexto do que está sendo nomeado permita.

3.1. Classes

3.1.1. Classes Objeto

· Nomeie classes objeto com nomes/substantivos;
· Use PascalCase;
· Não use prefixo de classe (por exemplo: CFTP);
· Utilize “T” no início do nome da declaração da classe;
· Não use o caractere de sublinha (_).
Exemplos:

TUsuario = Class;
TUsuarioPadrao = TUsuario;
TUsuarioBasico = TUsuario;

3.2. Interfaces

· Nomeie interfaces com substantivos ou adjetivos que descrevem o comportamento;
· Use PascalCase;
· Não use o caractere de sublinha (_);
· Coloque a letra I como prefixo, para indicar que o tipo é uma interface;
· Use nomes similares quando definir pares de classes/interfaces, onde a classe é uma implementação padrão das interfaces. O nome deve diferir apenas com a letra I, que é o prefixo do nome da interface.
Exemplos:

IUsuarioBase = Interface
TppInterfacedObject = class(TObject, IUnknown)

3.3. Parâmetros

· Use nomes de parâmetros descritivos. Nomes de parâmetros devem ser descritivos o suficiente para que se possa, baseado no nome do parâmetro e seu tipo, determinar o que o parâmetro significa;
· Use PascalCase;
· Use nomes baseados no significado do parâmetro e não baseados no tipo do parâmetro;
· Não use parâmetros reservados (por exemplo: params, args, etc);
· Não use notação Húngara.
Exemplos:

procedure FormataNumero(AValor : Inteiro);
function FormataNumero(AValor : Inteiro) : Integer;

3.4. Variáveis

· Nomeie Variáveis usando substantivos;
· Use PascalCase;
· Nunca utilize o caractere de sublinha (_);
· Quando for variável declarada na interface, utilize “F” no início do nome.
Exemplos:

Private

FNomeUsuario : String;

FSenhaUsuario : String;

Public

FNomeEmpresa : String;

End;


Declaração em métodos:

Procedure ProcessaUsuario(ACodigoUsuario : Integer);

var

ValorTemporario : Integer;

NomeUsuario : String;

begin

//

end;

3.5. Propriedades

· Nomeie propriedades usando substantivos;
· Use PascalCase;
· Considere ter uma propriedade com o mesmo nome do tipo;
· Quando declarar uma propriedade com o mesmo nome do tipo, defina o mesmo tipo da propriedade;
· Não utilize o “T” no início do nome, “T” é utilizado apenas na declaração de tipos.
Exemplos:

private

FNomeUsuario : String;

public

property NomeUsuario : String read FNomeUsuario write FNomeUsuario

3.6. Nome para Arquivos (Units)

· Use PascalCase para nomear arquivos;
· Para formar o nome, utilize o nome da funcionalidade, o tipo da funcionalidade, e o tipo de formulário (form) que você está utilizando (caso esse arquivo seja de um formulário).
Exemplos de formulários:

CategoriaCadastroForm.pas
UsuarioListaForm.pas
EntradaForm.pas
UsuarioPesquisaForm.pas

3.7. Prefixo para Objetos de Interface

· Esses objetos ainda seguem a notação húngara;
· Use as abreviações, nas tabelas a seguir, como prefixo dos objetos;
· Use CamelCase para nomear objetos de interface;
· Utilize a seguinte regra: Três consoantes + Nome do Objeto. Exemplos:
- Query da tabela Banco à qryBanco;
- ClientDataSet da tabela Banco à cdsBanco;
- DataSource ligado ao ClientDataSet à dsrBanco.
Exemplos:

TButton = btnNomeBotao; (Tentar não repetir consoantes).
TADOQuery = qryNomeQuery;
TSpeedButton = sbtNomeBotao;
TActionList = alsNomeActionList;

3.8. Prefixo para Formulários (Form) e Módulos de Dados (DataModule)

· Use CamelCase;
· Form = utilizar “frm” + o nome da funcionalidade;
· DataModule = utilizar “dmd” + o nome da funcionalidade.

Exemplos para DataModule:

dmdClienteProcesso : TDataModule;
dmdClienteCadastro : TDataModule;
dmdPessoaUsuarioCadastro : TDataModule;

Exemplos para Form:

frmClienteProcesso : TFom;
frmClienteCadastro : TForm;
frmPessoaUsuarioCadastro : TForm;

4. Endentação

A endentação citada é sobre o número de espaços entre os níveis de tabulação. Utilize como padrão 2 espaços. Este padrão pode ser configurado na janela de opções do Borland Delphi.

Evite escrever linhas com mais de 80 posições entre espaços e caracteres. A idéia é facilitar a compreensão do código e, se possível, visualizar a linha inteira em seu editor de código. Caso alguns trechos de código fiquem muito extensos, poderá ser feita a quebra da linha, entretanto é necessário seguir os seguintes princípios:
· Quebrar a linha após uma vírgula;

· Quebrar a linha após um operador;

· Alinhar a nova linha no início da expressão no mesmo nível da linha anterior.
Exemplos:

calculaArea(expr1, expr2, expr3,

expr4, expr5);

ou

var := a *b / (c – g + f) +

4 * z;

Outra questão importante é a utilização de espaços em branco para endentação. Utilize espaços em branco para endentação, nunca use tabulação!

5. Comentários

Os comentários são muito importantes, tanto para relembrar você como para orientar outra pessoa sobre a manutenção do código fonte. Comente tudo que puder, da seguinte forma:
· Utilize as duas barras “//” para comentar trechos de código;
· Utilize “{}” para comentar blocos.

5.1. Cabeçalho de Arquivos (Units)

Comentários de cabeçalho são importantes para saber quem foi o responsável pelo desenvolvimento e as alterações aplicadas na unit. Portanto:
· Descreva o propósito da unit;
· Coloque o nome do programador responsável pelo desenvolvimento inicial da unit;
· Coloque o nome do analista responsável;
· O item Revisões será utilizado quando for feita uma manutenção na unit;
· Comentários adicionais são importantes caso as alterações efetuadas nessa unit possam afetar alguma outra funcionalidade do sistema.

Exemplo:

(*——————————————————————
Propósito da Unit:
Programador: Data: ??
Analista Responsável:
Revisões:
Programador:
Data: Descrição da Revisão
Comentários adicionais:
——————————————————————*)

5.2. Cabeçalho de Métodos

Ao descrever o cabeçalho de um Método:
· Utilize comentário de bloco;
· Não seja detalhista, tente ser objetivo em seu comentário;
· Comente sobre os parâmetros, caso hajam.
Exemplo:

{——————————————————————-
* Propósito do Método: Exibir uma mensagem de Pergunta utilizando MessageBox
*
* Utilização dos parâmetros:
ATitulo = Titulo da Mensagem (Caption).
AMensagem = Mensangem que ira aparecer no corpo do MessageBox.
Result = Retorna True caso seja selecionado a opção Sim no MessageBox.
* Autor / Data: Everson R. Novka 09/06/2006
*——————————————————————}
class function TFWMensagem.Pergunta(const ATitulo,
AMensagem: String): Boolean;
begin
Result := (MessageBox(0, PChar(AMensagem), pChar(ATitulo),
MB_ICONQUESTION or MB_YESNO or MB_DEFBUTTON2) = idYes);
end;

5.3. Comentários dentro de métodos

· Utilize “//” para comentários de apenas um linha;
· Utilize comentário em bloco ( { … } ) somente em rotinas para comentários de mais de uma linha, a questão visual é fundamental para um melhor entendimento.
Exemplo:

function TfrmMovPontoManual.tbKeyIsDown(const key: integer): boolean;
begin
//Retorna se a tecla especificada está pressionada.
//Gislaine – 26/09/2005
Result := GetKeyState(Key) and 128 > 0;
end;
}