2
This file is part of the Free Component Library
5
Copyright (c) 1999-2000 by Sebastian Guenther, sg@freepascal.org
7
See the file COPYING.FPC, included in this distribution,
8
for details about the copyright.
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
**********************************************************************}
24
{off $DEFINE MEM_CHECK}
27
{$IFDEF MEM_CHECK}MemCheck,{$ENDIF}
28
SysUtils, Classes, types, LazUTF8, Laz_DOM;
32
EXMLReadError = class(Exception)
40
procedure ReadXMLFile(out ADoc: TXMLDocument; const AFilename: String); overload;
41
procedure ReadXMLFile(out ADoc: TXMLDocument; var f: File); overload;
42
procedure ReadXMLFile(out ADoc: TXMLDocument; f: TStream); overload;
43
procedure ReadXMLFile(out ADoc: TXMLDocument; f: TStream; const AFilename: String); overload;
45
procedure ReadXMLFragment(AParentNode: TDOMNode; const AFilename: String); overload;
46
procedure ReadXMLFragment(AParentNode: TDOMNode; var f: File); overload;
47
procedure ReadXMLFragment(AParentNode: TDOMNode; var f: TStream); overload;
48
procedure ReadXMLFragment(AParentNode: TDOMNode; var f: TStream; const AFilename: String); overload;
50
procedure ReadDTDFile(var ADoc: TXMLDocument; const AFilename: String); overload;
51
procedure ReadDTDFile(var ADoc: TXMLDocument; var f: File); overload;
52
procedure ReadDTDFile(var ADoc: TXMLDocument; var f: TStream); overload;
53
procedure ReadDTDFile(var ADoc: TXMLDocument; var f: TStream; const AFilename: String); overload;
56
// =======================================================
62
Letter = ['A'..'Z', 'a'..'z'];
64
PubidChars: set of Char = [' ', #13, #10, 'a'..'z', 'A'..'Z', '0'..'9',
65
'-', '''', '(', ')', '+', ',', '.', '/', ':', '=', '?', ';', '!', '*',
66
'#', '@', '$', '_', '%'];
67
WhitespaceChars: set of Char = [#9, #10, #13, ' '];
69
NmToken: set of Char = Letter + Digit + ['.', '-', '_', ':'];
71
function ComparePChar(p1, p2: PChar): boolean;
74
if (p1<>nil) and (p2<>nil) then begin
76
if (p1^=p2^) then begin
98
function CompareLPChar(p1, p2: PChar; Max: integer): boolean;
101
if (p1<>nil) and (p2<>nil) then begin
103
if (p1^=p2^) then begin
104
if (p1^<>#0) then begin
126
function CompareIPChar(p1, p2: PChar): boolean;
129
if (p1<>nil) and (p2<>nil) then begin
131
if (p1^=p2^) or (upcase(p1^)=upcase(p2^)) then begin
132
if p1^<>#0 then begin
153
function CompareLIPChar(p1, p2: PChar; Max: integer): boolean;
156
if (p1<>nil) and (p2<>nil) then begin
158
if (p1^=p2^) or (upcase(p1^)=upcase(p2^)) then begin
159
if (p1^<>#0) then begin
183
TXMLReaderDocument = class(TXMLDocument)
185
procedure SetDocType(ADocType: TDOMDocumentType);
188
TXMLReaderDocumentType = class(TDOMDocumentType)
190
constructor Create(ADocument: TXMLReaderDocument);
191
property Name: DOMString read FNodeName write FNodeName;
195
TSetOfChar = set of Char;
201
buf, BufStart: PChar;
203
function BufPosToLineCol(p: PChar): TPoint;
204
function BufPosToStr(p: PChar): string;
205
procedure RaiseExc(const descr: String);
206
procedure RaiseCharNotFound(c : char);
207
function SkipWhitespace: Boolean;
208
procedure ExpectWhitespace; inline;
209
procedure ExpectChar(c: char); inline;
210
procedure ExpectString(const s: String);
211
function CheckFor(s: PChar): Boolean;
212
function CheckForChar(c: Char): Boolean;
213
procedure SkipString(const ValidChars: TSetOfChar);
214
function GetString(const ValidChars: TSetOfChar): String;
215
function GetString(BufPos: PChar; Len: integer): String;
217
function CheckName: Boolean;
218
function GetName(out s: String): Boolean;
219
function ExpectName: String; // [5]
221
procedure ExpectAttValue(attr: TDOMAttr); // [10]
222
function ExpectPubidLiteral: String; // [12]
223
procedure SkipPubidLiteral;
224
function ParseComment(AOwner: TDOMNode): Boolean; // [15]
225
function ParsePI: Boolean; // [16]
226
procedure ExpectProlog; // [22]
227
function ParseEq: Boolean; // [25]
229
procedure ParseMisc(AOwner: TDOMNode); // [27]
230
function ParseMarkupDecl: Boolean; // [29]
231
function ParseCharData(AOwner: TDOMNode): Boolean; // [14]
232
function ParseCDSect(AOwner: TDOMNode): Boolean; // [18]
233
function ParseElement(AOwner: TDOMNode): Boolean; // [39]
234
procedure ExpectElement(AOwner: TDOMNode);
235
function ParseReference(AOwner: TDOMNode): Boolean; // [67]
236
procedure ExpectReference(AOwner: TDOMNode);
237
function ParsePEReference: Boolean; // [69]
238
function ParseExternalID: Boolean; // [75]
239
procedure ExpectExternalID;
240
function ParseEncodingDecl: String; // [80]
241
procedure SkipEncodingDecl;
243
procedure ResolveEntities(RootNode: TDOMNode);
246
procedure ProcessXML(ABuf: PChar; const AFilename: String); // [1]
247
procedure ProcessFragment(AOwner: TDOMNode; ABuf: PChar; const AFilename: String);
248
procedure ProcessDTD(ABuf: PChar; const AFilename: String); // ([29])
251
{ TXMLReaderDocument }
253
procedure TXMLReaderDocument.SetDocType(ADocType: TDOMDocumentType);
255
FDocType := ADocType;
259
constructor TXMLReaderDocumentType.Create(ADocument: TXMLReaderDocument);
261
inherited Create(ADocument);
264
function TXMLReader.BufPosToLineCol(p: PChar): TPoint;
270
// find out the line in which the error occured
274
while apos < p do begin
275
if apos^ in [#10,#13] then begin
278
if (apos[1] in [#10,#13]) and (apos[0]<>apos[1]) then
288
function TXMLReader.BufPosToStr(p: PChar): string;
294
// find out the line in which the error occured
295
LineCol:=BufPosToLineCol(p);
296
Result:=IntToStr(LineCol.y)+','+IntToStr(LineCol.x);
299
procedure TXMLReader.RaiseExc(const descr: String);
304
LineCol:=BufPosToLineCol(buf);
305
Err:=EXMLReadError.Create(
306
Filename+'('+IntToStr(LineCol.y)+','+IntToStr(LineCol.x)+') Error: ' + descr);
307
Err.Position:=buf-BufStart;
308
Err.LineCol:=LineCol;
313
procedure TXMLReader.RaiseCharNotFound(c: char);
315
RaiseExc('Expected "' + c + '", found "' + buf^ + '"');
318
function TXMLReader.SkipWhitespace: Boolean;
321
while buf[0] in WhitespaceChars do
328
procedure TXMLReader.ExpectWhitespace;
330
if not SkipWhitespace then
331
RaiseExc('Expected whitespace');
334
procedure TXMLReader.ExpectChar(c: char);
337
RaiseCharNotFound(c);
341
procedure TXMLReader.ExpectString(const s: String);
343
procedure RaiseStringNotFound;
348
GetMem(s2, Length(s) + 1);
349
StrLCopy(s2, buf, Length(s));
352
RaiseExc('Expected "' + s + '", found "' + s3 + '"');
358
for i := 1 to Length(s) do
359
if buf[i - 1] <> s[i] then begin
365
function TXMLReader.CheckFor(s: PChar): Boolean;
367
if buf[0] <> #0 then begin
368
if (buf[0]=s[0]) and (CompareLPChar(buf, s, StrLen(s))) then begin
378
function TXMLReader.CheckForChar(c: Char): Boolean;
380
if (buf[0]=c) and (c<>#0) then begin
388
procedure TXMLReader.SkipString(const ValidChars: TSetOfChar);
390
while buf[0] in ValidChars do begin
395
function TXMLReader.GetString(const ValidChars: TSetOfChar): String;
401
while buf[0] in ValidChars do begin
405
SetLength(Result, Len);
406
for i:=1 to len do begin
407
Result[i]:=OldBuf[0];
412
function TXMLReader.GetString(BufPos: PChar; Len: integer): string;
415
SetLength(Result,Len);
416
for i:=1 to Len do begin
417
Result[i]:=BufPos[0];
422
procedure TXMLReader.ProcessXML(ABuf: PChar; const AFilename: String); // [1]
426
Filename := AFilename;
428
doc := TXMLReaderDocument.Create;
430
{$IFDEF MEM_CHECK}CheckHeapWrtMemCnt('TXMLReader.ProcessXML A');{$ENDIF}
432
{$IFDEF MEM_CHECK}CheckHeapWrtMemCnt('TXMLReader.ProcessXML B');{$ENDIF}
435
// skip end of file characters
436
while buf^=#26 do inc(buf);
437
// check if whole document was read
439
RaiseExc('Text after end of document element found');
442
procedure TXMLReader.ProcessFragment(AOwner: TDOMNode; ABuf: PChar; const AFilename: String);
446
Filename := AFilename;
448
// do not call SkipWhitespace. They are needed by ParseCharData.
449
while ParseCharData(AOwner) or ParseCDSect(AOwner) or ParsePI or
450
ParseComment(AOwner) or ParseElement(AOwner) or
451
ParseReference(AOwner)
455
function TXMLReader.CheckName: Boolean;
458
if not (buf[0] in (Letter + ['_', ':'])) then begin
465
SkipString(Letter + ['0'..'9', '.', '-', '_', ':']);
470
function TXMLReader.GetName(out s: String): Boolean; // [5]
473
if not (buf[0] in (Letter + ['_', ':'])) then begin
481
SkipString(Letter + ['0'..'9', '.', '-', '_', ':']);
482
s := GetString(OldBuf,buf-OldBuf);
486
function TXMLReader.ExpectName: String; // [5]
488
procedure RaiseNameNotFound;
490
RaiseExc('Expected letter, "_" or ":" for name, found "' + buf[0] + '"');
495
if not (buf[0] in (Letter + ['_', ':'])) then
500
SkipString(Letter + ['0'..'9', '.', '-', '_', ':']);
501
Result:=GetString(OldBuf,buf-OldBuf);
504
procedure TXMLReader.SkipName;
506
procedure RaiseSkipNameNotFound;
508
RaiseExc('Expected letter, "_" or ":" for name, found "' + buf[0] + '"');
512
if not (buf[0] in (Letter + ['_', ':'])) then
513
RaiseSkipNameNotFound;
516
SkipString(Letter + ['0'..'9', '.', '-', '_', ':']);
519
procedure TXMLReader.ExpectAttValue(attr: TDOMAttr); // [10]
523
procedure FlushStringBuffer;
527
if OldBuf<>buf then begin
528
s := GetString(OldBuf,buf-OldBuf);
530
attr.AppendChild(doc.CreateTextNode(s));
538
if (buf[0] <> '''') and (buf[0] <> '"') then
539
RaiseExc('Expected quotation marks');
543
while (buf[0]<>StrDel) and (buf[0]<>#0) do begin
544
if buf[0] <> '&' then begin
548
if OldBuf<>buf then FlushStringBuffer;
549
ParseReference(attr);
553
if OldBuf<>buf then FlushStringBuffer;
555
ResolveEntities(Attr);
558
function TXMLReader.ExpectPubidLiteral: String;
560
SetLength(Result, 0);
561
if CheckForChar('''') then begin
562
SkipString(PubidChars - ['''']);
564
end else if CheckForChar('"') then begin
565
SkipString(PubidChars - ['"']);
568
RaiseExc('Expected quotation marks');
571
procedure TXMLReader.SkipPubidLiteral;
573
if CheckForChar('''') then begin
574
SkipString(PubidChars - ['''']);
576
end else if CheckForChar('"') then begin
577
SkipString(PubidChars - ['"']);
580
RaiseExc('Expected quotation marks');
583
function TXMLReader.ParseComment(AOwner: TDOMNode): Boolean; // [15]
588
if CheckFor('<!--') then begin
590
while (buf[0] <> #0) and (buf[1] <> #0) and
591
((buf[0] <> '-') or (buf[1] <> '-')) do begin
594
comment:=GetString(OldBuf,buf-OldBuf);
595
AOwner.AppendChild(doc.CreateComment(comment));
602
function TXMLReader.ParsePI: Boolean; // [16]
604
if CheckFor('<?') then begin
605
if CompareLIPChar(buf,'XML ',4) then
606
RaiseExc('"<?xml" processing instruction not allowed here');
608
if SkipWhitespace then
609
while (buf[0] <> #0) and (buf[1] <> #0) and not
610
((buf[0] = '?') and (buf[1] = '>')) do Inc(buf);
617
procedure TXMLReader.ExpectProlog; // [22]
619
procedure ParseVersionNum;
621
if doc.InheritsFrom(TXMLDocument) then
622
TXMLDocument(doc).XMLVersion :=
623
GetString(['a'..'z', 'A'..'Z', '0'..'9', '_', '.', ':', '-']);
626
procedure ParseDoctypeDecls;
630
until not (ParseMarkupDecl or ParsePEReference);
636
DocType: TXMLReaderDocumentType;
639
if CheckFor('<?xml') then
641
// '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
643
// VersionInfo: S 'version' Eq (' VersionNum ' | " VersionNum ")
645
ExpectString('version');
647
if buf[0] = '''' then
652
end else if buf[0] = '"' then
658
RaiseExc('Expected single or double quotation mark');
665
if CheckFor('standalone') then
668
if buf[0] = '''' then
671
if not (CheckFor('yes''') or CheckFor('no''')) then
672
RaiseExc('Expected ''yes'' or ''no''');
673
end else if buf[0] = '''' then
676
if not (CheckFor('yes"') or CheckFor('no"')) then
677
RaiseExc('Expected "yes" or "no"');
688
// Check for "(doctypedecl Misc*)?" [28]
689
if CheckFor('<!DOCTYPE') then
691
DocType := TXMLReaderDocumentType.Create(doc as TXMLReaderDocument);
692
if doc.InheritsFrom(TXMLReaderDocument) then
693
TXMLReaderDocument(doc).SetDocType(DocType);
695
DocType.Name := ExpectName;
697
if CheckForChar('[') then
702
end else if not CheckForChar('>') then
706
if CheckForChar('[') then
717
function TXMLReader.ParseEq: Boolean; // [25]
723
if buf[0] = '=' then begin
733
procedure TXMLReader.ExpectEq;
736
RaiseExc('Expected "="');
741
// Misc ::= Comment | PI | S
743
procedure TXMLReader.ParseMisc(AOwner: TDOMNode); // [27]
747
until not (ParseComment(AOwner) or ParsePI);
750
function TXMLReader.ParseMarkupDecl: Boolean; // [29]
752
function ParseElementDecl: Boolean; // [45]
754
procedure ExpectChoiceOrSeq; // [49], [50]
756
procedure ExpectCP; // [48]
758
if CheckForChar('(') then
762
if CheckForChar('?') then
763
else if CheckForChar('*') then
764
else if CheckForChar('+') then;
774
while not CheckForChar(')') do begin
775
if delimiter = #0 then begin
776
if (buf[0] = '|') or (buf[0] = ',') then
779
RaiseExc('Expected "|" or ","');
782
ExpectChar(delimiter);
789
if CheckFor('<!ELEMENT') then begin
794
// Get contentspec [46]
796
if CheckFor('EMPTY') then
797
else if CheckFor('ANY') then
798
else if CheckForChar('(') then begin
800
if CheckFor('#PCDATA') then begin
801
// Parse Mixed section [51]
803
if not CheckForChar(')') then
808
until CheckFor(')*');
810
// Parse Children section [47]
814
if CheckForChar('?') then
815
else if CheckForChar('*') then
816
else if CheckForChar('+') then;
819
RaiseExc('Invalid content specification');
828
function ParseAttlistDecl: Boolean; // [52]
832
if CheckFor('<!ATTLIST') then begin
836
while not CheckForChar('>') do begin
840
// Get AttType [54], [55], [56]
841
if CheckFor('CDATA') then
842
else if CheckFor('ID') then
843
else if CheckFor('IDREF') then
844
else if CheckFor('IDREFS') then
845
else if CheckFor('ENTITTY') then
846
else if CheckFor('ENTITIES') then
847
else if CheckFor('NMTOKEN') then
848
else if CheckFor('NMTOKENS') then
849
else if CheckFor('NOTATION') then begin // [57], [58]
855
while not CheckForChar(')') do begin
861
end else if CheckForChar('(') then begin // [59]
865
while not CheckForChar(')') do begin
872
RaiseExc('Invalid tokenized type');
876
// Get DefaultDecl [60]
877
if CheckFor('#REQUIRED') then
878
else if CheckFor('#IMPLIED') then
880
if CheckFor('#FIXED') then
882
attr := doc.CreateAttribute('');
883
ExpectAttValue(attr);
893
function ParseEntityDecl: Boolean; // [70]
895
NewEntity: TDOMEntity;
897
function ParseEntityValue: Boolean; // [9]
901
if (buf[0] <> '''') and (buf[0] <> '"') then begin
907
while not CheckForChar(strdel) do
908
if ParsePEReference then
909
else if ParseReference(NewEntity) then
911
Inc(buf); // Normal haracter
917
if CheckFor('<!ENTITY') then begin
919
if CheckForChar('%') then begin // [72]
921
NewEntity := doc.CreateEntity(ExpectName);
924
if ParseEntityValue then
925
else if ParseExternalID then
927
RaiseExc('Expected entity value or external ID');
928
end else begin // [71]
929
NewEntity := doc.CreateEntity(ExpectName);
931
// Get EntityDef [73]
932
if ParseEntityValue then
935
// Get NDataDecl [76]
937
ExpectString('NDATA');
949
function ParseNotationDecl: Boolean; // [82]
951
if CheckFor('<!NOTATION') then begin
955
if ParseExternalID then
956
else if CheckFor('PUBLIC') then begin // [83]
960
RaiseExc('Expected external or public ID');
970
while ParseElementDecl or ParseAttlistDecl or ParseEntityDecl or
971
ParseNotationDecl or ParsePI or ParseComment(doc) or SkipWhitespace do
975
procedure TXMLReader.ProcessDTD(ABuf: PChar; const AFilename: String);
979
Filename := AFilename;
981
doc := TXMLReaderDocument.Create;
985
if buf[0] <> #0 then begin
986
DebugLn('=== Unparsed: ===');
988
DebugLn(StrLen(buf), ' chars');
993
function TXMLReader.ParseCharData(AOwner: TDOMNode): Boolean; // [14]
1000
while not (buf[0] in [#0, '<', '&']) do
1004
DataLen:=buf-OldBuf;
1007
// Check if chardata has non-whitespace content
1009
while (p<buf) and (p[0] in WhitespaceChars) do
1012
AOwner.AppendChild(doc.CreateTextNode(GetString(OldBuf,DataLen)));
1019
function TXMLReader.ParseCDSect(AOwner: TDOMNode): Boolean; // [18]
1023
if CheckFor('<![CDATA[') then
1026
while not CheckFor(']]>') do
1030
AOwner.AppendChild(doc.CreateCDATASection(GetString(OldBuf,buf-OldBuf-3))); { Copy CDATA, discarding terminator }
1037
function TXMLReader.ParseElement(AOwner: TDOMNode): Boolean; // [39] [40] [44]
1039
NewElem: TDOMElement;
1041
procedure CreateNameElement;
1049
{$IFDEF MEM_CHECK}CheckHeapWrtMemCnt(' CreateNameElement A');{$ENDIF}
1052
NewElem := doc.CreateElement(name);
1053
AOwner.AppendChild(NewElem);
1059
{$IFDEF MEM_CHECK}CheckHeapWrtMemCnt(' CreateNameElement E');{$ENDIF}
1060
if CheckFor('/>') then
1065
if CheckForChar('>') then
1068
// Get Attribute [41]
1069
attr := doc.CreateAttribute(ExpectName);
1070
NewElem.Attributes.SetNamedItem(attr);
1072
ExpectAttValue(attr);
1081
while ParseCharData(NewElem) or ParseCDSect(NewElem) or ParsePI or
1082
ParseComment(NewElem) or ParseElement(NewElem) or
1083
ParseReference(NewElem) do;
1087
FoundName:=ExpectName;
1088
if FoundName <> name then
1089
RaiseExc('Unmatching element end tag (expected "</' + name + '>", found "</'+FoundName+'>", start tag at '+BufPosToStr(StartPos)+')');
1094
{$IFDEF MEM_CHECK}CheckHeapWrtMemCnt(' CreateNameElement END');{$ENDIF}
1095
ResolveEntities(NewElem);
1102
if CheckForChar('<') then
1104
{$IFDEF MEM_CHECK}CheckHeapWrtMemCnt('TXMLReader.ParseElement A');{$ENDIF}
1105
if not CheckName then
1115
{$IFDEF MEM_CHECK}CheckHeapWrtMemCnt('TXMLReader.ParseElement END');{$ENDIF}
1118
procedure TXMLReader.ExpectElement(AOwner: TDOMNode);
1120
if not ParseElement(AOwner) then
1121
RaiseExc('Expected element');
1124
function TXMLReader.ParsePEReference: Boolean; // [69]
1126
if CheckForChar('%') then begin
1134
function TXMLReader.ParseReference(AOwner: TDOMNode): Boolean; // [67] [68]
1136
if not CheckForChar('&') then begin
1140
if CheckForChar('#') then begin // Test for CharRef [66]
1141
if CheckForChar('x') then begin
1142
// !!!: there must be at least one digit
1143
while buf[0] in ['0'..'9', 'a'..'f', 'A'..'F'] do Inc(buf);
1145
// !!!: there must be at least one digit
1146
while buf[0] in ['0'..'9'] do Inc(buf);
1148
AOwner.AppendChild(doc.CreateEntityReference(ExpectName));
1153
procedure TXMLReader.ExpectReference(AOwner: TDOMNode);
1155
if not ParseReference(AOwner) then
1156
RaiseExc('Expected reference ("&Name;" or "%Name;")');
1160
function TXMLReader.ParseExternalID: Boolean; // [75]
1162
function GetSystemLiteral: String;
1166
if buf[0] = '''' then begin
1169
while (buf[0] <> '''') and (buf[0] <> #0) do begin
1172
Result := GetString(OldBuf,buf-OldBuf);
1174
end else if buf[0] = '"' then begin
1177
while (buf[0] <> '"') and (buf[0] <> #0) do begin
1180
Result := GetString(OldBuf,buf-OldBuf);
1186
procedure SkipSystemLiteral;
1188
if buf[0] = '''' then begin
1190
while (buf[0] <> '''') and (buf[0] <> #0) do begin
1194
end else if buf[0] = '"' then begin
1196
while (buf[0] <> '"') and (buf[0] <> #0) do begin
1204
if CheckFor('SYSTEM') then begin
1208
end else if CheckFor('PUBLIC') then begin
1218
procedure TXMLReader.ExpectExternalID;
1220
if not ParseExternalID then
1221
RaiseExc('Expected external ID');
1224
function TXMLReader.ParseEncodingDecl: String; // [80]
1226
function ParseEncName: String;
1229
if not (buf[0] in ['A'..'Z', 'a'..'z']) then
1230
RaiseExc('Expected character (A-Z, a-z)');
1233
SkipString(['A'..'Z', 'a'..'z', '0'..'9', '.', '_', '-']);
1234
Result := GetString(OldBuf,buf-OldBuf);
1238
SetLength(Result, 0);
1240
if CheckFor('encoding') then begin
1242
if buf[0] = '''' then begin
1244
Result := ParseEncName;
1246
end else if buf[0] = '"' then begin
1248
Result := ParseEncName;
1254
procedure TXMLReader.SkipEncodingDecl;
1256
procedure ParseEncName;
1258
if not (buf[0] in ['A'..'Z', 'a'..'z']) then
1259
RaiseExc('Expected character (A-Z, a-z)');
1261
SkipString(['A'..'Z', 'a'..'z', '0'..'9', '.', '_', '-']);
1266
if CheckFor('encoding') then begin
1268
if buf[0] = '''' then begin
1272
end else if buf[0] = '"' then begin
1281
{ Currently, this method will only resolve the entities which are
1282
predefined in XML: }
1284
procedure TXMLReader.ResolveEntities(RootNode: TDOMNode);
1286
Node, NextNode: TDOMNode;
1288
procedure ReplaceEntityRef(EntityNode: TDOMNode; const Replacement: String);
1290
PrevSibling, NextSibling: TDOMNode;
1292
PrevSibling := EntityNode.PreviousSibling;
1293
NextSibling := EntityNode.NextSibling;
1294
if Assigned(PrevSibling) and (PrevSibling.NodeType = TEXT_NODE) then
1296
TDOMCharacterData(PrevSibling).AppendData(Replacement);
1297
RootNode.RemoveChild(EntityNode);
1298
if Assigned(NextSibling) and (NextSibling.NodeType = TEXT_NODE) then
1300
NextNode := NextSibling.NextSibling;
1301
TDOMCharacterData(PrevSibling).AppendData(
1302
TDOMCharacterData(NextSibling).Data);
1303
RootNode.RemoveChild(NextSibling);
1306
if Assigned(NextSibling) and (NextSibling.NodeType = TEXT_NODE) then
1308
TDOMCharacterData(NextSibling).InsertData(0, Replacement);
1309
RootNode.RemoveChild(EntityNode);
1311
RootNode.ReplaceChild(Doc.CreateTextNode(Replacement), EntityNode);
1315
Node := RootNode.FirstChild;
1316
while Assigned(Node) do
1318
NextNode := Node.NextSibling;
1319
if Node.NodeType = ENTITY_REFERENCE_NODE then
1320
if Node.NodeName = 'amp' then
1321
ReplaceEntityRef(Node, '&')
1322
else if Node.NodeName = 'apos' then
1323
ReplaceEntityRef(Node, '''')
1324
else if Node.NodeName = 'gt' then
1325
ReplaceEntityRef(Node, '>')
1326
else if Node.NodeName = 'lt' then
1327
ReplaceEntityRef(Node, '<')
1328
else if Node.NodeName = 'quot' then
1329
ReplaceEntityRef(Node, '"');
1336
procedure ReadXMLFile(out ADoc: TXMLDocument; var f: File);
1343
BufSize := FileSize(f) + 1;
1344
if BufSize <= 1 then
1347
GetMem(buf, BufSize);
1349
BlockRead(f, buf^, BufSize - 1);
1350
buf[BufSize - 1] := #0;
1351
Reader := TXMLReader.Create;
1353
Reader.ProcessXML(buf, TFileRec(f).name);
1355
ADoc := TXMLDocument(Reader.doc);
1363
procedure ReadXMLFile(out ADoc: TXMLDocument; f: TStream; const AFilename: String);
1369
if f.Size = 0 then exit;
1371
GetMem(buf, f.Size + 1);
1373
f.Read(buf^, f.Size);
1375
Reader := TXMLReader.Create;
1377
Reader.ProcessXML(buf, AFilename);
1379
ADoc := TXMLDocument(Reader.doc);
1387
procedure ReadXMLFile(out ADoc: TXMLDocument; f: TStream);
1389
ReadXMLFile(ADoc, f, '<Stream>');
1392
procedure ReadXMLFile(out ADoc: TXMLDocument; const AFilename: String);
1394
FileStream: TFileStream;
1395
MemStream: TMemoryStream;
1398
FileStream := TFileStream.Create(UTF8ToSys(AFilename), fmOpenRead or fmShareDenyWrite);
1399
if FileStream = nil then exit;
1400
MemStream := TMemoryStream.Create;
1402
MemStream.LoadFromStream(FileStream);
1403
ReadXMLFile(ADoc, MemStream, AFilename);
1410
procedure ReadXMLFragment(AParentNode: TDOMNode; var f: File);
1416
BufSize := FileSize(f) + 1;
1417
if BufSize <= 1 then
1420
GetMem(buf, BufSize);
1422
BlockRead(f, buf^, BufSize - 1);
1423
buf[BufSize - 1] := #0;
1424
Reader := TXMLReader.Create;
1426
Reader.Doc := AParentNode.OwnerDocument;
1427
Reader.ProcessFragment(AParentNode, buf, TFileRec(f).name);
1436
procedure ReadXMLFragment(AParentNode: TDOMNode; var f: TStream; const AFilename: String);
1444
GetMem(buf, f.Size + 1);
1446
f.Read(buf^, f.Size);
1448
Reader := TXMLReader.Create;
1449
Reader.Doc := AParentNode.OwnerDocument;
1451
Reader.ProcessFragment(AParentNode, buf, AFilename);
1460
procedure ReadXMLFragment(AParentNode: TDOMNode; var f: TStream);
1462
ReadXMLFragment(AParentNode, f, '<Stream>');
1465
procedure ReadXMLFragment(AParentNode: TDOMNode; const AFilename: String);
1469
Stream := TFileStream.Create(UTF8ToSys(AFilename), fmOpenRead or fmShareDenyWrite);
1471
ReadXMLFragment(AParentNode, Stream, AFilename);
1478
procedure ReadDTDFile(var ADoc: TXMLDocument; var f: File);
1485
BufSize := FileSize(f) + 1;
1486
if BufSize <= 1 then
1489
GetMem(buf, BufSize);
1491
BlockRead(f, buf^, BufSize - 1);
1492
buf[BufSize - 1] := #0;
1493
Reader := TXMLReader.Create;
1495
Reader.ProcessDTD(buf, TFileRec(f).name);
1496
ADoc := TXMLDocument(Reader.doc);
1505
procedure ReadDTDFile(var ADoc: TXMLDocument; var f: TStream; const AFilename: String);
1514
GetMem(buf, f.Size + 1);
1516
f.Read(buf^, f.Size);
1518
Reader := TXMLReader.Create;
1520
Reader.ProcessDTD(buf, AFilename);
1521
ADoc := TXMLDocument(Reader.doc);
1530
procedure ReadDTDFile(var ADoc: TXMLDocument; var f: TStream);
1532
ReadDTDFile(ADoc, f, '<Stream>');
1535
procedure ReadDTDFile(var ADoc: TXMLDocument; const AFilename: String);
1540
Stream := TFileStream.Create(UTF8ToSys(AFilename), fmOpenRead or fmShareDenyWrite);
1542
ReadDTDFile(ADoc, Stream, AFilename);