📄 fs_xml.pas
字号:
{******************************************}
{ }
{ FastScript v1.8 }
{ XML document }
{ }
{ (c) 2003-2005 by Alexander Tzyganenko, }
{ Fast Reports Inc }
{ }
{******************************************}
unit fs_xml;
interface
{$i fs.inc}
uses
SysUtils, Classes;
type
TfsXMLItem = class(TObject)
private
FData: Pointer; { optional item data }
FItems: TList; { subitems }
FName: String; { item name }
FParent: TfsXMLItem; { item parent }
FText: String; { item attributes }
function GetCount: Integer;
function GetItems(Index: Integer): TfsXMLItem;
function GetProp(Index: String): String;
procedure SetProp(Index: String; const Value: String);
procedure SetParent(const Value: TfsXMLItem);
public
destructor Destroy; override;
procedure AddItem(Item: TfsXMLItem);
procedure Assign(Item: TfsXMLItem);
procedure Clear;
procedure InsertItem(Index: Integer; Item: TfsXMLItem);
function Add: TfsXMLItem;
function Find(const Name: String): Integer;
function FindItem(const Name: String): TfsXMLItem;
function IndexOf(Item: TfsXMLItem): Integer;
function PropExists(const Index: String): Boolean;
function Root: TfsXMLItem;
property Count: Integer read GetCount;
property Data: Pointer read FData write FData;
property Items[Index: Integer]: TfsXMLItem read GetItems; default;
property Name: String read FName write FName;
property Parent: TfsXMLItem read FParent write SetParent;
property Prop[Index: String]: String read GetProp write SetProp;
property Text: String read FText write FText;
end;
TfsXMLDocument = class(TObject)
private
FAutoIndent: Boolean; { use indents when writing document to a file }
FRoot: TfsXMLItem; { root item }
public
constructor Create;
destructor Destroy; override;
procedure Clear;
procedure SaveToStream(Stream: TStream);
procedure LoadFromStream(Stream: TStream);
procedure SaveToFile(const FileName: String);
procedure LoadFromFile(const FileName: String);
property AutoIndent: Boolean read FAutoIndent write FAutoIndent;
property Root: TfsXMLItem read FRoot;
end;
{ TfsXMLReader and TfsXMLWriter are doing actual read/write to the XML file.
Read/write process is buffered. }
TfsXMLReader = class(TObject)
private
FBuffer: PChar;
FBufPos: Integer;
FBufEnd: Integer;
FPosition: Int64;
FSize: Int64;
FStream: TStream;
procedure SetPosition(const Value: Int64);
procedure ReadBuffer;
procedure ReadItem(var Name, Text: String);
public
constructor Create(Stream: TStream);
destructor Destroy; override;
procedure RaiseException;
procedure ReadHeader;
procedure ReadRootItem(Item: TfsXMLItem);
property Position: Int64 read FPosition write SetPosition;
property Size: Int64 read FSize;
end;
TfsXMLWriter = class(TObject)
private
FAutoIndent: Boolean;
FBuffer: String;
FStream: TStream;
FTempStream: TStream;
procedure FlushBuffer;
procedure WriteLn(const s: String);
procedure WriteItem(Item: TfsXMLItem; Level: Integer = 0);
public
constructor Create(Stream: TStream);
procedure WriteHeader;
procedure WriteRootItem(RootItem: TfsXMLItem);
property TempStream: TStream read FTempStream write FTempStream;
end;
{ StrToXML changes '<', '>', '"', cr, lf symbols to its ascii codes }
function StrToXML(const s: String): String;
{ ValueToXML convert a value to the valid XML string }
function ValueToXML(const Value: Variant): String;
{ XMLToStr is opposite to StrToXML function }
function XMLToStr(const s: String): String;
implementation
function StrToXML(const s: String): String;
const
SpecChars = ['<', '>', '"', #10, #13];
var
i: Integer;
procedure ReplaceChars(var s: String; i: Integer);
begin
Insert('#' + IntToStr(Ord(s[i])) + ';', s, i + 1);
s[i] := '&';
end;
begin
Result := s;
for i := Length(s) downto 1 do
if s[i] in SpecChars then
ReplaceChars(Result, i);
end;
function XMLToStr(const s: String): String;
var
i, j, h, n: Integer;
begin
Result := s;
i := 1;
n := Length(s);
while i < n do
begin
if i + 3 <= n then
if (Result[i] = '&') and (Result[i + 1] = '#') then
begin
j := i + 3;
while Result[j] <> ';' do
Inc(j);
h := StrToInt(Copy(Result, i + 2, j - i - 2));
Delete(Result, i, j - i);
Result[i] := Chr(h);
Dec(n, j - i);
end;
Inc(i);
end;
end;
function ValueToXML(const Value: Variant): String;
begin
case TVarData(Value).VType of
varSmallint, varInteger, varByte:
Result := IntToStr(Value);
varSingle, varDouble, varCurrency:
Result := FloatToStr(Value);
varDate:
Result := DateToStr(Value);
varOleStr, varString, varVariant:
Result := StrToXML(Value);
varBoolean:
if Value = True then Result := '1' else Result := '0';
else
Result := '';
end;
end;
{ TfsXMLItem }
destructor TfsXMLItem.Destroy;
begin
Clear;
if FParent <> nil then
FParent.FItems.Remove(Self);
inherited;
end;
procedure TfsXMLItem.Clear;
begin
if FItems <> nil then
begin
while FItems.Count > 0 do
TfsXMLItem(FItems[0]).Free;
FItems.Free;
FItems := nil;
end;
end;
function TfsXMLItem.GetItems(Index: Integer): TfsXMLItem;
begin
Result := TfsXMLItem(FItems[Index]);
end;
function TfsXMLItem.GetCount: Integer;
begin
if FItems = nil then
Result := 0 else
Result := FItems.Count;
end;
function TfsXMLItem.Add: TfsXMLItem;
begin
Result := TfsXMLItem.Create;
AddItem(Result);
end;
procedure TfsXMLItem.AddItem(Item: TfsXMLItem);
begin
if FItems = nil then
FItems := TList.Create;
FItems.Add(Item);
if Item.FParent <> nil then
Item.FParent.FItems.Remove(Item);
Item.FParent := Self;
end;
procedure TfsXMLItem.InsertItem(Index: Integer; Item: TfsXMLItem);
begin
AddItem(Item);
FItems.Delete(FItems.Count - 1);
FItems.Insert(Index, Item);
end;
procedure TfsXMLItem.SetParent(const Value: TfsXMLItem);
begin
if FParent <> nil then
FParent.FItems.Remove(Self);
FParent := Value;
end;
function TfsXMLItem.Find(const Name: String): Integer;
var
i: Integer;
begin
Result := -1;
for i := 0 to Count - 1 do
if AnsiCompareText(Items[i].Name, Name) = 0 then
begin
Result := i;
break;
end;
end;
function TfsXMLItem.FindItem(const Name: String): TfsXMLItem;
var
i: Integer;
begin
i := Find(Name);
if i = -1 then
begin
Result := Add;
Result.Name := Name;
end
else
Result := Items[i];
end;
function TfsXMLItem.Root: TfsXMLItem;
begin
Result := Self;
while Result.Parent <> nil do
Result := Result.Parent;
end;
function TfsXMLItem.GetProp(Index: String): String;
var
i: Integer;
begin
i := Pos(' ' + AnsiUppercase(Index) + '="', AnsiUppercase(' ' + FText));
if i <> 0 then
begin
Result := Copy(FText, i + Length(Index + '="'), MaxInt);
Result := XMLToStr(Copy(Result, 1, Pos('"', Result) - 1));
end
else
Result := '';
end;
procedure TfsXMLItem.SetProp(Index: String; const Value: String);
var
i, j: Integer;
s: String;
begin
i := Pos(' ' + AnsiUppercase(Index) + '="', AnsiUppercase(' ' + FText));
if i <> 0 then
begin
j := i + Length(Index + '="');
while (j <= Length(FText)) and (FText[j] <> '"') do
Inc(j);
Delete(FText, i, j - i + 1);
end
else
i := Length(FText) + 1;
s := Index + '="' + StrToXML(Value) + '"';
if (i > 1) and (FText[i - 1] <> ' ') then
s := ' ' + s;
Insert(s, FText, i);
end;
function TfsXMLItem.PropExists(const Index: String): Boolean;
begin
Result := Pos(' ' + AnsiUppercase(Index) + '="', ' ' + AnsiUppercase(FText)) > 0;
end;
function TfsXMLItem.IndexOf(Item: TfsXMLItem): Integer;
begin
Result := FItems.IndexOf(Item);
end;
procedure TfsXMLItem.Assign(Item: TfsXMLItem);
procedure DoAssign(ItemFrom, ItemTo: TfsXMLItem);
var
i: Integer;
begin
ItemTo.Name := ItemFrom.Name;
ItemTo.Text := ItemFrom.Text;
ItemTo.Data := ItemFrom.Data;
for i := 0 to ItemFrom.Count - 1 do
DoAssign(ItemFrom[i], ItemTo.Add);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -