⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 omnixmldatabase.pas

📁 OmniXML源码
💻 PAS
📖 第 1 页 / 共 2 页
字号:
{ $OmniXML: OmniXML/OmniXMLDatabase.pas,v 1.1.1.1 2004/04/17 11:16:33 mr Exp $ }

(*:XML helper unit. Contains routines to copy data between XML and TDataSet.
   @author Primoz Gabrijelcic
   @desc <pre>
   (c) 2003 Primoz Gabrijelcic
   Free for personal and commercial use. No rights reserved.

   Author            : Primoz Gabrijelcic
   Creation date     : 2001-10-24
   Last modification : 2003-03-31
   Version           : 1.03
</pre>*)(*
   History:
     1.03: 2003-03-31
       - Added methods DatasetToXMLFile, DatasetToXMLString, XMLFileToDataset,
         XMLStringToDataset.
       - Added parameter doNotExport to the Dataset*ToXML* methods containing
         semicolon-delimited list of fields not to be exported.
       - Added parameter doNotImport to the XML*ToDataset* methods containing
         semicolon-delimited list of fields not to be imported.
       - Added optional parameter outputFormat to the DatasetToXMLDocument
         method.
       - DatasetToXML wrapped into ds.DisableControls/ds.EnableControls. This
         also applies to all DatasetToXML* methods. Initial position in the
         dataset is now preserved.
       - Fixed XMLNodeToDatasetRow to ignore case of the field name.
       - Added testing for rootTag non-emptiness.
       - Added <?xml version="1.0"?> to the exported XML document.
       - Modified XMLToDataset method to skip non-ELEMENT_NODE nodes so one can
         add comments to the XML file.
       - Modified XML*ToDataset* methods to raise exception EOmniXMLDatabase
         on errors.
       - Modified XMLNodeToDatasetRow to raise exception EOmniXMLDatabase if
         XML field doesn't exist in the table. This exception can be skipped
         if option odbIgnoreMissingColumns is passed to the XML*ToDataset*
         method.
       - Modified XMLNodeToDatasetRow to raise exception EOmniXMLDatabase if
         database column is not of a supported type. This exception can be
         skipped if option odbIgnoreUnsupportedColumns is passed to the
         XML*ToDataset* method.
       - Modified DatasetRowToXMLNode to raise exception EOmniXMLDatabase if
         database column is not of a supported type. This exception can be
         skipped if option odbIgnoreUnsupportedColumns is passed to the
         Dataset*ToXML* method.
     1.02: 2002-12-09
       - MSXML compatible (define USE_MSXML).
     1.01a: 2002-11-05
       - Modified function CleanupNodeName to use OmniXML.CharIs_Name.
     1.01: 2002-10-22
       - Updated to skip hidden fields (like DB_KEY returned from IBObjects
         queries).
       - Added numbers as valid tag characters (function CleanupNodeName).
     1.0: 2001-10-24
       - Created by extracting database-related functionality from unit GpXML.
*)

unit OmniXMLDatabase;

interface

uses
  SysUtils, Classes, DB,
  OmniXML
{$IFDEF USE_MSXML}, OmniXML_MSXML {$ENDIF USE_MSXML}
  ;

type
  //:OmniXMLDatabase-specific exception.
  EOmniXMLDatabase = Exception;

  //:Import-export options.
  TOmniXMLDatabaseOption = (odbIgnoreUnsupportedColumns, odbIgnoreMissingColumns);

  //:Set of all import-export options.
  TOmniXMLDatabaseOptions = set of TOmniXMLDatabaseOption; 

  {:Export currently selected dataset row to the XML node. Used internally in
    the DatasetToXML.
  }
  procedure DatasetRowToXMLNode(ds: TDataSet; dsNode: IXMLNode;
    const doNotExport: string = ''; options: TOmniXMLDatabaseOptions = []);

  {:Export dataset to the XML node. Child nodes will be used to store the data.
    Existing child nodes will be removed. To read data back into the dataset use
    the XMLToDataset function.
  }
  procedure DatasetToXML(ds: TDataSet; parentNode: IXMLNode;
    const doNotExport: string = ''; options: TOmniXMLDatabaseOptions = []);

  {:Export dataset to the XML document, then take string representation of the
    XML document and return it as as stream. Stream is emptied before it is
    written to.
  }
  procedure DatasetToXMLDocument(ds: TDataSet; xmlDocument: TStream;
    const rootTag: string; const doNotExport: string = '';
    outputFormat: TOutputFormat = ofNone; options: TOmniXMLDatabaseOptions = []);

  {:Export dataset to the XML document, then take string representation of the
    XML document and save it into a file.
  }
  procedure DatasetToXMLFile(ds: TDataSet; const xmlFileName: string;
    const rootTag: string; const doNotExport: string = '';
    outputFormat: TOutputFormat = ofNone; options: TOmniXMLDatabaseOptions = []);

  {:Export dataset to the XML document, then take string representation of the
    XML document and return it as as string.
  }
  function DatasetToXMLString(ds: TDataSet; const rootTag: string;
    const doNotExport: string = ''; outputFormat: TOutputFormat = ofNone;
    options: TOmniXMLDatabaseOptions = []): string;

  {:Append new dataset row, copy node data into equally-named fields, and post
    the changes.
  }
  procedure XMLNodeToDatasetRow(dsNode: IXMLNode; ds: TDataSet;
    const doNotImport: string = ''; options: TOmniXMLDatabaseOptions = []);

  {:Import data created with DatasetToXML from the XML node to the dataset.
    Existing dataset content won't be touched.
  }
  procedure XMLToDataset(parentNode: IXMLNode; ds: TDataSet;
    const doNotImport: string = ''; options: TOmniXMLDatabaseOptions = []);

  {:Create XML document from the textual representation stored in the stream,
    then copy its contents into the dataset. Dataset will be emptied before the
    import. XML document must be created with the DatasetToXML* call.
    Before reading, stream's position is reset to 0 and all data from the stream
    is read.
  }
  procedure XMLDocumentToDataset(xmlDocument: TStream; ds: TDataSet;
    const doNotImport: string = ''; options: TOmniXMLDatabaseOptions = []);

  {:Create XML document from the textual representation stored in the file,
    then copy its contents into the dataset. Dataset will be emptied before the
    import. XML document must be created with the DatasetToXML* call.
  }
  procedure XMLFileToDataset(const xmlFileName: string; ds: TDataSet;
    const doNotImport: string = ''; options: TOmniXMLDatabaseOptions = []);

  {:Create XML document from the textual representation stored in the string,
    then copy its contents into the dataset. Dataset will be emptied before the
    import. XML document must be created with the DatasetToXMLD* call.
  }
  procedure XMLStringToDataset(const xmlString: string; ds: TDataSet;
    const doNotImport: string = ''; options: TOmniXMLDatabaseOptions = []);

implementation

uses
  OmniXMLUtils;

const
  //:Node name to be used in TDataSet <-> XML conversion.
  CXMLDatasetRows = 'ROW'; // don't change!

  //:Atribute that specifies whether field is empty (NULL).
  CXMLFieldIsEmpty = 'isEmpty'; // don't change!

{:Clean XML node name to only contain valid characters. Unicode is politely
  ignored.
}
function CleanupNodeName(nodeName: string): string;
var
  iNodeName: integer;
begin
  SetLength(Result, Length(nodeName)); // best guess;
  for iNodeName := 1 to Length(nodeName) do begin
    if CharIs_Name(WideChar(nodeName[iNodeName]), false) then
      Result[iNodeName] := nodeName[iNodeName]
    else
      Result[iNodeName] := '_';
  end; //for iNodeName
  if (Length(nodeName) > 0) and (not CharIs_Name(WideChar(Result[1]), true)) then 
    Result[1] := 'z';
end; { CleanupNodeName }

{:@param   ds          Dataset row to be exported.
  @param   dsNode      XML node to take data from the dataset row. Existing
                       content will be removed.
  @param   doNotExport Semicolon-delimited list of fields that should not be
                       exported. No extraneous whitespace should be used.
  @param   options     Export options.
  @since   2001-09-09
}
procedure DatasetRowToXMLNode(ds: TDataSet; dsNode: IXMLNode;
  const doNotExport: string; options: TOmniXMLDatabaseOptions);
var
  field       : TField;
  fieldClass  : TFieldClass;
  fieldElement: IXMLElement;
  iField      : integer;
  memStr      : TMemoryStream;
  nodeName    : string;
  notExport   : string;
begin
  if doNotExport = '' then
    notExport := ''
  else
    notExport := ';' + doNotExport + ';';
  DeleteAllChildren(dsNode);
  for iField := 0 to ds.FieldDefs.Count-1 do begin
    if faHiddenCol in ds.fielddefs[iField].Attributes then
      continue;
    field := ds.Fields[iField];
    fieldClass := ds.FieldDefs[iField].FieldClass;
    if (notExport = '') or (Pos(';'+field.FieldName+';', notExport) = 0) then begin
      nodeName := CleanupNodeName(field.FieldName);
      fieldElement := dsNode.OwnerDocument.CreateElement(nodeName);
      dsNode.AppendChild(fieldElement);
      if field.IsNull then
        fieldElement.SetAttribute(CXMLFieldIsEmpty, XMLBoolToStr(true))
      else begin
        if (fieldClass = TStringField)     or
           (fieldClass = TStringField)     or
           (fieldClass = TWideStringField) or
           (fieldClass = TGuidField) then
          fieldElement.Text := field.AsString
        else if
           (fieldClass = TSmallIntField) or
           (fieldClass = TWordField)     or
           (fieldClass = TIntegerField) then
          fieldElement.Text := XMLIntToStr(field.AsInteger)
        else if fieldClass = TLargeIntField then
          fieldElement.Text := XMLInt64ToStr((field as TLargeintField).AsLargeInt)
        else if
           (fieldClass = TBCDField) or
           (fieldClass = TCurrencyField) then
          fieldElement.Text := XMLRealToStr(field.AsCurrency)
        else if fieldClass = TFloatField then
          fieldElement.Text := XMLRealToStr(field.AsFloat)
        else if fieldClass = TDateField then
          fieldElement.Text := XMLDateToStr(field.AsDateTime)
        else if fieldClass = TTimeField then
          fieldElement.Text := XMLTimeToStr(field.AsDateTime)
        else if fieldClass = TDateTimeField then
          fieldElement.Text := XMLDateTimeToStr(field.AsDateTime)
        else if fieldClass = TBooleanField then
          fieldElement.Text := XMLBoolToStr(field.AsBoolean)
        else if
           (fieldClass = TBlobField)    or
           (fieldClass = TGraphicField) or
           (fieldClass = TMemoField) then
        begin
          memStr := TMemoryStream.Create;
          try
            (field as TBLOBField).SaveToStream(memStr);
            memStr.Position := 0;
            SetNodeTextBinary(dsNode, nodeName, memStr);
          finally FreeAndNil(memStr); end;
        end
        else if
           (fieldClass = TBytesField)   or
           (fieldClass = TVarBytesField) then
        begin
          memStr := TMemoryStream.Create;
          try
            memStr.SetSize(field.DataSize);
            (field as TBytesField).GetData(memStr.Memory);
            SetNodeTextBinary(dsNode, nodeName, memStr);
          finally FreeAndNil(memStr); end;
        end
        else if fieldClass = TAutoIncField then
          // skipped
        else begin
          if not (odbIgnoreUnsupportedColumns in options) then
            raise EOmniXMLDatabase.CreateFmt('Unsupported column type in column %s', [field.FieldName]);
        end;
      end;
    end; //if notExport ...
  end; //for
end; { DatasetRowToXMLNode }

{:@param   ds          Dataset to be exported.
  @param   parentNode  Node containing exported data, stored in CXMLDatasetRows
                       children.
  @param   doNotExport Semicolon-delimited list of fields that should not be
                       exported. No extraneous whitespace should be used.
  @param   options     Export options.
  @since   2001-09-09
}        
procedure DatasetToXML(ds: TDataSet; parentNode: IXMLNode;
  const doNotExport: string; options: TOmniXMLDatabaseOptions);
var
  myNode  : IXMLNode;
  startPos: TBookmark;
begin
  DeleteAllChildren(parentNode, CXMLDatasetRows);
  ds.DisableControls;
  try
    startPos := ds.GetBookmark;
    try
      ds.First;
      while not ds.Eof do begin
        myNode := parentNode.OwnerDocument.CreateElement(CXMLDatasetRows);
        parentNode.AppendChild(myNode);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -