Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   OOP (https://www.clubdelphi.com/foros/forumdisplay.php?f=5)
-   -   Exportacion a XML (https://www.clubdelphi.com/foros/showthread.php?t=70416)

Wbarrantes 19-10-2010 19:11:37

Exportacion a XML
 
me encontre este codigo en varias paginas, sirve para la exportacion a XML, pero tengo problemas con este pues no sirve... aunque la idea general esta muy bien...


adjunto el codigo por si alguien mas avanzado en el tema puede decirme cual es el problema...

variable Global

Código Delphi [-]
  SourceBuffer: PChar;

Código Delphi [-]
procedure WriteString(Stream: TFileStream; s: string);
begin
  StrPCopy(SourceBuffer, s);
  Stream.Write(SourceBuffer[0], StrLen(SourceBuffer));
end;
procedure WriteFileBegin(Stream: TFileStream; Dataset: TDataset);
  function XMLFieldType(fld: TField): string;
  begin
    case fld.DataType of
      ftString: Result := '"string" WIDTH="' + IntToStr(fld.Size) + '"';
      ftSmallint: Result := '"i4"'; //??
      ftInteger: Result := '"i4"';
      ftWord: Result := '"i4"'; //??
      ftBoolean: Result := '"boolean"';
      ftAutoInc: Result := '"i4" SUBTYPE="Autoinc"';
      ftFloat: Result := '"r8"';
      ftCurrency: Result := '"r8" SUBTYPE="Money"';
      ftBCD: Result := '"r8"'; //??
      ftDate: Result := '"date"';
      ftTime: Result := '"time"'; //??
      ftDateTime: Result := '"datetime"';
    else
    end;
    if fld.Required then
      Result := Result + ' required="true"';
    if fld.Readonly then
      Result := Result + ' readonly="true"';
  end;
var
  i: Integer;
begin
  WriteString(Stream, '' +
                      '');
  WriteString(Stream, '');
  {write th metadata}
  with Dataset do
    for i := 0 to FieldCount-1 do
    begin
      WriteString(Stream, ''/>');
    end;
  WriteString(Stream, '');
  WriteString(Stream, '');
  WriteString(Stream, '');
end;
procedure WriteFileEnd(Stream: TFileStream);
begin
  WriteString(Stream, '');
end;
procedure WriteRowStart(Stream: TFileStream; IsAddedTitle: Boolean);
begin
  if not IsAddedTitle then
    WriteString(Stream, ');
end;
procedure WriteRowEnd(Stream: TFileStream; IsAddedTitle: Boolean);
begin
  if not IsAddedTitle then
    WriteString(Stream, '/>');
end;
procedure WriteData(Stream: TFileStream; fld: TField; AString: ShortString);
begin
  if Assigned(fld) and (AString <> '') then
    WriteString(Stream, ' ' + fld.FieldName + '="' + AString + '"');
end;
function GetFieldStr(Field: TField): string;
  function GetDig(i, j: Word): string;
  begin
    Result := IntToStr(i);
    while (Length(Result) < j) do
      Result := '0' + Result;
  end;
var Hour, Min, Sec, MSec: Word;
begin
  case Field.DataType of
    ftBoolean: Result := UpperCase(Field.AsString);
    ftDate: Result := FormatDateTime('yyyymmdd', Field.AsDateTime);
    ftTime: Result := FormatDateTime('hhnnss', Field.AsDateTime);
    ftDateTime: begin
                  Result := FormatDateTime('yyyymmdd', Field.AsDateTime);
                  DecodeTime(Field.AsDateTime, Hour, Min, Sec, MSec);
                  if (Hour <> 0) or (Min <> 0) or (Sec <> 0) or (MSec <> 0) then
                    Result := Result + 'T' + GetDig(Hour, 2) + ':' + GetDig(Min, 2) + ':' + GetDig(Sec, 2) + GetDig(MSec, 3);
                end;
  else
    Result := Field.AsString;
  end;
end;
procedure TForm1.DatasetToXML(Dataset: TDataset; FileName: string);
var
  Stream: TFileStream;
  bkmark: TBookmark;
  i: Integer;
begin
  Stream := TFileStream.Create(FileName, fmCreate);
  SourceBuffer := StrAlloc(2048);
  WriteFileBegin(Stream, Dataset);
  with DataSet do
  begin
    DisableControls;
    bkmark := GetBookmark;
    First;
    {write a title row}
    WriteRowStart(Stream, True);
    for i := 0 to FieldCount-1 do
      WriteData(Stream, nil, Fields[i].DisplayLabel);
    {write the end of row}
    WriteRowEnd(Stream, True);
    while (not EOF) do
    begin
      WriteRowStart(Stream, False);
      for i := 0 to FieldCount-1 do
        WriteData(Stream, Fields[i], GetFieldStr(Fields[i]));
      {write the end of row}
      WriteRowEnd(Stream, False);
      Next;
    end;
    GotoBookmark(bkmark);
    EnableControls;
  end;
  WriteFileEnd(Stream);
  Stream.Free;
  StrDispose(SourceBuffer);
end;



para la ejecucion...
Código Delphi [-]
DatasetToXML(ClientDataSet1 , 'C:/test.xml');



Uso Delphi embarcadero 2010, y el problema que me da es en el archivo final generado... como que incluye espacios en blnco entre cada caracter....


si alguien tiene alguna idea... le agradesco... o si a alguien le corre sin problema, favor decirme para ver si podria ser algo en mi equipo... gracias

Neftali [Germán.Estévez] 20-10-2010 12:33:34

Hola; Lo primero decir que al colocar el código con los TAG's de Delphi (seguramente por un error en el parser) faltan cosas y el código ha quedado incorrecto (revisar el procedimiento WriteFileEnd, por ejemplo).

Lo coloco con las etiquetas CODE, por si alguien quiere copiarlo.

Código:

procedure WriteString(Stream: TFileStream; s: string);
begin
  StrPCopy(SourceBuffer, s);
  Stream.Write(SourceBuffer[0], StrLen(SourceBuffer));
end;

procedure WriteFileBegin(Stream: TFileStream; Dataset: TDataset);

  //············································································
  function XMLFieldType(fld: TField): string;
  begin
    case fld.DataType of
      ftString: Result := '"string" WIDTH="' + IntToStr(fld.Size) + '"';
      ftSmallint: Result := '"i2"'; //??
      ftInteger: Result := '"i4"';
      ftWord: Result := '"i4"'; //??
      ftBoolean: Result := '"boolean"';
      ftAutoInc: Result := '"i4" SUBTYPE="Autoinc"';
      ftFloat: Result := '"r8"';
      ftCurrency: Result := '"r8" SUBTYPE="Money"';
      ftBCD: Result := '"r8"'; //??
      ftDate: Result := '"date"';
      ftTime: Result := '"time"'; //??
      ftDateTime: Result := '"datetime"';
    else
      Result := '"TIPO-DESCONOCIDO"';


    end;
    if fld.Required then
      Result := Result + ' required="true"';
    if fld.Readonly then
      Result := Result + ' readonly="true"';
  end;
  //············································································

var
  i: Integer;
begin
  WriteString(Stream, '<?xml version="1.0" standalone="yes"?><!-- Generated by SMExport -->  ' +
                      '<DATAPACKET Version="2.0">');
  WriteString(Stream, '<METADATA><FIELDS>');

  {write th metadata}
  with Dataset do
    for i := 0 to FieldCount-1 do
    begin
      WriteString(Stream, '<FIELD attrname="' +
                          Fields[i].FieldName +
                          '" fieldtype=' +
                          XMLFieldType(Fields[i]) +
                          '/>');
    end;
  WriteString(Stream, '</FIELDS>');
  WriteString(Stream, '<PARAMS DEFAULT_ORDER="1" PRIMARY_KEY="1" LCID="1033"/>');
  WriteString(Stream, '</METADATA><ROWDATA>');
end;

procedure WriteFileEnd(Stream: TFileStream);
begin
  WriteString(Stream, '</ROWDATA></DATAPACKET>');
end;

procedure WriteRowStart(Stream: TFileStream; IsAddedTitle: Boolean);
begin
  if not IsAddedTitle then
    WriteString(Stream, '<ROW');
end;

procedure WriteRowEnd(Stream: TFileStream; IsAddedTitle: Boolean);
begin
  if not IsAddedTitle then
    WriteString(Stream, '/>');
end;

procedure WriteData(Stream: TFileStream; fld: TField; AString: ShortString);
begin
  if Assigned(fld) and (AString <> '') then
    WriteString(Stream, ' ' + fld.FieldName + '="' + AString + '"');
end;

function GetFieldStr(Field: TField): string;
  //············································································
  function GetDig(i, j: Word): string;
  begin
    Result := IntToStr(i);
    while (Length(Result) < j) do
      Result := '0' + Result;
  end;
  //············································································
var Hour, Min, Sec, MSec: Word;
begin
  case Field.DataType of
    ftBoolean: Result := UpperCase(Field.AsString);
    ftDate: Result := FormatDateTime('yyyymmdd', Field.AsDateTime);
    ftTime: Result := FormatDateTime('hhnnss', Field.AsDateTime);
    ftDateTime: begin
                  Result := FormatDateTime('yyyymmdd', Field.AsDateTime);
                  DecodeTime(Field.AsDateTime, Hour, Min, Sec, MSec);
                  if (Hour <> 0) or (Min <> 0) or (Sec <> 0) or (MSec <> 0) then
                    Result := Result + 'T' + GetDig(Hour, 2) + ':' + GetDig(Min, 2) + ':' + GetDig(Sec, 2) + GetDig(MSec, 3);
                end;
  else
    Result := Field.AsString;
  end;
end;

En cuanto a tu problema, es posible que esté a la hora de definir tipos de datos. Fíjate con no están ftWideString, ftLargeInt,...
He añadido esto al else:

Código Delphi [-]
   Result := '"TIPO-DESCONOCIDO"';

Que te debería ayudar a detectar si ese es tu problema. Por lo demás yo lo he probado y parece que el código funciona bien.

nejamube 20-10-2010 16:28:26

Puedes utilizar una consulta en lugar de un DataSet ?
 
Puedes utilizar una consulta en lugar de un DataSet ?

Creo tener idea de como corregir el problema, ¿ puedes poner el resultado que obtienes en el XML ?

¿Puedes poner los datos que son usados en el DataSet?

Gracias.

Neftali [Germán.Estévez] 20-10-2010 16:31:25

Cita:

Empezado por nejamube (Mensaje 379882)
Puedes utilizar una consulta en lugar de un DataSet ?

Cualquier TQuery, TTable, TADOTable,... deriva de un DataSet, por lo tanto puedes utilizarlo con el resultado de un quey sin problemas (así lo he probado yo).

nejamube 20-10-2010 16:37:31

Muchas gracias Neftali
 
Cita:

Empezado por Neftali (Mensaje 379883)
Cualquier TQuery, TTable, TADOTable,... deriva de un DataSet, por lo tanto puedes utilizarlo con el resultado de un quey sin problemas (así lo he probado yo).

Muchas gracias Neftali:)

nejamube 20-10-2010 19:02:48

Duda acerca de nodos XML
 
Hola.

Intentando de otra forma he obtenido la siguiente estructura en el XML.

Código PHP:

<DATAPACKET Version="2.0">
&
#8722;
<METADATA>
&
#8722;
<FIELDS>
<
FIELD attrname="CAJA" fieldtype="i4" required="true"/>
<
FIELD attrname="NUMERO" fieldtype="i4" required="true"/>
<
FIELD attrname="FECHA" fieldtype="date" required="true"/>
<
FIELD attrname="HORA" fieldtype="time" required="true"/>
<
FIELD attrname="ESTATUS" fieldtype="string" WIDTH="7" required="true"/>
<
FIELD attrname="SUBTOTAL" fieldtype="r8"/>
<
FIELD attrname="IVA" fieldtype="r8"/>
<
FIELD attrname="TOTAL" fieldtype="r8" required="true"/>
</
FIELDS>
<
PARAMS DEFAULT_ORDER="1" PRIMARY_KEY="1" LCID="1033"/>
</
METADATA>
&
#8722;
<ROWDATA>
<
ROW Caja="1" Remisión="1" Fecha="20101020" Hora="10:58:21:000" Estatus="A" Subtotal="9" I.V.A.="0.99" Total="9.99"/>
<
ROW Caja="1" Remisión="2" Fecha="20101020" Hora="10:58:30:000" Estatus="A" Subtotal="18" I.V.A.="1.98" Total="19.98"/>
</
ROWDATA>
</
DATAPACKET

Lo que necesito es que despues de el nodo Field se despliegue otro nodo llamado Fields de la siguiente manera:

Código PHP:

<DATAPACKET Version="2.0">
&
#8722;
<METADATA>
&
#8722;
<FIELDS>
<
FIELD attrname="Version" fieldtype="i2"/>
<
FIELD attrname="Tipo" fieldtype="string" WIDTH="2"/>
<
FIELD attrname="Cadena" fieldtype="string" WIDTH="2"/>
<
FIELD attrname="Terminos" fieldtype="string" WIDTH="120"/>
&
#8722;
<FIELD attrname="Algomas" fieldtype="nested">
&
#8722;
<FIELDS>
<
FIELD attrname="Cuenta" fieldtype="string" WIDTH="21"/>
<
FIELD attrname="Depto" fieldtype="integer"/>
<
FIELD attrname="Concepto" fieldtype="string" WIDTH="120"/>
<
FIELD attrname="Monto" fieldtype="float"/>
<
FIELD attrname="Cambio" fieldtype="r8"/>
<
FIELD attrname="Hayer" fieldtype="string" WIDTH="1"/>
</
FIELDS>
<
PARAMS/> 

He intentado de muchas formas pero no he logrado mi proposito.:confused:

Muchas gracias.:)

Wbarrantes 20-10-2010 23:00:37

Cita:

Empezado por nejamube (Mensaje 379882)
Puedes utilizar una consulta en lugar de un DataSet ?

Creo tener idea de como corregir el problema, ¿ puedes poner el resultado que obtienes en el XML ?

¿Puedes poner los datos que son usados en el DataSet?

Gracias.


el resultado que me da el archivo XML es:

Código PHP:

< ? x m l   v e r s i o n " 1 . 0 "   s t a n d a l o n e " y e s " ? > < ! - -   G e n e r M E T A D A T A F I E L D   a t t r n a m e " N o m b r e "   f i e l d t y p e " < F I E L D   a t t r n a m e = " A p e l l i d o 1 "   f i e l d t y p e =< F I E L D   a t t r n a m e = " C e d u l a "   f i e l d t y p e = "F I E L D   a t t r n a m e " F U L L N A M E "   f i < / F I EP A R A M S   D E F A U L T _ O R D E R " 1 "   P R< / M E T A D A T A R   N o m b r   A p e l l i d o 1 =   C e d u l a " 0   F U L L N A M E = " A B C D E F G H / < R   N o m b r   A p e l l i d o 1 =   C e d u l a " 1   F U L L N A M E = " A B C D E F G H / < R   N o m b r   A p e l l i d o 1 =   C e d u l a " 1   F U L L N A M E = " A B C D E F G H / < R   N o m b r   A p e l l i d o 1 =   C e d u l a " 1   F U L L N A M E = " A B C D E F G H / < R   N o m b r   A p e l l i d o 1 =   C e d u l a " 1   F U L L N A M E = " A B C D E F G H / < R   N o m b r   A p e l l i d o 1 =   C e d u l a " 1   F U L L N A M E = " A B C D E F G H / < R   N o m b r   A p e l l i d o 1 =   C e d u l a " 2   F U L L N A M E = " A B C D E F G H / < R   N o m b r   A p e l l i d o 1 =   C e d u l a " 9   F U L L N A M E = " A B C D E F G H / < R   N o m b r   A p e l l i d o 1 =   C e d u l a " 9   F U L L N A M E = " A B C D E F G H / < / R O W D A T A > < / 



Cita:

¿Puedes poner los datos que son usados en el DataSet?
a cuales datos te refieres?

el dataset ejecuta una consulta de la tabla Personas(para este ejemplo especifico), y contiene...


Código SQL [-]
SELECT [Nombre]
      ,[Apellido1]
      ,[Apellido2]
      ,[Cedula]
      ,[FULLNAME]
  FROM [Prueba].[dbo].[Persona]

pobre con los cambios de Neftali pero nada.. sigue igual... por cierto gracias por las prontas respuestas...

Wbarrantes 21-10-2010 01:25:26

Neftali...
 
Cita:

En cuanto a tu problema, es posible que esté a la hora de definir tipos de datos. Fíjate con no están ftWideString, ftLargeInt,...
He añadido esto al else:
Pues efectivamente no tengo contemplado el ftWideString, como podria agregarlo?

Neftali [Germán.Estévez] 21-10-2010 10:46:21

Cita:

Empezado por Wbarrantes (Mensaje 379955)
Pues efectivamente no tengo contemplado el ftWideString, como podria agregarlo?

En el Case:

Código Delphi [-]
  case fld.DataType of

Habría que ir añadiendo los que faltan; Por ejemplo, al final puedes poner:

Código Delphi [-]
    ftLargeInt: Result := '"i8"';
    ftWideString: Result := '"string" WIDTH="' + IntToStr(fld.Size) + '"';

Wbarrantes 21-10-2010 17:23:58

Neftali
 
ok, genial, ya agregue los valores que hacian falta, (por cierto de donde tomas la tabla equivalencia de los valores, podria serme util en un futuro...)...

Pero sigo teniendo el problema en el archivo generado... como que mete un espacio en blanco entre cada caracter, antes de escribir el archivo xml... y ademas lo corta...

por ejemplo la primera linea queda en el archivo
Código PHP:

< ? x m l   v e r s i o n " 1 . 0 "   s t a n d a l o n e " y e s " ? > < ! - -   G e n e r 

y deberia ser...

Código PHP:

<?xml version="1.0" standalone="yes"?><!-- Generated by SMExport -->

como pueden ver se corta en "Gener", no termina de escribir toda la sentencia "Generated by SMExport -->"... se que en esta linea esto no es importante, a exepcion de los reconocimientos de los creditos... pero es un ejemplo, pues hace lo mismo con el resto de lineas en el archivo...

Neftali [Germán.Estévez] 21-10-2010 17:57:15

Cita:

Empezado por Wbarrantes (Mensaje 380032)
...por cierto de donde tomas la tabla equivalencia de los valores, podria serme util en un futuro...

En mi caso de la ayuda de SQL Server, pero supongo que por internet si buscas deben estar.

En cuanto a los espacios no lo entiendo, porque eso lo añade esta línea que parece bastante "inofensiva". :confused::confused:

Código:

  WriteString(Stream, '<?xml version="1.0" standalone="yes"?><!-- Generated by SMExport -->  ' +
                      '<DATAPACKET Version="2.0">');


Wbarrantes 21-10-2010 18:20:59

muy confundido???
 
:confused:
si de echo alli tengo misdudas pues debugeando, la informacion entra nitida....

tengo office 2007 y windows XP, y Delphi 2010 (con licencia)... no veo que pueda estar fallando... y ya pobre el ejecutable en otras maquinas y nada...

WriteString

Código Delphi [-]
 
procedure WriteString(Stream: TFileStream; s: string);
begin
  StrPCopy(SourceBuffer, s);
  Stream.Write(SourceBuffer[0], StrLen(SourceBuffer));
end;

Write

Código Delphi [-]
function THandleStream.Write(const Buffer; Count: Longint): Longint;
begin
  Result := FileWrite(FHandle, Buffer, Count);
  if Result = -1 then Result := 0;
end;

de echo cuando trate de revisar el ejemplo para escribir en excell, tambien me dio este tipo de problemas... me ponia un caracter con signo de pregunta, entre cada caracter de la cadena del string, que deseabaguardar en una celda...

pero ya lo he probado, tambien en otras maquinas con configuraciones diferentes, lo que me lleva a pensar que podrian ser la unidades, mas bien...

Neftali [Germán.Estévez] 21-10-2010 18:40:25

¿No estará relacionado con Unicode?
Lo digo por los 2 caracteres en lugar de 1.

Wbarrantes 21-10-2010 18:47:53

pos la verdad no se...
 
pos la verdad, en este momento, ya no me queda piedra sin revisar... al menos hasta donde mi "malicia indigena" alcanza...

inicailmente pense que podria estar cortando la cadena por el tamano del
Código Delphi [-]
SourceBuffer := StrAlloc(1024);
por lo que lo triplique...
Código Delphi [-]
SourceBuffer := StrAlloc(4096);

pero el resultado es el mismo...

estoy en un 98% convencido que el problema viene dado por el Stream, lo que me tiene chichoso, es que el problema no parece tenerlo nadie mas en este foro... pero si cambio de equipo y lo intento de nuevo, yo sigo teniendo problemas...

rastafarey 23-10-2010 05:10:18

resp
 
Carga los datos en un cliendataset y lo guardas como xml esta atarea el clien dataset la hace solita.


La franja horaria es GMT +2. Ahora son las 06:58:21.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi