📄 jvsimplexml.pas
字号:
Date: '$Date: 2005/03/10 22:37:23 $';
LogPath: 'JVCL\run'
);
{$ENDIF UNITVERSIONING}
implementation
uses
{$IFDEF COMPILER5}
JvJCLUtils, // for StrToFloatDef
{$ENDIF COMPILER5}
JvConsts, JvResources;
const
cBufferSize = 8192;
DefaultTrueBoolStr = 'True'; // DO NOT LOCALIZE
DefaultFalseBoolStr = 'False'; // DO NOT LOCALIZE
var
GlobalSorts: TList = nil;
{$IFDEF COMPILER6_UP}
GlobalXMLVariant: TXMLVariant = nil;
{$ENDIF COMPILER6_UP}
{$IFDEF COMPILER5}
TrueBoolStrs: array of string;
FalseBoolStrs: array of string;
{$ENDIF COMPILER5}
function GSorts: TList;
begin
if not Assigned(GlobalSorts) then
GlobalSorts := TList.Create;
Result := GlobalSorts;
end;
{$IFDEF COMPILER6_UP}
function XMLVariant: TXMLVariant;
begin
if not Assigned(GlobalXMLVariant) then
GlobalXMLVariant := TXMLVariant.Create;
Result := GlobalXMLVariant;
end;
{$ENDIF COMPILER6_UP}
function EntityEncode(const S: string): string;
var
I, J, K, L: Integer;
tmp: string;
begin
SetLength(Result, Length(S) * 6); // worst case
J := 1;
I := 1;
L := Length(S);
while I <= L do
begin
case S[I] of
'"':
tmp := '"';
'&':
tmp := '&';
#39:
tmp := ''';
'<':
tmp := '<';
'>':
tmp := '>';
else
tmp := S[I];
end;
for K := 1 to Length(tmp) do
begin
Result[J] := tmp[K];
Inc(J);
end;
Inc(I);
end;
if J > 1 then
SetLength(Result, J - 1)
else
SetLength(Result, 0);
end;
function EntityDecode(const S: string): string;
var
I, J, L: Integer;
begin
Result := S;
I := 1;
J := 1;
L := Length(Result);
while I <= L do
begin
if Result[I] = '&' then
begin
if AnsiSameText(Copy(Result, I, 5), '&') then
begin
Result[J] := '&';
Inc(J);
Inc(I, 4);
end
else
if AnsiSameText(Copy(Result, I, 4), '<') then
begin
Result[J] := '<';
Inc(J);
Inc(I, 3);
end
else
if AnsiSameText(Copy(Result, I, 4), '>') then
begin
Result[J] := '>';
Inc(J);
Inc(I, 3);
end
else
if AnsiSameText(Copy(Result, I, 6), ''') then
begin
Result[J] := #39;
Inc(J);
Inc(I, 5);
end
else
if AnsiSameText(Copy(Result, I, 6), '"') then
begin
Result[J] := '"';
Inc(J);
Inc(I, 5);
end
else
begin
Result[J] := Result[I];
Inc(J);
end;
end
else
begin
Result[J] := Result[I];
Inc(J);
end;
Inc(I);
end;
if J > 1 then
SetLength(Result, J - 1)
else
SetLength(Result, 0);
end;
{$IFDEF COMPILER5}
procedure VerifyBoolStrArray;
begin
if Length(TrueBoolStrs) = 0 then
begin
SetLength(TrueBoolStrs, 1);
TrueBoolStrs[0] := DefaultTrueBoolStr;
end;
if Length(FalseBoolStrs) = 0 then
begin
SetLength(FalseBoolStrs, 1);
FalseBoolStrs[0] := DefaultFalseBoolStr;
end;
end;
function TryStrToFloat(const S: string; out Value: Extended): Boolean;
begin
Result := TextToFloat(PChar(S), Value, fvExtended);
end;
(* make Delphi 5 compiler happy // andreas
procedure ConvertErrorFmt(ResString: PResStringRec; const Args: array of const);
begin
raise EConvertError.CreateResFmt(ResString, Args);
end;
*)
function TryStrToBool(const S: string; out Value: Boolean): Boolean;
var
lResult: Extended;
function CompareWith(const AStrings: array of string): Boolean;
var
I: Integer;
begin
Result := False;
for I := Low(AStrings) to High(AStrings) do
if AnsiSameText(S, AStrings[I]) then
begin
Result := True;
Break;
end;
end;
begin
Result := TryStrToFloat(S, lResult);
if Result then
Value := lResult <> 0
else
begin
VerifyBoolStrArray;
Result := CompareWith(TrueBoolStrs);
if Result then
Value := True
else
begin
Result := CompareWith(FalseBoolStrs);
if Result then
Value := False;
end;
end;
end;
function StrToBoolDef(const S: string; const Default: Boolean): Boolean;
begin
if not TryStrToBool(S, Result) then
Result := Default;
end;
(* make Delphi 5 compiler happy // andreas
function StrToBool(const S: string): Boolean;
begin
if not TryStrToBool(S, Result) then
ConvertErrorFmt(@SInvalidBoolean, [S]);
end;
*)
function BoolToStr(B: Boolean; UseBoolStrs: Boolean = False): string;
const
cSimpleBoolStrs: array [Boolean] of string = ('0', '-1');
begin
if UseBoolStrs then
begin
VerifyBoolStrArray;
if B then
Result := TrueBoolStrs[0]
else
Result := FalseBoolStrs[0];
end
else
Result := cSimpleBoolStrs[B];
end;
{$ENDIF COMPILER5}
function SimpleXMLEncode(const S: string): string;
const
NoConversion = [#0..#127] - ['"', '&', #39, '<', '>'];
var
I, J, K: Integer;
tmp: string;
begin
SetLength(Result, Length(S) * 6); // worst case
J := 1;
for I := 1 to Length(S) do
begin
if S[I] in NoConversion then
Result[J] := S[I]
else
begin
case S[I] of
'"':
tmp := '"';
'&':
tmp := '&';
#39:
tmp := ''';
'<':
tmp := '<';
'>':
tmp := '>';
else
tmp := Format('&#x%.2x;', [Ord(S[I])]);
end;
for K := 1 to Length(tmp) do
begin
Result[J] := tmp[K];
Inc(J);
end;
Dec(J);
end;
Inc(J);
end;
if J > 0 then
SetLength(Result, J - 1)
else
SetLength(Result, 0);
end;
procedure SimpleXMLDecode(var S: string; TrimBlanks: Boolean);
var
StringLength, ReadIndex, WriteIndex: Cardinal;
procedure DecodeEntity(var S: string; StringLength: Cardinal;
var ReadIndex, WriteIndex: Cardinal);
const
cHexPrefix: array [Boolean] of PChar = ('', '$');
var
I: Cardinal;
Value: Integer;
IsHex: Boolean;
begin
Inc(ReadIndex, 2);
IsHex := (ReadIndex <= StringLength) and (S[ReadIndex] in ['x', 'X']);
Inc(ReadIndex, Ord(IsHex));
I := ReadIndex;
while ReadIndex <= StringLength do
begin
if S[ReadIndex] = ';' then
begin
Value := StrToIntDef(cHexPrefix[IsHex] + Copy(S, I, ReadIndex - I), -1); // no characters are less than 0
if Value > 0 then
S[WriteIndex] := Chr(Value)
else
ReadIndex := I - (2 + Cardinal(IsHex)); // reset to start
Exit;
end;
Inc(ReadIndex);
end;
ReadIndex := I - (2 + Cardinal(IsHex)); // reset to start
end;
procedure SkipBlanks(var S: string; StringLength: Cardinal; var ReadIndex: Cardinal);
begin
while ReadIndex < StringLength do
begin
if S[ReadIndex] = Cr then
S[ReadIndex] := Lf
else
if S[ReadIndex + 1] = Cr then
S[ReadIndex + 1] := Lf;
if (S[ReadIndex] < #33) and (S[ReadIndex] = S[ReadIndex + 1]) then
Inc(ReadIndex)
else
Exit;
end;
end;
begin
// NB! This procedure replaces the text inplace to speed up the conversion. This
// works because when decoding, the string can only become shorter. This is
// accomplished by keeping track of the current read and write points.
// In addition, the original string length is read only once and passed to the
// inner procedures to speed up conversion as much as possible
ReadIndex := 1;
WriteIndex := 1;
StringLength := Length(S);
while ReadIndex <= StringLength do
begin
// this call lowers conversion speed by ~30%, ie 21MB/sec -> 15MB/sec (repeated tests, various inputs)
if TrimBlanks then
SkipBlanks(S, StringLength, ReadIndex);
if S[ReadIndex] = '&' then
begin
if S[ReadIndex + 1] = '#' then
begin
DecodeEntity(S, StringLength, ReadIndex, WriteIndex);
Inc(WriteIndex);
end
else
if AnsiSameText(Copy(S, ReadIndex, 5), '&') then
begin
S[WriteIndex] := '&';
Inc(WriteIndex);
Inc(ReadIndex, 4);
end
else
if AnsiSameText(Copy(S, ReadIndex, 4), '<') then
begin
S[WriteIndex] := '<';
Inc(WriteIndex);
Inc(ReadIndex, 3);
end
else
if AnsiSameText(Copy(S, ReadIndex, 4), '>') then
begin
S[WriteIndex] := '>';
Inc(WriteIndex);
Inc(ReadIndex, 3);
end
else
if AnsiSameText(Copy(S, ReadIndex, 6), ''') then
begin
S[WriteIndex] := #39;
Inc(WriteIndex);
Inc(ReadIndex, 5);
end
else
if AnsiSameText(Copy(S, ReadIndex, 6), '"') then
begin
S[WriteIndex] := '"';
Inc(WriteIndex);
Inc(ReadIndex, 5);
end
else
begin
S[WriteIndex] := S[ReadIndex];
Inc(WriteIndex);
end;
end
else
begin
S[WriteIndex] := S[ReadIndex];
Inc(WriteIndex);
end;
Inc(ReadIndex);
end;
if WriteIndex > 0 then
SetLength(S, WriteIndex - 1)
else
SetLength(S, 0);
// this call lowers conversion speed by ~65%, ie 21MB/sec -> 7MB/sec (repeated tests, various inputs)
// if TrimBlanks then
// S := AdjustLineBreaks(S);
end;
function XMLEncode(const S: string): string;
begin
Result := SimpleXMLEncode(S);
end;
function XMLDecode(const S: string): string;
begin
Result := S;
SimpleXMLDecode(Result, False);
end;
//=== { TJvSimpleXML } =======================================================
constructor TJvSimpleXML.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FRoot := TJvSimpleXMLElemClassic.Create(nil);
FRoot.FSimpleXML := Self;
FProlog := TJvSimpleXMLElemsProlog.Create;
FOptions := [sxoAutoIndent, sxoAutoEncodeValue, sxoAutoEncodeEntity];
FIndentString := ' ';
end;
destructor TJvSimpleXML.Destroy;
begin
FreeAndNil(FRoot);
FreeAndNil(FProlog);
inherited Destroy;
end;
procedure TJvSimpleXML.DoDecodeValue(var Value: string);
begin
if Assigned(FOnDecodeValue) then
FOnDecodeValue(Self, Value)
else
if sxoAutoEncodeValue in Options then
SimpleXMLDecode(Value, False)
else
if sxoAutoEncodeEntity in Options then
Value := EntityDecode(Value);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -