2
$Id: laz_xmlread.pas 22274 2009-10-24 10:23:12Z mattias $
3
This file is part of the Free Component Library
6
Copyright (c) 1999-2000 by Sebastian Guenther, sg@freepascal.org
8
See the file COPYING.FPC, included in this distribution,
9
for details about the copyright.
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15
**********************************************************************}
25
{off $DEFINE MEM_CHECK}
28
{$IFDEF MEM_CHECK}MemCheck,{$ENDIF}
29
SysUtils, Classes, types, Laz_DOM, FileProcs;
33
EXMLReadError = class(Exception)
41
procedure ReadXMLFile(out ADoc: TXMLDocument; const AFilename: String); overload;
42
procedure ReadXMLFile(out ADoc: TXMLDocument; var f: File); overload;
43
procedure ReadXMLFile(out ADoc: TXMLDocument; f: TStream); overload;
44
procedure ReadXMLFile(out ADoc: TXMLDocument; f: TStream; const AFilename: String); overload;
46
procedure ReadXMLFragment(AParentNode: TDOMNode; const AFilename: String); overload;
47
procedure ReadXMLFragment(AParentNode: TDOMNode; var f: File); overload;
48
procedure ReadXMLFragment(AParentNode: TDOMNode; var f: TStream); overload;
49
procedure ReadXMLFragment(AParentNode: TDOMNode; var f: TStream; const AFilename: String); overload;
51
procedure ReadDTDFile(var ADoc: TXMLDocument; const AFilename: String); overload;
52
procedure ReadDTDFile(var ADoc: TXMLDocument; var f: File); overload;
53
procedure ReadDTDFile(var ADoc: TXMLDocument; var f: TStream); overload;
54
procedure ReadDTDFile(var ADoc: TXMLDocument; var f: TStream; const AFilename: String); overload;
57
// =======================================================
63
Letter = ['A'..'Z', 'a'..'z'];
65
PubidChars: set of Char = [' ', #13, #10, 'a'..'z', 'A'..'Z', '0'..'9',
66
'-', '''', '(', ')', '+', ',', '.', '/', ':', '=', '?', ';', '!', '*',
67
'#', '@', '$', '_', '%'];
68
WhitespaceChars: set of Char = [#9, #10, #13, ' '];
70
NmToken: set of Char = Letter + Digit + ['.', '-', '_', ':'];
72
function ComparePChar(p1, p2: PChar): boolean;
75
if (p1<>nil) and (p2<>nil) then begin
77
if (p1^=p2^) then begin
99
function CompareLPChar(p1, p2: PChar; Max: integer): boolean;
102
if (p1<>nil) and (p2<>nil) then begin
104
if (p1^=p2^) then begin
105
if (p1^<>#0) then begin
127
function CompareIPChar(p1, p2: PChar): boolean;
130
if (p1<>nil) and (p2<>nil) then begin
132
if (p1^=p2^) or (upcase(p1^)=upcase(p2^)) then begin
133
if p1^<>#0 then begin
154
function CompareLIPChar(p1, p2: PChar; Max: integer): boolean;
157
if (p1<>nil) and (p2<>nil) then begin
159
if (p1^=p2^) or (upcase(p1^)=upcase(p2^)) then begin
160
if (p1^<>#0) then begin
184
TXMLReaderDocument = class(TXMLDocument)
186
procedure SetDocType(ADocType: TDOMDocumentType);
189
TXMLReaderDocumentType = class(TDOMDocumentType)
191
constructor Create(ADocument: TXMLReaderDocument);
192
property Name: DOMString read FNodeName write FNodeName;
196
TSetOfChar = set of Char;
202
buf, BufStart: PChar;
204
function BufPosToLineCol(p: PChar): TPoint;
205
function BufPosToStr(p: PChar): string;
206
procedure RaiseExc(const descr: String);
207
procedure RaiseCharNotFound(c : char);
208
function SkipWhitespace: Boolean;
209
procedure ExpectWhitespace; inline;
210
procedure ExpectChar(c: char); inline;
211
procedure ExpectString(const s: String);
212
function CheckFor(s: PChar): Boolean;
213
function CheckForChar(c: Char): Boolean;
214
procedure SkipString(const ValidChars: TSetOfChar);
215
function GetString(const ValidChars: TSetOfChar): String;
216
function GetString(BufPos: PChar; Len: integer): String;
218
function CheckName: Boolean;
219
function GetName(var s: String): Boolean;
220
function ExpectName: String; // [5]
222
procedure ExpectAttValue(attr: TDOMAttr); // [10]
223
function ExpectPubidLiteral: String; // [12]
224
procedure SkipPubidLiteral;
225
function ParseComment(AOwner: TDOMNode): Boolean; // [15]
226
function ParsePI: Boolean; // [16]
227
procedure ExpectProlog; // [22]
228
function ParseEq: Boolean; // [25]
230
procedure ParseMisc(AOwner: TDOMNode); // [27]
231
function ParseMarkupDecl: Boolean; // [29]
232
function ParseCharData(AOwner: TDOMNode): Boolean; // [14]
233
function ParseCDSect(AOwner: TDOMNode): Boolean; // [18]
234
function ParseElement(AOwner: TDOMNode): Boolean; // [39]
235
procedure ExpectElement(AOwner: TDOMNode);
236
function ParseReference(AOwner: TDOMNode): Boolean; // [67]
237
procedure ExpectReference(AOwner: TDOMNode);
238
function ParsePEReference: Boolean; // [69]
239
function ParseExternalID: Boolean; // [75]
240
procedure ExpectExternalID;
241
function ParseEncodingDecl: String; // [80]
242
procedure SkipEncodingDecl;
244
procedure ResolveEntities(RootNode: TDOMNode);
247
procedure ProcessXML(ABuf: PChar; const AFilename: String); // [1]
248
procedure ProcessFragment(AOwner: TDOMNode; ABuf: PChar; const AFilename: String);
249
procedure ProcessDTD(ABuf: PChar; const AFilename: String); // ([29])
252
{ TXMLReaderDocument }
254
procedure TXMLReaderDocument.SetDocType(ADocType: TDOMDocumentType);
256
FDocType := ADocType;
260
constructor TXMLReaderDocumentType.Create(ADocument: TXMLReaderDocument);
262
inherited Create(ADocument);
265
function TXMLReader.BufPosToLineCol(p: PChar): TPoint;
271
// find out the line in which the error occured
275
while apos < p do begin
276
if apos^ in [#10,#13] then begin
279
if (apos[1] in [#10,#13]) and (apos[0]<>apos[1]) then
289
function TXMLReader.BufPosToStr(p: PChar): string;
293
// find out the line in which the error occured
294
LineCol:=BufPosToLineCol(BufStart);
295
Result:=IntToStr(LineCol.y)+','+IntToStr(LineCol.x);
298
procedure TXMLReader.RaiseExc(const descr: String);
303
LineCol:=BufPosToLineCol(buf);
304
Err:=EXMLReadError.Create(
305
Filename+'('+IntToStr(LineCol.y)+','+IntToStr(LineCol.x)+') Error: ' + descr);
306
Err.Position:=buf-BufStart;
307
Err.LineCol:=LineCol;
312
procedure TXMLReader.RaiseCharNotFound(c: char);
314
RaiseExc('Expected "' + c + '", found "' + buf^ + '"');
317
function TXMLReader.SkipWhitespace: Boolean;
320
while buf[0] in WhitespaceChars do
327
procedure TXMLReader.ExpectWhitespace;
329
if not SkipWhitespace then
330
RaiseExc('Expected whitespace');
333
procedure TXMLReader.ExpectChar(c: char);
336
RaiseCharNotFound(c);
340
procedure TXMLReader.ExpectString(const s: String);
342
procedure RaiseStringNotFound;
347
GetMem(s2, Length(s) + 1);
348
StrLCopy(s2, buf, Length(s));
351
RaiseExc('Expected "' + s + '", found "' + s3 + '"');
357
for i := 1 to Length(s) do
358
if buf[i - 1] <> s[i] then begin
364
function TXMLReader.CheckFor(s: PChar): Boolean;
366
if buf[0] <> #0 then begin
367
if (buf[0]=s[0]) and (CompareLPChar(buf, s, StrLen(s))) then begin
377
function TXMLReader.CheckForChar(c: Char): Boolean;
379
if (buf[0]=c) and (c<>#0) then begin
387
procedure TXMLReader.SkipString(const ValidChars: TSetOfChar);
389
while buf[0] in ValidChars do begin
394
function TXMLReader.GetString(const ValidChars: TSetOfChar): String;
400
while buf[0] in ValidChars do begin
404
SetLength(Result, Len);
405
for i:=1 to len do begin
406
Result[i]:=OldBuf[0];
411
function TXMLReader.GetString(BufPos: PChar; Len: integer): string;
414
SetLength(Result,Len);
415
for i:=1 to Len do begin
416
Result[i]:=BufPos[0];
421
procedure TXMLReader.ProcessXML(ABuf: PChar; const AFilename: String); // [1]
425
Filename := AFilename;
427
doc := TXMLReaderDocument.Create;
429
{$IFDEF MEM_CHECK}CheckHeapWrtMemCnt('TXMLReader.ProcessXML A');{$ENDIF}
431
{$IFDEF MEM_CHECK}CheckHeapWrtMemCnt('TXMLReader.ProcessXML B');{$ENDIF}
434
// skip end of file characters
435
while buf^=#26 do inc(buf);
436
// check if whole document was read
438
RaiseExc('Text after end of document element found');
441
procedure TXMLReader.ProcessFragment(AOwner: TDOMNode; ABuf: PChar; const AFilename: String);
445
Filename := AFilename;
447
// do not call SkipWhitespace. They are needed by ParseCharData.
448
while ParseCharData(AOwner) or ParseCDSect(AOwner) or ParsePI or
449
ParseComment(AOwner) or ParseElement(AOwner) or
450
ParseReference(AOwner)
454
function TXMLReader.CheckName: Boolean;
457
if not (buf[0] in (Letter + ['_', ':'])) then begin
464
SkipString(Letter + ['0'..'9', '.', '-', '_', ':']);
469
function TXMLReader.GetName(var s: String): Boolean; // [5]
472
if not (buf[0] in (Letter + ['_', ':'])) then begin
480
SkipString(Letter + ['0'..'9', '.', '-', '_', ':']);
481
s := GetString(OldBuf,buf-OldBuf);
485
function TXMLReader.ExpectName: String; // [5]
487
procedure RaiseNameNotFound;
489
RaiseExc('Expected letter, "_" or ":" for name, found "' + buf[0] + '"');
494
if not (buf[0] in (Letter + ['_', ':'])) then
499
SkipString(Letter + ['0'..'9', '.', '-', '_', ':']);
500
Result:=GetString(OldBuf,buf-OldBuf);
503
procedure TXMLReader.SkipName;
505
procedure RaiseSkipNameNotFound;
507
RaiseExc('Expected letter, "_" or ":" for name, found "' + buf[0] + '"');
511
if not (buf[0] in (Letter + ['_', ':'])) then
512
RaiseSkipNameNotFound;
515
SkipString(Letter + ['0'..'9', '.', '-', '_', ':']);
518
procedure TXMLReader.ExpectAttValue(attr: TDOMAttr); // [10]
522
procedure FlushStringBuffer;
526
if OldBuf<>buf then begin
527
s := GetString(OldBuf,buf-OldBuf);
529
attr.AppendChild(doc.CreateTextNode(s));
537
if (buf[0] <> '''') and (buf[0] <> '"') then
538
RaiseExc('Expected quotation marks');
542
while (buf[0]<>StrDel) and (buf[0]<>#0) do begin
543
if buf[0] <> '&' then begin
547
if OldBuf<>buf then FlushStringBuffer;
548
ParseReference(attr);
552
if OldBuf<>buf then FlushStringBuffer;
554
ResolveEntities(Attr);
557
function TXMLReader.ExpectPubidLiteral: String;
559
SetLength(Result, 0);
560
if CheckForChar('''') then begin
561
SkipString(PubidChars - ['''']);
563
end else if CheckForChar('"') then begin
564
SkipString(PubidChars - ['"']);
567
RaiseExc('Expected quotation marks');
570
procedure TXMLReader.SkipPubidLiteral;
572
if CheckForChar('''') then begin
573
SkipString(PubidChars - ['''']);
575
end else if CheckForChar('"') then begin
576
SkipString(PubidChars - ['"']);
579
RaiseExc('Expected quotation marks');
582
function TXMLReader.ParseComment(AOwner: TDOMNode): Boolean; // [15]
587
if CheckFor('<!--') then begin
589
while (buf[0] <> #0) and (buf[1] <> #0) and
590
((buf[0] <> '-') or (buf[1] <> '-')) do begin
593
comment:=GetString(OldBuf,buf-OldBuf);
594
AOwner.AppendChild(doc.CreateComment(comment));
601
function TXMLReader.ParsePI: Boolean; // [16]
603
if CheckFor('<?') then begin
604
if CompareLIPChar(buf,'XML ',4) then
605
RaiseExc('"<?xml" processing instruction not allowed here');
607
if SkipWhitespace then
608
while (buf[0] <> #0) and (buf[1] <> #0) and not
609
((buf[0] = '?') and (buf[1] = '>')) do Inc(buf);
616
procedure TXMLReader.ExpectProlog; // [22]
618
procedure ParseVersionNum;
620
if doc.InheritsFrom(TXMLDocument) then
621
TXMLDocument(doc).XMLVersion :=
622
GetString(['a'..'z', 'A'..'Z', '0'..'9', '_', '.', ':', '-']);
625
procedure ParseDoctypeDecls;
629
until not (ParseMarkupDecl or ParsePEReference);
635
DocType: TXMLReaderDocumentType;
638
if CheckFor('<?xml') then
640
// '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
642
// VersionInfo: S 'version' Eq (' VersionNum ' | " VersionNum ")
644
ExpectString('version');
646
if buf[0] = '''' then
651
end else if buf[0] = '"' then
657
RaiseExc('Expected single or double quotation mark');
664
if CheckFor('standalone') then
667
if buf[0] = '''' then
670
if not (CheckFor('yes''') or CheckFor('no''')) then
671
RaiseExc('Expected ''yes'' or ''no''');
672
end else if buf[0] = '''' then
675
if not (CheckFor('yes"') or CheckFor('no"')) then
676
RaiseExc('Expected "yes" or "no"');
687
// Check for "(doctypedecl Misc*)?" [28]
688
if CheckFor('<!DOCTYPE') then
690
DocType := TXMLReaderDocumentType.Create(doc as TXMLReaderDocument);
691
if doc.InheritsFrom(TXMLReaderDocument) then
692
TXMLReaderDocument(doc).SetDocType(DocType);
694
DocType.Name := ExpectName;
696
if CheckForChar('[') then
701
end else if not CheckForChar('>') then
705
if CheckForChar('[') then
716
function TXMLReader.ParseEq: Boolean; // [25]
722
if buf[0] = '=' then begin
732
procedure TXMLReader.ExpectEq;
735
RaiseExc('Expected "="');
740
// Misc ::= Comment | PI | S
742
procedure TXMLReader.ParseMisc(AOwner: TDOMNode); // [27]
746
until not (ParseComment(AOwner) or ParsePI);
749
function TXMLReader.ParseMarkupDecl: Boolean; // [29]
751
function ParseElementDecl: Boolean; // [45]
753
procedure ExpectChoiceOrSeq; // [49], [50]
755
procedure ExpectCP; // [48]
757
if CheckForChar('(') then
761
if CheckForChar('?') then
762
else if CheckForChar('*') then
763
else if CheckForChar('+') then;
773
while not CheckForChar(')') do begin
774
if delimiter = #0 then begin
775
if (buf[0] = '|') or (buf[0] = ',') then
778
RaiseExc('Expected "|" or ","');
781
ExpectChar(delimiter);
788
if CheckFor('<!ELEMENT') then begin
793
// Get contentspec [46]
795
if CheckFor('EMPTY') then
796
else if CheckFor('ANY') then
797
else if CheckForChar('(') then begin
799
if CheckFor('#PCDATA') then begin
800
// Parse Mixed section [51]
802
if not CheckForChar(')') then
807
until CheckFor(')*');
809
// Parse Children section [47]
813
if CheckForChar('?') then
814
else if CheckForChar('*') then
815
else if CheckForChar('+') then;
818
RaiseExc('Invalid content specification');
827
function ParseAttlistDecl: Boolean; // [52]
831
if CheckFor('<!ATTLIST') then begin
835
while not CheckForChar('>') do begin
839
// Get AttType [54], [55], [56]
840
if CheckFor('CDATA') then
841
else if CheckFor('ID') then
842
else if CheckFor('IDREF') then
843
else if CheckFor('IDREFS') then
844
else if CheckFor('ENTITTY') then
845
else if CheckFor('ENTITIES') then
846
else if CheckFor('NMTOKEN') then
847
else if CheckFor('NMTOKENS') then
848
else if CheckFor('NOTATION') then begin // [57], [58]
854
while not CheckForChar(')') do begin
860
end else if CheckForChar('(') then begin // [59]
864
while not CheckForChar(')') do begin
871
RaiseExc('Invalid tokenized type');
875
// Get DefaultDecl [60]
876
if CheckFor('#REQUIRED') then
877
else if CheckFor('#IMPLIED') then
879
if CheckFor('#FIXED') then
881
attr := doc.CreateAttribute('');
882
ExpectAttValue(attr);
892
function ParseEntityDecl: Boolean; // [70]
894
NewEntity: TDOMEntity;
896
function ParseEntityValue: Boolean; // [9]
900
if (buf[0] <> '''') and (buf[0] <> '"') then begin
906
while not CheckForChar(strdel) do
907
if ParsePEReference then
908
else if ParseReference(NewEntity) then
910
Inc(buf); // Normal haracter
916
if CheckFor('<!ENTITY') then begin
918
if CheckForChar('%') then begin // [72]
920
NewEntity := doc.CreateEntity(ExpectName);
923
if ParseEntityValue then
924
else if ParseExternalID then
926
RaiseExc('Expected entity value or external ID');
927
end else begin // [71]
928
NewEntity := doc.CreateEntity(ExpectName);
930
// Get EntityDef [73]
931
if ParseEntityValue then
934
// Get NDataDecl [76]
936
ExpectString('NDATA');
948
function ParseNotationDecl: Boolean; // [82]
950
if CheckFor('<!NOTATION') then begin
954
if ParseExternalID then
955
else if CheckFor('PUBLIC') then begin // [83]
959
RaiseExc('Expected external or public ID');
969
while ParseElementDecl or ParseAttlistDecl or ParseEntityDecl or
970
ParseNotationDecl or ParsePI or ParseComment(doc) or SkipWhitespace do
974
procedure TXMLReader.ProcessDTD(ABuf: PChar; const AFilename: String);
978
Filename := AFilename;
980
doc := TXMLReaderDocument.Create;
984
if buf[0] <> #0 then begin
985
DebugLn('=== Unparsed: ===');
987
DebugLn(StrLen(buf), ' chars');
992
function TXMLReader.ParseCharData(AOwner: TDOMNode): Boolean; // [14]
999
while not (buf[0] in [#0, '<', '&']) do
1003
DataLen:=buf-OldBuf;
1006
// Check if chardata has non-whitespace content
1008
while (p<buf) and (p[0] in WhitespaceChars) do
1011
AOwner.AppendChild(doc.CreateTextNode(GetString(OldBuf,DataLen)));
1018
function TXMLReader.ParseCDSect(AOwner: TDOMNode): Boolean; // [18]
1022
if CheckFor('<![CDATA[') then
1025
while not CheckFor(']]>') do
1029
AOwner.AppendChild(doc.CreateCDATASection(GetString(OldBuf,buf-OldBuf-3))); { Copy CDATA, discarding terminator }
1036
function TXMLReader.ParseElement(AOwner: TDOMNode): Boolean; // [39] [40] [44]
1038
NewElem: TDOMElement;
1040
procedure CreateNameElement;
1048
{$IFDEF MEM_CHECK}CheckHeapWrtMemCnt(' CreateNameElement A');{$ENDIF}
1051
NewElem := doc.CreateElement(name);
1052
AOwner.AppendChild(NewElem);
1058
{$IFDEF MEM_CHECK}CheckHeapWrtMemCnt(' CreateNameElement E');{$ENDIF}
1059
if CheckFor('/>') then
1064
if CheckForChar('>') then
1067
// Get Attribute [41]
1068
attr := doc.CreateAttribute(ExpectName);
1069
NewElem.Attributes.SetNamedItem(attr);
1071
ExpectAttValue(attr);
1080
while ParseCharData(NewElem) or ParseCDSect(NewElem) or ParsePI or
1081
ParseComment(NewElem) or ParseElement(NewElem) or
1082
ParseReference(NewElem) do;
1086
FoundName:=ExpectName;
1087
if FoundName <> name then
1088
RaiseExc('Unmatching element end tag (expected "</' + name + '>", found "</'+FoundName+'>", start tag at '+BufPosToStr(StartPos)+')');
1093
{$IFDEF MEM_CHECK}CheckHeapWrtMemCnt(' CreateNameElement END');{$ENDIF}
1094
ResolveEntities(NewElem);
1101
if CheckForChar('<') then
1103
{$IFDEF MEM_CHECK}CheckHeapWrtMemCnt('TXMLReader.ParseElement A');{$ENDIF}
1104
if not CheckName then
1114
{$IFDEF MEM_CHECK}CheckHeapWrtMemCnt('TXMLReader.ParseElement END');{$ENDIF}
1117
procedure TXMLReader.ExpectElement(AOwner: TDOMNode);
1119
if not ParseElement(AOwner) then
1120
RaiseExc('Expected element');
1123
function TXMLReader.ParsePEReference: Boolean; // [69]
1125
if CheckForChar('%') then begin
1133
function TXMLReader.ParseReference(AOwner: TDOMNode): Boolean; // [67] [68]
1135
if not CheckForChar('&') then begin
1139
if CheckForChar('#') then begin // Test for CharRef [66]
1140
if CheckForChar('x') then begin
1141
// !!!: there must be at least one digit
1142
while buf[0] in ['0'..'9', 'a'..'f', 'A'..'F'] do Inc(buf);
1144
// !!!: there must be at least one digit
1145
while buf[0] in ['0'..'9'] do Inc(buf);
1147
AOwner.AppendChild(doc.CreateEntityReference(ExpectName));
1152
procedure TXMLReader.ExpectReference(AOwner: TDOMNode);
1154
if not ParseReference(AOwner) then
1155
RaiseExc('Expected reference ("&Name;" or "%Name;")');
1159
function TXMLReader.ParseExternalID: Boolean; // [75]
1161
function GetSystemLiteral: String;
1165
if buf[0] = '''' then begin
1168
while (buf[0] <> '''') and (buf[0] <> #0) do begin
1171
Result := GetString(OldBuf,buf-OldBuf);
1173
end else if buf[0] = '"' then begin
1176
while (buf[0] <> '"') and (buf[0] <> #0) do begin
1179
Result := GetString(OldBuf,buf-OldBuf);
1185
procedure SkipSystemLiteral;
1187
if buf[0] = '''' then begin
1189
while (buf[0] <> '''') and (buf[0] <> #0) do begin
1193
end else if buf[0] = '"' then begin
1195
while (buf[0] <> '"') and (buf[0] <> #0) do begin
1203
if CheckFor('SYSTEM') then begin
1207
end else if CheckFor('PUBLIC') then begin
1217
procedure TXMLReader.ExpectExternalID;
1219
if not ParseExternalID then
1220
RaiseExc('Expected external ID');
1223
function TXMLReader.ParseEncodingDecl: String; // [80]
1225
function ParseEncName: String;
1228
if not (buf[0] in ['A'..'Z', 'a'..'z']) then
1229
RaiseExc('Expected character (A-Z, a-z)');
1232
SkipString(['A'..'Z', 'a'..'z', '0'..'9', '.', '_', '-']);
1233
Result := GetString(OldBuf,buf-OldBuf);
1237
SetLength(Result, 0);
1239
if CheckFor('encoding') then begin
1241
if buf[0] = '''' then begin
1243
Result := ParseEncName;
1245
end else if buf[0] = '"' then begin
1247
Result := ParseEncName;
1253
procedure TXMLReader.SkipEncodingDecl;
1255
procedure ParseEncName;
1257
if not (buf[0] in ['A'..'Z', 'a'..'z']) then
1258
RaiseExc('Expected character (A-Z, a-z)');
1260
SkipString(['A'..'Z', 'a'..'z', '0'..'9', '.', '_', '-']);
1265
if CheckFor('encoding') then begin
1267
if buf[0] = '''' then begin
1271
end else if buf[0] = '"' then begin
1280
{ Currently, this method will only resolve the entities which are
1281
predefined in XML: }
1283
procedure TXMLReader.ResolveEntities(RootNode: TDOMNode);
1285
Node, NextNode: TDOMNode;
1287
procedure ReplaceEntityRef(EntityNode: TDOMNode; const Replacement: String);
1289
PrevSibling, NextSibling: TDOMNode;
1291
PrevSibling := EntityNode.PreviousSibling;
1292
NextSibling := EntityNode.NextSibling;
1293
if Assigned(PrevSibling) and (PrevSibling.NodeType = TEXT_NODE) then
1295
TDOMCharacterData(PrevSibling).AppendData(Replacement);
1296
RootNode.RemoveChild(EntityNode);
1297
if Assigned(NextSibling) and (NextSibling.NodeType = TEXT_NODE) then
1299
NextNode := NextSibling.NextSibling;
1300
TDOMCharacterData(PrevSibling).AppendData(
1301
TDOMCharacterData(NextSibling).Data);
1302
RootNode.RemoveChild(NextSibling);
1305
if Assigned(NextSibling) and (NextSibling.NodeType = TEXT_NODE) then
1307
TDOMCharacterData(NextSibling).InsertData(0, Replacement);
1308
RootNode.RemoveChild(EntityNode);
1310
RootNode.ReplaceChild(Doc.CreateTextNode(Replacement), EntityNode);
1314
Node := RootNode.FirstChild;
1315
while Assigned(Node) do
1317
NextNode := Node.NextSibling;
1318
if Node.NodeType = ENTITY_REFERENCE_NODE then
1319
if Node.NodeName = 'amp' then
1320
ReplaceEntityRef(Node, '&')
1321
else if Node.NodeName = 'apos' then
1322
ReplaceEntityRef(Node, '''')
1323
else if Node.NodeName = 'gt' then
1324
ReplaceEntityRef(Node, '>')
1325
else if Node.NodeName = 'lt' then
1326
ReplaceEntityRef(Node, '<')
1327
else if Node.NodeName = 'quot' then
1328
ReplaceEntityRef(Node, '"');
1335
procedure ReadXMLFile(out ADoc: TXMLDocument; var f: File);
1342
BufSize := FileSize(f) + 1;
1343
if BufSize <= 1 then
1346
GetMem(buf, BufSize);
1348
BlockRead(f, buf^, BufSize - 1);
1349
buf[BufSize - 1] := #0;
1350
Reader := TXMLReader.Create;
1352
Reader.ProcessXML(buf, TFileRec(f).name);
1354
ADoc := TXMLDocument(Reader.doc);
1362
procedure ReadXMLFile(out ADoc: TXMLDocument; f: TStream; const AFilename: String);
1368
if f.Size = 0 then exit;
1370
GetMem(buf, f.Size + 1);
1372
f.Read(buf^, f.Size);
1374
Reader := TXMLReader.Create;
1376
Reader.ProcessXML(buf, AFilename);
1378
ADoc := TXMLDocument(Reader.doc);
1386
procedure ReadXMLFile(out ADoc: TXMLDocument; f: TStream);
1388
ReadXMLFile(ADoc, f, '<Stream>');
1391
procedure ReadXMLFile(out ADoc: TXMLDocument; const AFilename: String);
1393
FileStream: TFileStream;
1394
MemStream: TMemoryStream;
1397
FileStream := TFileStream.Create(UTF8ToSys(AFilename), fmOpenRead or fmShareDenyWrite);
1398
if FileStream = nil then exit;
1399
MemStream := TMemoryStream.Create;
1401
MemStream.LoadFromStream(FileStream);
1402
ReadXMLFile(ADoc, MemStream, AFilename);
1409
procedure ReadXMLFragment(AParentNode: TDOMNode; var f: File);
1415
BufSize := FileSize(f) + 1;
1416
if BufSize <= 1 then
1419
GetMem(buf, BufSize);
1421
BlockRead(f, buf^, BufSize - 1);
1422
buf[BufSize - 1] := #0;
1423
Reader := TXMLReader.Create;
1425
Reader.Doc := AParentNode.OwnerDocument;
1426
Reader.ProcessFragment(AParentNode, buf, TFileRec(f).name);
1435
procedure ReadXMLFragment(AParentNode: TDOMNode; var f: TStream; const AFilename: String);
1443
GetMem(buf, f.Size + 1);
1445
f.Read(buf^, f.Size);
1447
Reader := TXMLReader.Create;
1448
Reader.Doc := AParentNode.OwnerDocument;
1450
Reader.ProcessFragment(AParentNode, buf, AFilename);
1459
procedure ReadXMLFragment(AParentNode: TDOMNode; var f: TStream);
1461
ReadXMLFragment(AParentNode, f, '<Stream>');
1464
procedure ReadXMLFragment(AParentNode: TDOMNode; const AFilename: String);
1468
Stream := TFileStream.Create(UTF8ToSys(AFilename), fmOpenRead or fmShareDenyWrite);
1470
ReadXMLFragment(AParentNode, Stream, AFilename);
1477
procedure ReadDTDFile(var ADoc: TXMLDocument; var f: File);
1484
BufSize := FileSize(f) + 1;
1485
if BufSize <= 1 then
1488
GetMem(buf, BufSize);
1490
BlockRead(f, buf^, BufSize - 1);
1491
buf[BufSize - 1] := #0;
1492
Reader := TXMLReader.Create;
1494
Reader.ProcessDTD(buf, TFileRec(f).name);
1495
ADoc := TXMLDocument(Reader.doc);
1504
procedure ReadDTDFile(var ADoc: TXMLDocument; var f: TStream; const AFilename: String);
1513
GetMem(buf, f.Size + 1);
1515
f.Read(buf^, f.Size);
1517
Reader := TXMLReader.Create;
1519
Reader.ProcessDTD(buf, AFilename);
1520
ADoc := TXMLDocument(Reader.doc);
1529
procedure ReadDTDFile(var ADoc: TXMLDocument; var f: TStream);
1531
ReadDTDFile(ADoc, f, '<Stream>');
1534
procedure ReadDTDFile(var ADoc: TXMLDocument; const AFilename: String);
1539
Stream := TFileStream.Create(UTF8ToSys(AFilename), fmOpenRead or fmShareDenyWrite);
1541
ReadDTDFile(ADoc, Stream, AFilename);