📄 jvqsimplexml.pas
字号:
lName := '';
lPropStart := ' ';
lPos := ptWaiting;
// We read from a stream, thus replacing the existing properties
Clear;
repeat
Count := Stream.Read(lBuf, SizeOf(lBuf));
for I := 0 to Count - 1 do
begin
//Increment Stream pos for after comment
Inc(lStreamPos);
case lPos of
ptWaiting: //We are waiting for a property
begin
case lBuf[I] of
' ', Tab, Cr, Lf:
begin
end;
'a'..'z', 'A'..'Z', '0'..'9', '-', '_':
begin
lName := lBuf[I];
lPointer := '';
lPos := ptReadingName;
end;
'/', '>', '?':
begin
Dec(lStreamPos);
Count := 0;
Break;
end;
else
FmtError(RsEInvalidXMLElementUnexpectedCharacte, [lBuf[I]]);
end;
end;
ptReadingName: //We are reading a property name
case lBuf[I] of
'a'..'z', 'A'..'Z', '0'..'9', '-', '_':
lName := lName + lBuf[I];
':':
begin
lPointer := lName;
lName := '';
end;
'=':
lPos := ptStartingContent;
' ', Tab, Cr, Lf:
lPos := ptSpaceBeforeEqual;
else
FmtError(RsEInvalidXMLElementUnexpectedCharacte, [lBuf[I]]);
end;
ptStartingContent: //We are going to start a property content
case lBuf[I] of
' ', Tab, Cr, Lf:
; // ignore white space
'''', '"':
begin
lPropStart := lBuf[I];
lValue := '';
lPos := ptReadingValue;
end;
else
FmtError(RsEInvalidXMLElementUnexpectedCharacte_, [lBuf[I]]);
end;
ptReadingValue: //We are reading a property
if lBuf[I] = lPropStart then
begin
if (GetSimpleXML <> nil) then
GetSimpleXML.DoDecodeValue(lValue);
with Add(lName, lValue) do
Pointer := lPointer;
lPos := ptWaiting;
end
else
lValue := lValue + lBuf[I];
ptSpaceBeforeEqual: // We are reading the white space between a property name and the = sign
case lBuf[I] of
' ', Tab, Cr, Lf:
; // more white space, stay in this state and ignore
'=':
lPos := ptStartingContent;
else
FmtError(RsEInvalidXMLElementUnexpectedCharacte, [lBuf[I]]);
end;
else
Assert(False, RsEUnexpectedValueForLPos);
end;
end;
until Count = 0;
Stream.Seek(lStreamPos, soFromBeginning);
end;
procedure TJvSimpleXMLProps.SaveToStream(const Stream: TStream);
var
St: string;
I: Integer;
begin
St := '';
for I := 0 to Count - 1 do
St := St + Item[I].SaveToString;
if St <> '' then
Stream.Write(St[1], Length(St));
end;
function TJvSimpleXMLProps.Value(const Name: string; Default: string): string;
var
Prop: TJvSimpleXMLProp;
begin
Result := '';
Prop := GetItemNamedDefault(Name, Default);
if Prop = nil then
Result := Default
else
Result := Prop.Value;
end;
//=== { TJvSimpleXMLProp } ===================================================
function TJvSimpleXMLProp.GetBoolValue: Boolean;
begin
Result := StrToBoolDef(Value, False);
end;
function TJvSimpleXMLProp.GetFloatValue: Extended;
begin
Result := StrToFloatDef(Value, 0.0);
end;
function TJvSimpleXMLProp.GetIntValue: Int64;
begin
Result := StrToInt64Def(Value, -1);
end;
function TJvSimpleXMLProp.GetSimpleXML: TJvSimpleXML;
begin
if (FParent <> nil) and (FParent.FParent <> nil) then
Result := FParent.FParent.GetSimpleXML
else
Result := nil;
end;
function TJvSimpleXMLProp.SaveToString: string;
var
AEncoder: TJvSimpleXML;
tmp:string;
begin
AEncoder := GetSimpleXML;
tmp := FValue;
if Pointer <> '' then
begin
if AEncoder <> nil then
AEncoder.DoEncodeValue(tmp);
Result := Format(' %s:%s="%s"', [Pointer, Name, tmp]);
end
else
begin
if AEncoder <> nil then
AEncoder.DoEncodeValue(tmp);
Result := Format(' %s="%s"', [Name, tmp]);
end;
end;
procedure TJvSimpleXMLProp.SetBoolValue(const Value: Boolean);
begin
FValue := BoolToStr(Value);
end;
procedure TJvSimpleXMLProp.SetFloatValue(const Value: Extended);
begin
FValue := FloatToStr(Value);
end;
procedure TJvSimpleXMLProp.SetIntValue(const Value: Int64);
begin
FValue := IntToStr(Value);
end;
procedure TJvSimpleXMLProp.SetName(const Value: string);
begin
if (Value <> FName) and (Value <> '') then
begin
if (Parent <> nil) and (FName <> '') then
Parent.DoItemRename(Self, Value);
FName := Value;
end;
end;
//=== { TJvSimpleXMLElemClassic } ============================================
procedure TJvSimpleXMLElemClassic.LoadFromStream(const Stream: TStream; Parent: TJvSimpleXML);
//<element Prop="foo" Prop='bar'/>
//<element Prop="foo" Prop='bar'>foor<b>beuh</b>bar</element>
//<xml:element Prop="foo" Prop='bar'>foor<b>beuh</b>bar</element>
var
I, lStreamPos, Count, lPos: Integer;
lBuf: array [0..cBufferSize - 1] of Char;
St, lName, lValue, lPointer: string;
begin
lStreamPos := Stream.Position;
St := '';
lValue := '';
lPointer := '';
lPos := 1;
repeat
Count := Stream.Read(lBuf, SizeOf(lBuf));
if Parent <> nil then
Parent.DoLoadProgress(Stream.Position, Stream.Size);
for I := 0 to Count - 1 do
begin
//Increment Stream pos for after comment
Inc(lStreamPos);
case lPos of
1:
if lBuf[I] = '<' then
lPos := 2
else
FmtError(RsEInvalidXMLElementExpectedBeginningO, [lBuf[I]]);
-1:
if lBuf[I] = '>' then
begin
Count := 0;
Break;
end
else
FmtError(RsEInvalidXMLElementExpectedEndOfTagBu, [lBuf[I]]);
else
begin
if lBuf[I] in [Tab, Lf, Cr, ' ' {, '.'}] then
begin
if lPos = 2 then
Error(RsEInvalidXMLElementMalformedTagFoundn);
Stream.Seek(lStreamPos, soFromBeginning);
Properties.LoadFromStream(Stream);
lStreamPos := Stream.Position;
Break; //Re read buffer
end
else
begin
case lBuf[I] of
'>':
begin
lName := St;
//Load elements
Stream.Seek(lStreamPos, soFromBeginning);
St := Items.LoadFromStream(Stream, Parent);
if lName <> St then
FmtError(RsEInvalidXMLElementErroneousEndOfTagE, [lName, St]);
lStreamPos := Stream.Position;
//Set value if only one sub element
//This might reduce speed, but this is for compatibility issues
if (Items.Count = 1) and (Items[0] is TJvSimpleXMLElemText) then
begin
lValue := Items[0].Value;
Items.Clear;
end;
Count := 0;
Break;
end;
'/':
begin
lName := St;
lPos := -1;
end;
':':
begin
lPointer := St;
St := '';
end;
else
begin
St := St + lBuf[I];
Inc(lPos);
end;
end;
end;
end;
end;
end;
until Count = 0;
Name := lName;
if GetSimpleXML <> nil then
GetSimpleXML.DoDecodeValue(lValue);
Value := lValue;
Pointer := lPointer;
if Parent <> nil then
begin
Parent.DoTagParsed(lName);
Parent.DoValueParsed(lName, lValue);
end;
Stream.Seek(lStreamPos, soFromBeginning);
end;
procedure TJvSimpleXMLElemClassic.SaveToStream(const Stream: TStream; const Level: string; Parent: TJvSimpleXML);
var
St, AName, tmp: string;
LevelAdd: string;
begin
AName := Name;
if Name <> '' then
begin
if GetSimpleXML <> nil then
GetSimpleXML.DoEncodeValue(AName);
St := Level + '<' + AName;
Stream.Write(St[1], Length(St));
Properties.SaveToStream(Stream);
end;
if (Items.Count = 0) then
begin
tmp := FValue;
if (Name <> '') then
begin
if Value = '' then
St := '/>' + sLineBreak
else
begin
if GetSimpleXML <> nil then
GetSimpleXML.DoEncodeValue(tmp);
St := '>' + tmp + '</' + AName + '>' + sLineBreak;
end;
Stream.Write(St[1], Length(St));
end;
end
else
begin
if (Name <> '') then
begin
St := '>' + sLineBreak;
Stream.Write(St[1], Length(St));
end;
if Assigned(SimpleXML) and
(sxoAutoIndent in SimpleXML.Options) then
begin
LevelAdd := SimpleXML.IndentString;
end;
Items.SaveToStream(Stream, Level + LevelAdd, Parent);
if Name <> '' then
begin
St := Level + '</' + AName + '>' + sLineBreak;
Stream.Write(St[1], Length(St));
end;
end;
if Parent <> nil then
Parent.DoSaveProgress;
end;
//=== { TJvSimpleXMLElemComment } ============================================
procedure TJvSimpleXMLElemComment.LoadFromStream(const Stream: TStream; Parent: TJvSimpleXML);
//<!-- declarations for <head> & <body> -->
const
CS_START_COMMENT = '<!--';
CS_STOP_COMMENT = ' -->';
var
I, lStreamPos, Count, lPos: Integer;
lBuf: array [0..cBufferSize - 1] of Char;
St: string;
lOk: Boolean;
begin
lStreamPos := Stream.Position;
St := '';
lPos := 1;
lOk := False;
repeat
Count := Stream.Read(lBuf, SizeOf(lBuf));
if Parent <> nil then
Parent.DoLoadProgress(Stream.Position, Stream.Size);
for I := 0 to Count - 1 do
begin
//Increment Stream pos for after comment
Inc(lStreamPos);
case lPos of
1..4: //<!--
if lBuf[I] = CS_START_COMMENT[lPos] then
Inc(lPos)
else
FmtError(RsEInvalidCommentExpectedsButFounds, [CS_START_COMMENT[lPos], lBuf[I]]);
5:
if lBuf[I] = CS_STOP_COMMENT[lPos] then
Inc(lPos)
else
St := St + lBuf[I];
6: //-
if lBuf[I] = CS_STOP_COMMENT[lPos] then
Inc(lPos)
else
begin
St := St + '-' + lBuf[I];
Dec(lPos);
end;
7: //>
if lBuf[I] = CS_STOP_COMMENT[lPos] then
begin
Count := 0; //End repeat
lOk := True;
Break; //End if
end
else
begin
if lBuf[I + 1] <> '>' then
Error(RsEInvalidCommentNotAllowedInsideComme);
St := St + '--' + lBuf[I];
Dec(lPos, 2);
end;
end;
end;
until Count = 0;
if not lOk then
Error(RsEInvalidCommentUnexpectedEndOfData);
Value := St;
Name := '';
if Parent <> nil then
Parent.DoValueParsed('', St);
Stream.Seek(lStreamPos, soFromBeginning);
end;
procedure TJvSimpleXMLElemComment.SaveToStream(const Stream: TStream; const Level: string; Parent: TJvSimpleXML);
var
St: string;
begin
St := Level + '<!--';
Stream.Write(St[1], Length(St));
if Value <> '' then
Stream.Write(Value[1], Length(Value));
St := '-->' + sLineBreak;
Stream.Write(St[1], Length(St));
if Parent <> nil then
Parent.DoSaveProgress;
end;
//=== { TJvSimpleXMLElemCData } ==============================================
procedure TJvSimpleXMLElemC
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -