xmlread.pp 37 KB

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