xmlread.pp 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562
  1. {
  2. This file is part of the Free Component Library
  3. XML reading routines.
  4. Copyright (c) 1999-2000 by Sebastian Guenther, [email protected]
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit XMLRead;
  12. {$MODE objfpc}
  13. {$H+}
  14. interface
  15. {off $DEFINE MEM_CHECK}
  16. uses
  17. {$IFDEF MEM_CHECK}MemCheck,{$ENDIF}
  18. SysUtils, Classes, DOM;
  19. type
  20. EXMLReadError = class(Exception);
  21. procedure ReadXMLFile(var ADoc: TXMLDocument; const AFilename: String); overload;
  22. procedure ReadXMLFile(var ADoc: TXMLDocument; var f: File); overload;
  23. procedure ReadXMLFile(var ADoc: TXMLDocument; var f: TStream); overload;
  24. procedure ReadXMLFile(var ADoc: TXMLDocument; var f: TStream; const AFilename: String); overload;
  25. procedure ReadXMLFragment(AParentNode: TDOMNode; const AFilename: String); overload;
  26. procedure ReadXMLFragment(AParentNode: TDOMNode; var f: File); overload;
  27. procedure ReadXMLFragment(AParentNode: TDOMNode; var f: TStream); overload;
  28. procedure ReadXMLFragment(AParentNode: TDOMNode; var f: TStream; const AFilename: String); overload;
  29. procedure ReadDTDFile(var ADoc: TXMLDocument; const AFilename: String); overload;
  30. procedure ReadDTDFile(var ADoc: TXMLDocument; var f: File); overload;
  31. procedure ReadDTDFile(var ADoc: TXMLDocument; var f: TStream); overload;
  32. procedure ReadDTDFile(var ADoc: TXMLDocument; var f: TStream; const AFilename: String); overload;
  33. // =======================================================
  34. implementation
  35. const
  36. Letter = ['A'..'Z', 'a'..'z'];
  37. Digit = ['0'..'9'];
  38. PubidChars: set of Char = [' ', #13, #10, 'a'..'z', 'A'..'Z', '0'..'9',
  39. '-', '''', '(', ')', '+', ',', '.', '/', ':', '=', '?', ';', '!', '*',
  40. '#', '@', '$', '_', '%'];
  41. WhitespaceChars: set of Char = [#9, #10, #13, ' '];
  42. NmToken: set of Char = Letter + Digit + ['.', '-', '_', ':'];
  43. function ComparePChar(p1, p2: PChar): boolean;
  44. begin
  45. if p1<>p2 then begin
  46. if (p1<>nil) and (p2<>nil) then begin
  47. while true do begin
  48. if (p1^=p2^) then begin
  49. if p1^<>#0 then begin
  50. inc(p1);
  51. inc(p2);
  52. end else begin
  53. Result:=true;
  54. exit;
  55. end;
  56. end else begin
  57. Result:=false;
  58. exit;
  59. end;
  60. end;
  61. Result:=true;
  62. end else begin
  63. Result:=false;
  64. end;
  65. end else begin
  66. Result:=true;
  67. end;
  68. end;
  69. function CompareLPChar(p1, p2: PChar; Max: integer): boolean;
  70. begin
  71. if p1<>p2 then begin
  72. if (p1<>nil) and (p2<>nil) then begin
  73. while Max>0 do begin
  74. if (p1^=p2^) then begin
  75. if (p1^<>#0) then begin
  76. inc(p1);
  77. inc(p2);
  78. dec(Max);
  79. end else begin
  80. Result:=true;
  81. exit;
  82. end;
  83. end else begin
  84. Result:=false;
  85. exit;
  86. end;
  87. end;
  88. Result:=true;
  89. end else begin
  90. Result:=false;
  91. end;
  92. end else begin
  93. Result:=true;
  94. end;
  95. end;
  96. function CompareIPChar(p1, p2: PChar): boolean;
  97. begin
  98. if p1<>p2 then begin
  99. if (p1<>nil) and (p2<>nil) then begin
  100. while true do begin
  101. if (p1^=p2^) or (upcase(p1^)=upcase(p2^)) then begin
  102. if p1^<>#0 then begin
  103. inc(p1);
  104. inc(p2);
  105. end else begin
  106. Result:=true;
  107. exit;
  108. end;
  109. end else begin
  110. Result:=false;
  111. exit;
  112. end;
  113. end;
  114. Result:=true;
  115. end else begin
  116. Result:=false;
  117. end;
  118. end else begin
  119. Result:=true;
  120. end;
  121. end;
  122. function CompareLIPChar(p1, p2: PChar; Max: integer): boolean;
  123. begin
  124. if p1<>p2 then begin
  125. if (p1<>nil) and (p2<>nil) then begin
  126. while Max>0 do begin
  127. if (p1^=p2^) or (upcase(p1^)=upcase(p2^)) then begin
  128. if (p1^<>#0) then begin
  129. inc(p1);
  130. inc(p2);
  131. dec(Max);
  132. end else begin
  133. Result:=true;
  134. exit;
  135. end;
  136. end else begin
  137. Result:=false;
  138. exit;
  139. end;
  140. end;
  141. Result:=true;
  142. end else begin
  143. Result:=false;
  144. end;
  145. end else begin
  146. Result:=true;
  147. end;
  148. end;
  149. type
  150. TXMLReaderDocument = class(TXMLDocument)
  151. public
  152. procedure SetDocType(ADocType: TDOMDocumentType);
  153. end;
  154. TXMLReaderDocumentType = class(TDOMDocumentType)
  155. public
  156. constructor Create(ADocument: TXMLReaderDocument);
  157. property Name: DOMString read FNodeName write FNodeName;
  158. end;
  159. TSetOfChar = set of Char;
  160. TXMLReader = class
  161. protected
  162. buf, BufStart: PChar;
  163. Filename: String;
  164. procedure RaiseExc(const descr: String);
  165. function SkipWhitespace: Boolean;
  166. procedure ExpectWhitespace;
  167. procedure ExpectString(const s: String);
  168. function CheckFor(s: PChar): Boolean;
  169. function CheckForChar(c: Char): Boolean;
  170. procedure SkipString(const ValidChars: TSetOfChar);
  171. function GetString(const ValidChars: TSetOfChar): String;
  172. function GetString(BufPos: PChar; Len: integer): String;
  173. function CheckName: Boolean;
  174. function GetName(var s: String): Boolean;
  175. function ExpectName: String; // [5]
  176. procedure SkipName;
  177. procedure ExpectAttValue(attr: TDOMAttr); // [10]
  178. function ExpectPubidLiteral: String; // [12]
  179. procedure SkipPubidLiteral;
  180. function ParseComment(AOwner: TDOMNode): Boolean; // [15]
  181. function ParsePI: Boolean; // [16]
  182. procedure ExpectProlog; // [22]
  183. function ParseEq: Boolean; // [25]
  184. procedure ExpectEq;
  185. procedure ParseMisc(AOwner: TDOMNode); // [27]
  186. function ParseMarkupDecl: Boolean; // [29]
  187. function ParseCharData(AOwner: TDOMNode): Boolean; // [14]
  188. function ParseCDSect(AOwner: TDOMNode): Boolean; // [18]
  189. function ParseElement(AOwner: TDOMNode): Boolean; // [39]
  190. procedure ExpectElement(AOwner: TDOMNode);
  191. function ParseReference(AOwner: TDOMNode): Boolean; // [67]
  192. procedure ExpectReference(AOwner: TDOMNode);
  193. function ParsePEReference: Boolean; // [69]
  194. function ParseExternalID: Boolean; // [75]
  195. procedure ExpectExternalID;
  196. function ParseEncodingDecl: String; // [80]
  197. procedure SkipEncodingDecl;
  198. procedure ResolveEntities(RootNode: TDOMNode);
  199. public
  200. doc: TDOMDocument;
  201. procedure ProcessXML(ABuf: PChar; const AFilename: String); // [1]
  202. procedure ProcessFragment(AOwner: TDOMNode; ABuf: PChar; const AFilename: String);
  203. procedure ProcessDTD(ABuf: PChar; const AFilename: String); // ([29])
  204. end;
  205. { TXMLReaderDocument }
  206. procedure TXMLReaderDocument.SetDocType(ADocType: TDOMDocumentType);
  207. begin
  208. FDocType := ADocType;
  209. end;
  210. constructor TXMLReaderDocumentType.Create(ADocument: TXMLReaderDocument);
  211. begin
  212. inherited Create(ADocument);
  213. end;
  214. procedure TXMLReader.RaiseExc(const descr: String);
  215. var
  216. apos: PChar;
  217. x, y: Integer;
  218. begin
  219. // find out the line in which the error occured
  220. apos := BufStart;
  221. x := 1;
  222. y := 1;
  223. while apos < buf do begin
  224. if apos[0] = #10 then begin
  225. Inc(y);
  226. x := 1;
  227. end else
  228. Inc(x);
  229. Inc(apos);
  230. end;
  231. raise EXMLReadError.Create('In ' + Filename + ' (line ' + IntToStr(y) + ' pos ' +
  232. IntToStr(x) + '): ' + descr);
  233. end;
  234. function TXMLReader.SkipWhitespace: Boolean;
  235. begin
  236. Result := False;
  237. while buf[0] in WhitespaceChars do
  238. begin
  239. Inc(buf);
  240. Result := True;
  241. end;
  242. end;
  243. procedure TXMLReader.ExpectWhitespace;
  244. begin
  245. if not SkipWhitespace then
  246. RaiseExc('Expected whitespace');
  247. end;
  248. procedure TXMLReader.ExpectString(const s: String);
  249. procedure RaiseStringNotFound;
  250. var
  251. s2: PChar;
  252. s3: String;
  253. begin
  254. GetMem(s2, Length(s) + 1);
  255. StrLCopy(s2, buf, Length(s));
  256. s3 := StrPas(s2);
  257. FreeMem(s2);
  258. RaiseExc('Expected "' + s + '", found "' + s3 + '"');
  259. end;
  260. var
  261. i: Integer;
  262. begin
  263. for i := 1 to Length(s) do
  264. if buf[i - 1] <> s[i] then begin
  265. RaiseStringNotFound;
  266. end;
  267. Inc(buf, Length(s));
  268. end;
  269. function TXMLReader.CheckFor(s: PChar): Boolean;
  270. begin
  271. if buf[0] <> #0 then begin
  272. if (buf[0]=s[0]) and (CompareLPChar(buf, s, StrLen(s))) then begin
  273. Inc(buf, StrLen(s));
  274. Result := True;
  275. end else
  276. Result := False;
  277. end else begin
  278. Result := False;
  279. end;
  280. end;
  281. function TXMLReader.CheckForChar(c: Char): Boolean;
  282. begin
  283. if (buf[0]=c) and (c<>#0) then begin
  284. inc(buf);
  285. Result:=true;
  286. end else begin
  287. Result:=false;
  288. end;
  289. end;
  290. procedure TXMLReader.SkipString(const ValidChars: TSetOfChar);
  291. begin
  292. while buf[0] in ValidChars do begin
  293. Inc(buf);
  294. end;
  295. end;
  296. function TXMLReader.GetString(const ValidChars: TSetOfChar): String;
  297. var
  298. OldBuf: PChar;
  299. i, len: integer;
  300. begin
  301. OldBuf:=Buf;
  302. while buf[0] in ValidChars do begin
  303. Inc(buf);
  304. end;
  305. len:=buf-OldBuf;
  306. SetLength(Result, Len);
  307. for i:=1 to len do begin
  308. Result[i]:=OldBuf[0];
  309. inc(OldBuf);
  310. end;
  311. end;
  312. function TXMLReader.GetString(BufPos: PChar; Len: integer): string;
  313. var i: integer;
  314. begin
  315. SetLength(Result,Len);
  316. for i:=1 to Len do begin
  317. Result[i]:=BufPos[0];
  318. inc(BufPos);
  319. end;
  320. end;
  321. {$IFDEF FPC}
  322. {$DEFINE UsesFPCWidestrings}
  323. {$ENDIF}
  324. {$IFDEF UsesFPCWidestrings}
  325. {procedure SimpleWide2AnsiMove(source:pwidechar;dest:pchar;len:sizeint);
  326. var
  327. i : sizeint;
  328. begin
  329. for i:=1 to len do
  330. begin
  331. if word(source^)<256 then
  332. dest^:=char(word(source^))
  333. else
  334. dest^:='?';
  335. inc(dest);
  336. inc(source);
  337. end;
  338. end;
  339. procedure SimpleAnsi2WideMove(source:pchar;dest:pwidechar;len:sizeint);
  340. var
  341. i : sizeint;
  342. begin
  343. for i:=1 to len do
  344. begin
  345. dest^:=widechar(byte(source^));
  346. inc(dest);
  347. inc(source);
  348. end;
  349. end;
  350. }
  351. {$ENDIF}
  352. procedure TXMLReader.ProcessXML(ABuf: PChar; const AFilename: String); // [1]
  353. {$IFDEF UsesFPCWidestrings}
  354. var
  355. OldWideStringManager,MyWideStringManager : TWideStringManager;
  356. {$ENDIF}
  357. begin
  358. buf := ABuf;
  359. BufStart := ABuf;
  360. Filename := AFilename;
  361. {$IFDEF UsesFPCWidestrings}
  362. GetWideStringManager(MyWideStringManager);
  363. MyWideStringManager.Wide2AnsiMoveProc:=@defaultWide2AnsiMove;
  364. MyWideStringManager.Ansi2WideMoveProc:=@defaultAnsi2WideMove;
  365. SetWideStringManager(MyWideStringManager, OldWideStringManager);
  366. try
  367. {$ENDIF}
  368. doc := TXMLReaderDocument.Create;
  369. ExpectProlog;
  370. {$IFDEF MEM_CHECK}CheckHeapWrtMemCnt('TXMLReader.ProcessXML A');{$ENDIF}
  371. ExpectElement(doc);
  372. {$IFDEF MEM_CHECK}CheckHeapWrtMemCnt('TXMLReader.ProcessXML B');{$ENDIF}
  373. ParseMisc(doc);
  374. {$IFDEF UsesFPCWidestrings}
  375. finally
  376. SetWideStringManager(OldWideStringManager);
  377. end;
  378. {$ENDIF}
  379. if buf[0] <> #0 then
  380. RaiseExc('Text after end of document element found');
  381. end;
  382. procedure TXMLReader.ProcessFragment(AOwner: TDOMNode; ABuf: PChar; const AFilename: String);
  383. {$IFDEF UsesFPCWidestrings}
  384. var
  385. OldWideStringManager: TWideStringManager;
  386. {$ENDIF}
  387. begin
  388. buf := ABuf;
  389. BufStart := ABuf;
  390. Filename := AFilename;
  391. {$IFDEF UsesFPCWidestrings}
  392. SetWideStringManager(WideStringManager, OldWideStringManager);
  393. try
  394. {$ENDIF}
  395. SkipWhitespace;
  396. while ParseCharData(AOwner) or ParseCDSect(AOwner) or ParsePI or
  397. ParseComment(AOwner) or ParseElement(AOwner) or
  398. ParseReference(AOwner) do
  399. SkipWhitespace;
  400. {$IFDEF UsesFPCWidestrings}
  401. finally
  402. SetWideStringManager(OldWideStringManager);
  403. end;
  404. {$ENDIF}
  405. end;
  406. function TXMLReader.CheckName: Boolean;
  407. var OldBuf: PChar;
  408. begin
  409. if not (buf[0] in (Letter + ['_', ':'])) then begin
  410. Result := False;
  411. exit;
  412. end;
  413. OldBuf := buf;
  414. Inc(buf);
  415. SkipString(Letter + ['0'..'9', '.', '-', '_', ':']);
  416. buf := OldBuf;
  417. Result := True;
  418. end;
  419. function TXMLReader.GetName(var s: String): Boolean; // [5]
  420. var OldBuf: PChar;
  421. begin
  422. if not (buf[0] in (Letter + ['_', ':'])) then begin
  423. SetLength(s, 0);
  424. Result := False;
  425. exit;
  426. end;
  427. OldBuf := buf;
  428. Inc(buf);
  429. SkipString(Letter + ['0'..'9', '.', '-', '_', ':']);
  430. s := GetString(OldBuf,buf-OldBuf);
  431. Result := True;
  432. end;
  433. function TXMLReader.ExpectName: String; // [5]
  434. procedure RaiseNameNotFound;
  435. begin
  436. RaiseExc('Expected letter, "_" or ":" for name, found "' + buf[0] + '"');
  437. end;
  438. var OldBuf: PChar;
  439. begin
  440. if not (buf[0] in (Letter + ['_', ':'])) then
  441. RaiseNameNotFound;
  442. OldBuf := buf;
  443. Inc(buf);
  444. SkipString(Letter + ['0'..'9', '.', '-', '_', ':']);
  445. Result:=GetString(OldBuf,buf-OldBuf);
  446. end;
  447. procedure TXMLReader.SkipName;
  448. procedure RaiseSkipNameNotFound;
  449. begin
  450. RaiseExc('Expected letter, "_" or ":" for name, found "' + buf[0] + '"');
  451. end;
  452. begin
  453. if not (buf[0] in (Letter + ['_', ':'])) then
  454. RaiseSkipNameNotFound;
  455. Inc(buf);
  456. SkipString(Letter + ['0'..'9', '.', '-', '_', ':']);
  457. end;
  458. procedure TXMLReader.ExpectAttValue(attr: TDOMAttr); // [10]
  459. var
  460. OldBuf: PChar;
  461. procedure FlushStringBuffer;
  462. var
  463. s: String;
  464. begin
  465. if OldBuf<>buf then begin
  466. s := GetString(OldBuf,buf-OldBuf);
  467. OldBuf := buf;
  468. attr.AppendChild(doc.CreateTextNode(s));
  469. SetLength(s, 0);
  470. end;
  471. end;
  472. var
  473. StrDel: char;
  474. begin
  475. if (buf[0] <> '''') and (buf[0] <> '"') then
  476. RaiseExc('Expected quotation marks');
  477. StrDel:=buf[0];
  478. Inc(buf);
  479. OldBuf := buf;
  480. while (buf[0]<>StrDel) and (buf[0]<>#0) do begin
  481. if buf[0] <> '&' then begin
  482. Inc(buf);
  483. end else
  484. begin
  485. if OldBuf<>buf then FlushStringBuffer;
  486. ParseReference(attr);
  487. OldBuf := buf;
  488. end;
  489. end;
  490. if OldBuf<>buf then FlushStringBuffer;
  491. inc(buf);
  492. ResolveEntities(Attr);
  493. end;
  494. function TXMLReader.ExpectPubidLiteral: String;
  495. begin
  496. SetLength(Result, 0);
  497. if CheckForChar('''') then begin
  498. SkipString(PubidChars - ['''']);
  499. ExpectString('''');
  500. end else if CheckForChar('"') then begin
  501. SkipString(PubidChars - ['"']);
  502. ExpectString('"');
  503. end else
  504. RaiseExc('Expected quotation marks');
  505. end;
  506. procedure TXMLReader.SkipPubidLiteral;
  507. begin
  508. if CheckForChar('''') then begin
  509. SkipString(PubidChars - ['''']);
  510. ExpectString('''');
  511. end else if CheckForChar('"') then begin
  512. SkipString(PubidChars - ['"']);
  513. ExpectString('"');
  514. end else
  515. RaiseExc('Expected quotation marks');
  516. end;
  517. function TXMLReader.ParseComment(AOwner: TDOMNode): Boolean; // [15]
  518. var
  519. comment: String;
  520. OldBuf: PChar;
  521. begin
  522. if CheckFor('<!--') then begin
  523. OldBuf := buf;
  524. while (buf[0] <> #0) and (buf[1] <> #0) and
  525. ((buf[0] <> '-') or (buf[1] <> '-')) do begin
  526. Inc(buf);
  527. end;
  528. comment:=GetString(OldBuf,buf-OldBuf);
  529. AOwner.AppendChild(doc.CreateComment(comment));
  530. ExpectString('-->');
  531. Result := True;
  532. end else
  533. Result := False;
  534. end;
  535. function TXMLReader.ParsePI: Boolean; // [16]
  536. begin
  537. if CheckFor('<?') then begin
  538. if CompareLIPChar(buf,'XML ',4) then
  539. RaiseExc('"<?xml" processing instruction not allowed here');
  540. SkipName;
  541. if SkipWhitespace then
  542. while (buf[0] <> #0) and (buf[1] <> #0) and not
  543. ((buf[0] = '?') and (buf[1] = '>')) do Inc(buf);
  544. ExpectString('?>');
  545. Result := True;
  546. end else
  547. Result := False;
  548. end;
  549. procedure TXMLReader.ExpectProlog; // [22]
  550. procedure ParseVersionNum;
  551. begin
  552. if doc.InheritsFrom(TXMLDocument) then
  553. TXMLDocument(doc).XMLVersion :=
  554. GetString(['a'..'z', 'A'..'Z', '0'..'9', '_', '.', ':', '-']);
  555. end;
  556. procedure ParseDoctypeDecls;
  557. begin
  558. repeat
  559. SkipWhitespace;
  560. until not (ParseMarkupDecl or ParsePEReference);
  561. ExpectString(']');
  562. end;
  563. var
  564. DocType: TXMLReaderDocumentType;
  565. begin
  566. if CheckFor('<?xml') then
  567. begin
  568. // '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
  569. // VersionInfo: S 'version' Eq (' VersionNum ' | " VersionNum ")
  570. SkipWhitespace;
  571. ExpectString('version');
  572. ParseEq;
  573. if buf[0] = '''' then
  574. begin
  575. Inc(buf);
  576. ParseVersionNum;
  577. ExpectString('''');
  578. end else if buf[0] = '"' then
  579. begin
  580. Inc(buf);
  581. ParseVersionNum;
  582. ExpectString('"');
  583. end else
  584. RaiseExc('Expected single or double quotation mark');
  585. // EncodingDecl?
  586. SkipEncodingDecl;
  587. // SDDecl?
  588. SkipWhitespace;
  589. if CheckFor('standalone') then
  590. begin
  591. ExpectEq;
  592. if buf[0] = '''' then
  593. begin
  594. Inc(buf);
  595. if not (CheckFor('yes''') or CheckFor('no''')) then
  596. RaiseExc('Expected ''yes'' or ''no''');
  597. end else if buf[0] = '"' then
  598. begin
  599. Inc(buf);
  600. if not (CheckFor('yes"') or CheckFor('no"')) then
  601. RaiseExc('Expected "yes" or "no"');
  602. end;
  603. SkipWhitespace;
  604. end;
  605. ExpectString('?>');
  606. end;
  607. // Check for "Misc*"
  608. ParseMisc(doc);
  609. // Check for "(doctypedecl Misc*)?" [28]
  610. if CheckFor('<!DOCTYPE') then
  611. begin
  612. DocType := TXMLReaderDocumentType.Create(doc as TXMLReaderDocument);
  613. if doc.InheritsFrom(TXMLReaderDocument) then
  614. TXMLReaderDocument(doc).SetDocType(DocType);
  615. SkipWhitespace;
  616. DocType.Name := ExpectName;
  617. SkipWhitespace;
  618. if CheckForChar('[') then
  619. begin
  620. ParseDoctypeDecls;
  621. SkipWhitespace;
  622. ExpectString('>');
  623. end else if not CheckForChar('>') then
  624. begin
  625. ParseExternalID;
  626. SkipWhitespace;
  627. if CheckForChar('[') then
  628. begin
  629. ParseDoctypeDecls;
  630. SkipWhitespace;
  631. end;
  632. ExpectString('>');
  633. end;
  634. ParseMisc(doc);
  635. end;
  636. end;
  637. function TXMLReader.ParseEq: Boolean; // [25]
  638. var
  639. savedbuf: PChar;
  640. begin
  641. savedbuf := buf;
  642. SkipWhitespace;
  643. if buf[0] = '=' then begin
  644. Inc(buf);
  645. SkipWhitespace;
  646. Result := True;
  647. end else begin
  648. buf := savedbuf;
  649. Result := False;
  650. end;
  651. end;
  652. procedure TXMLReader.ExpectEq;
  653. begin
  654. if not ParseEq then
  655. RaiseExc('Expected "="');
  656. end;
  657. // Parse "Misc*":
  658. // Misc ::= Comment | PI | S
  659. procedure TXMLReader.ParseMisc(AOwner: TDOMNode); // [27]
  660. begin
  661. repeat
  662. SkipWhitespace;
  663. until not (ParseComment(AOwner) or ParsePI);
  664. end;
  665. function TXMLReader.ParseMarkupDecl: Boolean; // [29]
  666. function ParseElementDecl: Boolean; // [45]
  667. procedure ExpectChoiceOrSeq; // [49], [50]
  668. procedure ExpectCP; // [48]
  669. begin
  670. if CheckForChar('(') then
  671. ExpectChoiceOrSeq
  672. else
  673. SkipName;
  674. if CheckForChar('?') then
  675. else if CheckForChar('*') then
  676. else if CheckForChar('+') then;
  677. end;
  678. var
  679. delimiter: Char;
  680. begin
  681. SkipWhitespace;
  682. ExpectCP;
  683. SkipWhitespace;
  684. delimiter := #0;
  685. while not CheckForChar(')') do begin
  686. if delimiter = #0 then begin
  687. if (buf[0] = '|') or (buf[0] = ',') then
  688. delimiter := buf[0]
  689. else
  690. RaiseExc('Expected "|" or ","');
  691. Inc(buf);
  692. end else
  693. ExpectString(delimiter);
  694. SkipWhitespace;
  695. ExpectCP;
  696. end;
  697. end;
  698. begin
  699. if CheckFor('<!ELEMENT') then begin
  700. ExpectWhitespace;
  701. SkipName;
  702. ExpectWhitespace;
  703. // Get contentspec [46]
  704. if CheckFor('EMPTY') then
  705. else if CheckFor('ANY') then
  706. else if CheckForChar('(') then begin
  707. SkipWhitespace;
  708. if CheckFor('#PCDATA') then begin
  709. // Parse Mixed section [51]
  710. SkipWhitespace;
  711. if not CheckForChar(')') then
  712. repeat
  713. ExpectString('|');
  714. SkipWhitespace;
  715. SkipName;
  716. until CheckFor(')*');
  717. end else begin
  718. // Parse Children section [47]
  719. ExpectChoiceOrSeq;
  720. if CheckForChar('?') then
  721. else if CheckForChar('*') then
  722. else if CheckForChar('+') then;
  723. end;
  724. end else
  725. RaiseExc('Invalid content specification');
  726. SkipWhitespace;
  727. ExpectString('>');
  728. Result := True;
  729. end else
  730. Result := False;
  731. end;
  732. function ParseAttlistDecl: Boolean; // [52]
  733. var
  734. attr: TDOMAttr;
  735. begin
  736. if CheckFor('<!ATTLIST') then begin
  737. ExpectWhitespace;
  738. SkipName;
  739. SkipWhitespace;
  740. while not CheckForChar('>') do begin
  741. SkipName;
  742. ExpectWhitespace;
  743. // Get AttType [54], [55], [56]
  744. if CheckFor('CDATA') then
  745. else if CheckFor('ID') then
  746. else if CheckFor('IDREF') then
  747. else if CheckFor('IDREFS') then
  748. else if CheckFor('ENTITTY') then
  749. else if CheckFor('ENTITIES') then
  750. else if CheckFor('NMTOKEN') then
  751. else if CheckFor('NMTOKENS') then
  752. else if CheckFor('NOTATION') then begin // [57], [58]
  753. ExpectWhitespace;
  754. ExpectString('(');
  755. SkipWhitespace;
  756. SkipName;
  757. SkipWhitespace;
  758. while not CheckForChar(')') do begin
  759. ExpectString('|');
  760. SkipWhitespace;
  761. SkipName;
  762. SkipWhitespace;
  763. end;
  764. end else if CheckForChar('(') then begin // [59]
  765. SkipWhitespace;
  766. SkipString(Nmtoken);
  767. SkipWhitespace;
  768. while not CheckForChar(')') do begin
  769. ExpectString('|');
  770. SkipWhitespace;
  771. SkipString(Nmtoken);
  772. SkipWhitespace;
  773. end;
  774. end else
  775. RaiseExc('Invalid tokenized type');
  776. ExpectWhitespace;
  777. // Get DefaultDecl [60]
  778. if CheckFor('#REQUIRED') then
  779. else if CheckFor('#IMPLIED') then
  780. else begin
  781. if CheckFor('#FIXED') then
  782. SkipWhitespace;
  783. attr := doc.CreateAttribute('');
  784. ExpectAttValue(attr);
  785. end;
  786. SkipWhitespace;
  787. end;
  788. Result := True;
  789. end else
  790. Result := False;
  791. end;
  792. function ParseEntityDecl: Boolean; // [70]
  793. var
  794. NewEntity: TDOMEntity;
  795. function ParseEntityValue: Boolean; // [9]
  796. var
  797. strdel: Char;
  798. begin
  799. if (buf[0] <> '''') and (buf[0] <> '"') then begin
  800. Result := False;
  801. exit;
  802. end;
  803. strdel := buf[0];
  804. Inc(buf);
  805. while not CheckForChar(strdel) do
  806. if ParsePEReference then
  807. else if ParseReference(NewEntity) then
  808. else begin
  809. Inc(buf); // Normal haracter
  810. end;
  811. Result := True;
  812. end;
  813. begin
  814. if CheckFor('<!ENTITY') then begin
  815. ExpectWhitespace;
  816. if CheckForChar('%') then begin // [72]
  817. ExpectWhitespace;
  818. NewEntity := doc.CreateEntity(ExpectName);
  819. ExpectWhitespace;
  820. // Get PEDef [74]
  821. if ParseEntityValue then
  822. else if ParseExternalID then
  823. else
  824. RaiseExc('Expected entity value or external ID');
  825. end else begin // [71]
  826. NewEntity := doc.CreateEntity(ExpectName);
  827. ExpectWhitespace;
  828. // Get EntityDef [73]
  829. if ParseEntityValue then
  830. else begin
  831. ExpectExternalID;
  832. // Get NDataDecl [76]
  833. ExpectWhitespace;
  834. ExpectString('NDATA');
  835. ExpectWhitespace;
  836. SkipName;
  837. end;
  838. end;
  839. SkipWhitespace;
  840. ExpectString('>');
  841. Result := True;
  842. end else
  843. Result := False;
  844. end;
  845. function ParseNotationDecl: Boolean; // [82]
  846. begin
  847. if CheckFor('<!NOTATION') then begin
  848. ExpectWhitespace;
  849. SkipName;
  850. ExpectWhitespace;
  851. if ParseExternalID then
  852. else if CheckFor('PUBLIC') then begin // [83]
  853. ExpectWhitespace;
  854. SkipPubidLiteral;
  855. end else
  856. RaiseExc('Expected external or public ID');
  857. SkipWhitespace;
  858. ExpectString('>');
  859. Result := True;
  860. end else
  861. Result := False;
  862. end;
  863. begin
  864. Result := False;
  865. while ParseElementDecl or ParseAttlistDecl or ParseEntityDecl or
  866. ParseNotationDecl or ParsePI or ParseComment(doc) or SkipWhitespace do
  867. Result := True;
  868. end;
  869. procedure TXMLReader.ProcessDTD(ABuf: PChar; const AFilename: String);
  870. begin
  871. buf := ABuf;
  872. BufStart := ABuf;
  873. Filename := AFilename;
  874. doc := TXMLReaderDocument.Create;
  875. ParseMarkupDecl;
  876. {
  877. if buf[0] <> #0 then begin
  878. DebugLn('=== Unparsed: ===');
  879. //DebugLn(buf);
  880. DebugLn(StrLen(buf), ' chars');
  881. end;
  882. }
  883. end;
  884. function TXMLReader.ParseCharData(AOwner: TDOMNode): Boolean; // [14]
  885. var
  886. p: PChar;
  887. DataLen: integer;
  888. OldBuf: PChar;
  889. begin
  890. OldBuf := buf;
  891. while not (buf[0] in [#0, '<', '&']) do
  892. begin
  893. Inc(buf);
  894. end;
  895. DataLen:=buf-OldBuf;
  896. if DataLen > 0 then
  897. begin
  898. // Check if chardata has non-whitespace content
  899. p:=OldBuf;
  900. while (p<buf) and (p[0] in WhitespaceChars) do
  901. inc(p);
  902. if p<buf then
  903. AOwner.AppendChild(doc.CreateTextNode(GetString(OldBuf,DataLen)));
  904. Result := True;
  905. end
  906. else
  907. Result := False;
  908. end;
  909. function TXMLReader.ParseCDSect(AOwner: TDOMNode): Boolean; // [18]
  910. var
  911. OldBuf: PChar;
  912. begin
  913. if CheckFor('<![CDATA[') then
  914. begin
  915. OldBuf := buf;
  916. while not CheckFor(']]>') do
  917. begin
  918. Inc(buf);
  919. end;
  920. AOwner.AppendChild(doc.CreateCDATASection(GetString(OldBuf,buf-OldBuf-3))); { Copy CDATA, discarding terminator }
  921. Result := True;
  922. end
  923. else
  924. Result := False;
  925. end;
  926. function TXMLReader.ParseElement(AOwner: TDOMNode): Boolean; // [39] [40] [44]
  927. var
  928. NewElem: TDOMElement;
  929. procedure CreateNameElement;
  930. var
  931. IsEmpty: Boolean;
  932. attr: TDOMAttr;
  933. name: string;
  934. begin
  935. {$IFDEF MEM_CHECK}CheckHeapWrtMemCnt(' CreateNameElement A');{$ENDIF}
  936. GetName(name);
  937. NewElem := doc.CreateElement(name);
  938. AOwner.AppendChild(NewElem);
  939. SkipWhitespace;
  940. IsEmpty := False;
  941. while True do
  942. begin
  943. {$IFDEF MEM_CHECK}CheckHeapWrtMemCnt(' CreateNameElement E');{$ENDIF}
  944. if CheckFor('/>') then
  945. begin
  946. IsEmpty := True;
  947. break;
  948. end;
  949. if CheckForChar('>') then
  950. break;
  951. // Get Attribute [41]
  952. attr := doc.CreateAttribute(ExpectName);
  953. NewElem.Attributes.SetNamedItem(attr);
  954. ExpectEq;
  955. ExpectAttValue(attr);
  956. SkipWhitespace;
  957. end;
  958. if not IsEmpty then
  959. begin
  960. // Get content
  961. SkipWhitespace;
  962. while ParseCharData(NewElem) or ParseCDSect(NewElem) or ParsePI or
  963. ParseComment(NewElem) or ParseElement(NewElem) or
  964. ParseReference(NewElem) do;
  965. // Get ETag [42]
  966. ExpectString('</');
  967. if ExpectName <> name then
  968. RaiseExc('Unmatching element end tag (expected "</' + name + '>")');
  969. SkipWhitespace;
  970. ExpectString('>');
  971. end;
  972. {$IFDEF MEM_CHECK}CheckHeapWrtMemCnt(' CreateNameElement END');{$ENDIF}
  973. ResolveEntities(NewElem);
  974. end;
  975. var
  976. OldBuf: PChar;
  977. begin
  978. OldBuf := Buf;
  979. if CheckForChar('<') then
  980. begin
  981. {$IFDEF MEM_CHECK}CheckHeapWrtMemCnt('TXMLReader.ParseElement A');{$ENDIF}
  982. if not CheckName then
  983. begin
  984. Buf := OldBuf;
  985. Result := False;
  986. end else begin
  987. CreateNameElement;
  988. Result := True;
  989. end;
  990. end else
  991. Result := False;
  992. {$IFDEF MEM_CHECK}CheckHeapWrtMemCnt('TXMLReader.ParseElement END');{$ENDIF}
  993. end;
  994. procedure TXMLReader.ExpectElement(AOwner: TDOMNode);
  995. begin
  996. if not ParseElement(AOwner) then
  997. RaiseExc('Expected element');
  998. end;
  999. function TXMLReader.ParsePEReference: Boolean; // [69]
  1000. begin
  1001. if CheckForChar('%') then begin
  1002. SkipName;
  1003. ExpectString(';');
  1004. Result := True;
  1005. end else
  1006. Result := False;
  1007. end;
  1008. function TXMLReader.ParseReference(AOwner: TDOMNode): Boolean; // [67] [68]
  1009. begin
  1010. if not CheckForChar('&') then begin
  1011. Result := False;
  1012. exit;
  1013. end;
  1014. if CheckForChar('#') then begin // Test for CharRef [66]
  1015. if CheckForChar('x') then begin
  1016. // !!!: there must be at least one digit
  1017. while buf[0] in ['0'..'9', 'a'..'f', 'A'..'F'] do Inc(buf);
  1018. end else
  1019. // !!!: there must be at least one digit
  1020. while buf[0] in ['0'..'9'] do Inc(buf);
  1021. end else
  1022. AOwner.AppendChild(doc.CreateEntityReference(ExpectName));
  1023. ExpectString(';');
  1024. Result := True;
  1025. end;
  1026. procedure TXMLReader.ExpectReference(AOwner: TDOMNode);
  1027. begin
  1028. if not ParseReference(AOwner) then
  1029. RaiseExc('Expected reference ("&Name;" or "%Name;")');
  1030. end;
  1031. function TXMLReader.ParseExternalID: Boolean; // [75]
  1032. function GetSystemLiteral: String;
  1033. var
  1034. OldBuf: PChar;
  1035. begin
  1036. if buf[0] = '''' then begin
  1037. Inc(buf);
  1038. OldBuf := buf;
  1039. while (buf[0] <> '''') and (buf[0] <> #0) do begin
  1040. Inc(buf);
  1041. end;
  1042. Result := GetString(OldBuf,buf-OldBuf);
  1043. ExpectString('''');
  1044. end else if buf[0] = '"' then begin
  1045. Inc(buf);
  1046. OldBuf := buf;
  1047. while (buf[0] <> '"') and (buf[0] <> #0) do begin
  1048. Inc(buf);
  1049. end;
  1050. Result := GetString(OldBuf,buf-OldBuf);
  1051. ExpectString('"');
  1052. end else
  1053. Result:='';
  1054. end;
  1055. procedure SkipSystemLiteral;
  1056. begin
  1057. if buf[0] = '''' then begin
  1058. Inc(buf);
  1059. while (buf[0] <> '''') and (buf[0] <> #0) do begin
  1060. Inc(buf);
  1061. end;
  1062. ExpectString('''');
  1063. end else if buf[0] = '"' then begin
  1064. Inc(buf);
  1065. while (buf[0] <> '"') and (buf[0] <> #0) do begin
  1066. Inc(buf);
  1067. end;
  1068. ExpectString('"');
  1069. end;
  1070. end;
  1071. begin
  1072. if CheckFor('SYSTEM') then begin
  1073. ExpectWhitespace;
  1074. SkipSystemLiteral;
  1075. Result := True;
  1076. end else if CheckFor('PUBLIC') then begin
  1077. ExpectWhitespace;
  1078. SkipPubidLiteral;
  1079. ExpectWhitespace;
  1080. SkipSystemLiteral;
  1081. Result := True;
  1082. end else
  1083. Result := False;
  1084. end;
  1085. procedure TXMLReader.ExpectExternalID;
  1086. begin
  1087. if not ParseExternalID then
  1088. RaiseExc('Expected external ID');
  1089. end;
  1090. function TXMLReader.ParseEncodingDecl: String; // [80]
  1091. function ParseEncName: String;
  1092. var OldBuf: PChar;
  1093. begin
  1094. if not (buf[0] in ['A'..'Z', 'a'..'z']) then
  1095. RaiseExc('Expected character (A-Z, a-z)');
  1096. OldBuf := buf;
  1097. Inc(buf);
  1098. SkipString(['A'..'Z', 'a'..'z', '0'..'9', '.', '_', '-']);
  1099. Result := GetString(OldBuf,buf-OldBuf);
  1100. end;
  1101. begin
  1102. SetLength(Result, 0);
  1103. SkipWhitespace;
  1104. if CheckFor('encoding') then begin
  1105. ExpectEq;
  1106. if buf[0] = '''' then begin
  1107. Inc(buf);
  1108. Result := ParseEncName;
  1109. ExpectString('''');
  1110. end else if buf[0] = '"' then begin
  1111. Inc(buf);
  1112. Result := ParseEncName;
  1113. ExpectString('"');
  1114. end;
  1115. end;
  1116. end;
  1117. procedure TXMLReader.SkipEncodingDecl;
  1118. procedure ParseEncName;
  1119. begin
  1120. if not (buf[0] in ['A'..'Z', 'a'..'z']) then
  1121. RaiseExc('Expected character (A-Z, a-z)');
  1122. Inc(buf);
  1123. SkipString(['A'..'Z', 'a'..'z', '0'..'9', '.', '_', '-']);
  1124. end;
  1125. begin
  1126. SkipWhitespace;
  1127. if CheckFor('encoding') then begin
  1128. ExpectEq;
  1129. if buf[0] = '''' then begin
  1130. Inc(buf);
  1131. ParseEncName;
  1132. ExpectString('''');
  1133. end else if buf[0] = '"' then begin
  1134. Inc(buf);
  1135. ParseEncName;
  1136. ExpectString('"');
  1137. end;
  1138. end;
  1139. end;
  1140. { Currently, this method will only resolve the entities which are
  1141. predefined in XML: }
  1142. procedure TXMLReader.ResolveEntities(RootNode: TDOMNode);
  1143. var
  1144. Node, NextNode: TDOMNode;
  1145. procedure ReplaceEntityRef(EntityNode: TDOMNode; const Replacement: string);
  1146. var
  1147. PrevSibling, NextSibling: TDOMNode;
  1148. begin
  1149. PrevSibling := EntityNode.PreviousSibling;
  1150. NextSibling := EntityNode.NextSibling;
  1151. if Assigned(PrevSibling) and (PrevSibling.NodeType = TEXT_NODE) then
  1152. begin
  1153. TDOMCharacterData(PrevSibling).AppendData(Replacement);
  1154. RootNode.RemoveChild(EntityNode);
  1155. if Assigned(NextSibling) and (NextSibling.NodeType = TEXT_NODE) then
  1156. begin
  1157. // next sibling is to be removed, so we can't use it anymore
  1158. NextNode := NextSibling.NextSibling;
  1159. TDOMCharacterData(PrevSibling).AppendData(
  1160. TDOMCharacterData(NextSibling).Data);
  1161. RootNode.RemoveChild(NextSibling);
  1162. end
  1163. end else
  1164. if Assigned(NextSibling) and (NextSibling.NodeType = TEXT_NODE) then
  1165. begin
  1166. TDOMCharacterData(NextSibling).InsertData(0, Replacement);
  1167. RootNode.RemoveChild(EntityNode);
  1168. end else
  1169. RootNode.ReplaceChild(Doc.CreateTextNode(Replacement), EntityNode);
  1170. end;
  1171. begin
  1172. Node := RootNode.FirstChild;
  1173. while Assigned(Node) do
  1174. begin
  1175. NextNode := Node.NextSibling;
  1176. if Node.NodeType = ENTITY_REFERENCE_NODE then
  1177. if Node.NodeName = 'amp' then
  1178. ReplaceEntityRef(Node, '&')
  1179. else if Node.NodeName = 'apos' then
  1180. ReplaceEntityRef(Node, '''')
  1181. else if Node.NodeName = 'gt' then
  1182. ReplaceEntityRef(Node, '>')
  1183. else if Node.NodeName = 'lt' then
  1184. ReplaceEntityRef(Node, '<')
  1185. else if Node.NodeName = 'quot' then
  1186. ReplaceEntityRef(Node, '"');
  1187. Node := NextNode;
  1188. end;
  1189. end;
  1190. procedure ReadXMLFile(var ADoc: TXMLDocument; var f: File);
  1191. var
  1192. reader: TXMLReader;
  1193. buf: PChar;
  1194. BufSize: LongInt;
  1195. begin
  1196. ADoc := nil;
  1197. BufSize := FileSize(f) + 1;
  1198. if BufSize <= 1 then
  1199. exit;
  1200. GetMem(buf, BufSize);
  1201. try
  1202. BlockRead(f, buf^, BufSize - 1);
  1203. buf[BufSize - 1] := #0;
  1204. Reader := TXMLReader.Create;
  1205. try
  1206. Reader.ProcessXML(buf, TFileRec(f).name);
  1207. ADoc := TXMLDocument(Reader.doc);
  1208. finally
  1209. Reader.Free;
  1210. end;
  1211. finally
  1212. FreeMem(buf);
  1213. end;
  1214. end;
  1215. procedure ReadXMLFile(var ADoc: TXMLDocument; var f: TStream; const AFilename: String);
  1216. var
  1217. reader: TXMLReader;
  1218. buf: PChar;
  1219. begin
  1220. ADoc := nil;
  1221. if f.Size = 0 then exit;
  1222. GetMem(buf, f.Size + 1);
  1223. try
  1224. f.Read(buf^, f.Size);
  1225. buf[f.Size] := #0;
  1226. Reader := TXMLReader.Create;
  1227. try
  1228. Reader.ProcessXML(buf, AFilename);
  1229. finally
  1230. ADoc := TXMLDocument(Reader.doc);
  1231. Reader.Free;
  1232. end;
  1233. finally
  1234. FreeMem(buf);
  1235. end;
  1236. end;
  1237. procedure ReadXMLFile(var ADoc: TXMLDocument; var f: TStream);
  1238. begin
  1239. ReadXMLFile(ADoc, f, '<Stream>');
  1240. end;
  1241. procedure ReadXMLFile(var ADoc: TXMLDocument; const AFilename: String);
  1242. var
  1243. FileStream: TFileStream;
  1244. MemStream: TMemoryStream;
  1245. begin
  1246. ADoc := nil;
  1247. FileStream := TFileStream.Create(AFilename, fmOpenRead);
  1248. if FileStream=nil then exit;
  1249. MemStream := TMemoryStream.Create;
  1250. try
  1251. MemStream.LoadFromStream(FileStream);
  1252. ReadXMLFile(ADoc, MemStream, AFilename);
  1253. finally
  1254. FileStream.Free;
  1255. MemStream.Free;
  1256. end;
  1257. end;
  1258. procedure ReadXMLFragment(AParentNode: TDOMNode; var f: File);
  1259. var
  1260. Reader: TXMLReader;
  1261. buf: PChar;
  1262. BufSize: LongInt;
  1263. begin
  1264. BufSize := FileSize(f) + 1;
  1265. if BufSize <= 1 then
  1266. exit;
  1267. GetMem(buf, BufSize);
  1268. try
  1269. BlockRead(f, buf^, BufSize - 1);
  1270. buf[BufSize - 1] := #0;
  1271. Reader := TXMLReader.Create;
  1272. try
  1273. Reader.Doc := AParentNode.OwnerDocument;
  1274. Reader.ProcessFragment(AParentNode, buf, TFileRec(f).name);
  1275. finally
  1276. Reader.Free;
  1277. end;
  1278. finally
  1279. FreeMem(buf);
  1280. end;
  1281. end;
  1282. procedure ReadXMLFragment(AParentNode: TDOMNode; var f: TStream; const AFilename: String);
  1283. var
  1284. Reader: TXMLReader;
  1285. buf: PChar;
  1286. begin
  1287. if f.Size = 0 then
  1288. exit;
  1289. GetMem(buf, f.Size + 1);
  1290. try
  1291. f.Read(buf^, f.Size);
  1292. buf[f.Size] := #0;
  1293. Reader := TXMLReader.Create;
  1294. Reader.Doc := AParentNode.OwnerDocument;
  1295. try
  1296. Reader.ProcessFragment(AParentNode, buf, AFilename);
  1297. finally
  1298. Reader.Free;
  1299. end;
  1300. finally
  1301. FreeMem(buf);
  1302. end;
  1303. end;
  1304. procedure ReadXMLFragment(AParentNode: TDOMNode; var f: TStream);
  1305. begin
  1306. ReadXMLFragment(AParentNode, f, '<Stream>');
  1307. end;
  1308. procedure ReadXMLFragment(AParentNode: TDOMNode; const AFilename: String);
  1309. var
  1310. Stream: TStream;
  1311. begin
  1312. Stream := TFileStream.Create(AFilename, fmOpenRead);
  1313. try
  1314. ReadXMLFragment(AParentNode, Stream, AFilename);
  1315. finally
  1316. Stream.Free;
  1317. end;
  1318. end;
  1319. procedure ReadDTDFile(var ADoc: TXMLDocument; var f: File);
  1320. var
  1321. Reader: TXMLReader;
  1322. buf: PChar;
  1323. BufSize: LongInt;
  1324. begin
  1325. ADoc := nil;
  1326. BufSize := FileSize(f) + 1;
  1327. if BufSize <= 1 then
  1328. exit;
  1329. GetMem(buf, BufSize);
  1330. try
  1331. BlockRead(f, buf^, BufSize - 1);
  1332. buf[BufSize - 1] := #0;
  1333. Reader := TXMLReader.Create;
  1334. try
  1335. Reader.ProcessDTD(buf, TFileRec(f).name);
  1336. ADoc := TXMLDocument(Reader.doc);
  1337. finally
  1338. Reader.Free;
  1339. end;
  1340. finally
  1341. FreeMem(buf);
  1342. end;
  1343. end;
  1344. procedure ReadDTDFile(var ADoc: TXMLDocument; var f: TStream; const AFilename: String);
  1345. var
  1346. Reader: TXMLReader;
  1347. buf: PChar;
  1348. begin
  1349. ADoc := nil;
  1350. if f.Size = 0 then
  1351. exit;
  1352. GetMem(buf, f.Size + 1);
  1353. try
  1354. f.Read(buf^, f.Size);
  1355. buf[f.Size] := #0;
  1356. Reader := TXMLReader.Create;
  1357. try
  1358. Reader.ProcessDTD(buf, AFilename);
  1359. ADoc := TXMLDocument(Reader.doc);
  1360. finally
  1361. Reader.Free;
  1362. end;
  1363. finally
  1364. FreeMem(buf);
  1365. end;
  1366. end;
  1367. procedure ReadDTDFile(var ADoc: TXMLDocument; var f: TStream);
  1368. begin
  1369. ReadDTDFile(ADoc, f, '<Stream>');
  1370. end;
  1371. procedure ReadDTDFile(var ADoc: TXMLDocument; const AFilename: String);
  1372. var
  1373. Stream: TStream;
  1374. begin
  1375. ADoc := nil;
  1376. Stream := TFileStream.Create(AFilename, fmOpenRead);
  1377. try
  1378. ReadDTDFile(ADoc, Stream, AFilename);
  1379. finally
  1380. Stream.Free;
  1381. end;
  1382. end;
  1383. end.