xmlread.pp 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581
  1. {
  2. $Id: xmlread.pp,v 1.17 2005/05/02 13:06:51 michael Exp $
  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. {$DEFINE UsesFPCWidestrings}
  324. {$ENDIF}
  325. {$IFDEF UsesFPCWidestrings}
  326. {procedure SimpleWide2AnsiMove(source:pwidechar;dest:pchar;len:sizeint);
  327. var
  328. i : sizeint;
  329. begin
  330. for i:=1 to len do
  331. begin
  332. if word(source^)<256 then
  333. dest^:=char(word(source^))
  334. else
  335. dest^:='?';
  336. inc(dest);
  337. inc(source);
  338. end;
  339. end;
  340. procedure SimpleAnsi2WideMove(source:pchar;dest:pwidechar;len:sizeint);
  341. var
  342. i : sizeint;
  343. begin
  344. for i:=1 to len do
  345. begin
  346. dest^:=widechar(byte(source^));
  347. inc(dest);
  348. inc(source);
  349. end;
  350. end;
  351. }
  352. {$ENDIF}
  353. procedure TXMLReader.ProcessXML(ABuf: PChar; const AFilename: String); // [1]
  354. {$IFDEF UsesFPCWidestrings}
  355. var
  356. OldWideStringManager,MyWideStringManager : TWideStringManager;
  357. {$ENDIF}
  358. begin
  359. buf := ABuf;
  360. BufStart := ABuf;
  361. Filename := AFilename;
  362. {$IFDEF UsesFPCWidestrings}
  363. GetWideStringManager(MyWideStringManager);
  364. MyWideStringManager.Wide2AnsiMoveProc:=@defaultWide2AnsiMove;
  365. MyWideStringManager.Ansi2WideMoveProc:=@defaultAnsi2WideMove;
  366. SetWideStringManager(MyWideStringManager, OldWideStringManager);
  367. try
  368. {$ENDIF}
  369. doc := TXMLReaderDocument.Create;
  370. ExpectProlog;
  371. {$IFDEF MEM_CHECK}CheckHeapWrtMemCnt('TXMLReader.ProcessXML A');{$ENDIF}
  372. ExpectElement(doc);
  373. {$IFDEF MEM_CHECK}CheckHeapWrtMemCnt('TXMLReader.ProcessXML B');{$ENDIF}
  374. ParseMisc(doc);
  375. {$IFDEF UsesFPCWidestrings}
  376. finally
  377. SetWideStringManager(OldWideStringManager);
  378. end;
  379. {$ENDIF}
  380. if buf[0] <> #0 then
  381. RaiseExc('Text after end of document element found');
  382. end;
  383. procedure TXMLReader.ProcessFragment(AOwner: TDOMNode; ABuf: PChar; const AFilename: String);
  384. {$IFDEF UsesFPCWidestrings}
  385. var
  386. OldWideStringManager: TWideStringManager;
  387. {$ENDIF}
  388. begin
  389. buf := ABuf;
  390. BufStart := ABuf;
  391. Filename := AFilename;
  392. {$IFDEF UsesFPCWidestrings}
  393. SetWideStringManager(WideStringManager, OldWideStringManager);
  394. try
  395. {$ENDIF}
  396. SkipWhitespace;
  397. while ParseCharData(AOwner) or ParseCDSect(AOwner) or ParsePI or
  398. ParseComment(AOwner) or ParseElement(AOwner) or
  399. ParseReference(AOwner) do
  400. SkipWhitespace;
  401. {$IFDEF UsesFPCWidestrings}
  402. finally
  403. SetWideStringManager(OldWideStringManager);
  404. end;
  405. {$ENDIF}
  406. end;
  407. function TXMLReader.CheckName: Boolean;
  408. var OldBuf: PChar;
  409. begin
  410. if not (buf[0] in (Letter + ['_', ':'])) then begin
  411. Result := False;
  412. exit;
  413. end;
  414. OldBuf := buf;
  415. Inc(buf);
  416. SkipString(Letter + ['0'..'9', '.', '-', '_', ':']);
  417. buf := OldBuf;
  418. Result := True;
  419. end;
  420. function TXMLReader.GetName(var s: String): Boolean; // [5]
  421. var OldBuf: PChar;
  422. begin
  423. if not (buf[0] in (Letter + ['_', ':'])) then begin
  424. SetLength(s, 0);
  425. Result := False;
  426. exit;
  427. end;
  428. OldBuf := buf;
  429. Inc(buf);
  430. SkipString(Letter + ['0'..'9', '.', '-', '_', ':']);
  431. s := GetString(OldBuf,buf-OldBuf);
  432. Result := True;
  433. end;
  434. function TXMLReader.ExpectName: String; // [5]
  435. procedure RaiseNameNotFound;
  436. begin
  437. RaiseExc('Expected letter, "_" or ":" for name, found "' + buf[0] + '"');
  438. end;
  439. var OldBuf: PChar;
  440. begin
  441. if not (buf[0] in (Letter + ['_', ':'])) then
  442. RaiseNameNotFound;
  443. OldBuf := buf;
  444. Inc(buf);
  445. SkipString(Letter + ['0'..'9', '.', '-', '_', ':']);
  446. Result:=GetString(OldBuf,buf-OldBuf);
  447. end;
  448. procedure TXMLReader.SkipName;
  449. procedure RaiseSkipNameNotFound;
  450. begin
  451. RaiseExc('Expected letter, "_" or ":" for name, found "' + buf[0] + '"');
  452. end;
  453. begin
  454. if not (buf[0] in (Letter + ['_', ':'])) then
  455. RaiseSkipNameNotFound;
  456. Inc(buf);
  457. SkipString(Letter + ['0'..'9', '.', '-', '_', ':']);
  458. end;
  459. procedure TXMLReader.ExpectAttValue(attr: TDOMAttr); // [10]
  460. var
  461. OldBuf: PChar;
  462. procedure FlushStringBuffer;
  463. var
  464. s: String;
  465. begin
  466. if OldBuf<>buf then begin
  467. s := GetString(OldBuf,buf-OldBuf);
  468. OldBuf := buf;
  469. attr.AppendChild(doc.CreateTextNode(s));
  470. SetLength(s, 0);
  471. end;
  472. end;
  473. var
  474. StrDel: char;
  475. begin
  476. if (buf[0] <> '''') and (buf[0] <> '"') then
  477. RaiseExc('Expected quotation marks');
  478. StrDel:=buf[0];
  479. Inc(buf);
  480. OldBuf := buf;
  481. while (buf[0]<>StrDel) and (buf[0]<>#0) do begin
  482. if buf[0] <> '&' then begin
  483. Inc(buf);
  484. end else
  485. begin
  486. if OldBuf<>buf then FlushStringBuffer;
  487. ParseReference(attr);
  488. OldBuf := buf;
  489. end;
  490. end;
  491. if OldBuf<>buf then FlushStringBuffer;
  492. inc(buf);
  493. ResolveEntities(Attr);
  494. end;
  495. function TXMLReader.ExpectPubidLiteral: String;
  496. begin
  497. SetLength(Result, 0);
  498. if CheckForChar('''') then begin
  499. SkipString(PubidChars - ['''']);
  500. ExpectString('''');
  501. end else if CheckForChar('"') then begin
  502. SkipString(PubidChars - ['"']);
  503. ExpectString('"');
  504. end else
  505. RaiseExc('Expected quotation marks');
  506. end;
  507. procedure TXMLReader.SkipPubidLiteral;
  508. begin
  509. if CheckForChar('''') then begin
  510. SkipString(PubidChars - ['''']);
  511. ExpectString('''');
  512. end else if CheckForChar('"') then begin
  513. SkipString(PubidChars - ['"']);
  514. ExpectString('"');
  515. end else
  516. RaiseExc('Expected quotation marks');
  517. end;
  518. function TXMLReader.ParseComment(AOwner: TDOMNode): Boolean; // [15]
  519. var
  520. comment: String;
  521. OldBuf: PChar;
  522. begin
  523. if CheckFor('<!--') then begin
  524. OldBuf := buf;
  525. while (buf[0] <> #0) and (buf[1] <> #0) and
  526. ((buf[0] <> '-') or (buf[1] <> '-')) do begin
  527. Inc(buf);
  528. end;
  529. comment:=GetString(OldBuf,buf-OldBuf);
  530. AOwner.AppendChild(doc.CreateComment(comment));
  531. ExpectString('-->');
  532. Result := True;
  533. end else
  534. Result := False;
  535. end;
  536. function TXMLReader.ParsePI: Boolean; // [16]
  537. begin
  538. if CheckFor('<?') then begin
  539. if CompareLIPChar(buf,'XML ',4) then
  540. RaiseExc('"<?xml" processing instruction not allowed here');
  541. SkipName;
  542. if SkipWhitespace then
  543. while (buf[0] <> #0) and (buf[1] <> #0) and not
  544. ((buf[0] = '?') and (buf[1] = '>')) do Inc(buf);
  545. ExpectString('?>');
  546. Result := True;
  547. end else
  548. Result := False;
  549. end;
  550. procedure TXMLReader.ExpectProlog; // [22]
  551. procedure ParseVersionNum;
  552. begin
  553. if doc.InheritsFrom(TXMLDocument) then
  554. TXMLDocument(doc).XMLVersion :=
  555. GetString(['a'..'z', 'A'..'Z', '0'..'9', '_', '.', ':', '-']);
  556. end;
  557. procedure ParseDoctypeDecls;
  558. begin
  559. repeat
  560. SkipWhitespace;
  561. until not (ParseMarkupDecl or ParsePEReference);
  562. ExpectString(']');
  563. end;
  564. var
  565. DocType: TXMLReaderDocumentType;
  566. begin
  567. if CheckFor('<?xml') then
  568. begin
  569. // '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
  570. // VersionInfo: S 'version' Eq (' VersionNum ' | " VersionNum ")
  571. SkipWhitespace;
  572. ExpectString('version');
  573. ParseEq;
  574. if buf[0] = '''' then
  575. begin
  576. Inc(buf);
  577. ParseVersionNum;
  578. ExpectString('''');
  579. end else if buf[0] = '"' then
  580. begin
  581. Inc(buf);
  582. ParseVersionNum;
  583. ExpectString('"');
  584. end else
  585. RaiseExc('Expected single or double quotation mark');
  586. // EncodingDecl?
  587. SkipEncodingDecl;
  588. // SDDecl?
  589. SkipWhitespace;
  590. if CheckFor('standalone') then
  591. begin
  592. ExpectEq;
  593. if buf[0] = '''' then
  594. begin
  595. Inc(buf);
  596. if not (CheckFor('yes''') or CheckFor('no''')) then
  597. RaiseExc('Expected ''yes'' or ''no''');
  598. end else if buf[0] = '''' then
  599. begin
  600. Inc(buf);
  601. if not (CheckFor('yes"') or CheckFor('no"')) then
  602. RaiseExc('Expected "yes" or "no"');
  603. end;
  604. SkipWhitespace;
  605. end;
  606. ExpectString('?>');
  607. end;
  608. // Check for "Misc*"
  609. ParseMisc(doc);
  610. // Check for "(doctypedecl Misc*)?" [28]
  611. if CheckFor('<!DOCTYPE') then
  612. begin
  613. DocType := TXMLReaderDocumentType.Create(doc as TXMLReaderDocument);
  614. if doc.InheritsFrom(TXMLReaderDocument) then
  615. TXMLReaderDocument(doc).SetDocType(DocType);
  616. SkipWhitespace;
  617. DocType.Name := ExpectName;
  618. SkipWhitespace;
  619. if CheckForChar('[') then
  620. begin
  621. ParseDoctypeDecls;
  622. SkipWhitespace;
  623. ExpectString('>');
  624. end else if not CheckForChar('>') then
  625. begin
  626. ParseExternalID;
  627. SkipWhitespace;
  628. if CheckForChar('[') then
  629. begin
  630. ParseDoctypeDecls;
  631. SkipWhitespace;
  632. end;
  633. ExpectString('>');
  634. end;
  635. ParseMisc(doc);
  636. end;
  637. end;
  638. function TXMLReader.ParseEq: Boolean; // [25]
  639. var
  640. savedbuf: PChar;
  641. begin
  642. savedbuf := buf;
  643. SkipWhitespace;
  644. if buf[0] = '=' then begin
  645. Inc(buf);
  646. SkipWhitespace;
  647. Result := True;
  648. end else begin
  649. buf := savedbuf;
  650. Result := False;
  651. end;
  652. end;
  653. procedure TXMLReader.ExpectEq;
  654. begin
  655. if not ParseEq then
  656. RaiseExc('Expected "="');
  657. end;
  658. // Parse "Misc*":
  659. // Misc ::= Comment | PI | S
  660. procedure TXMLReader.ParseMisc(AOwner: TDOMNode); // [27]
  661. begin
  662. repeat
  663. SkipWhitespace;
  664. until not (ParseComment(AOwner) or ParsePI);
  665. end;
  666. function TXMLReader.ParseMarkupDecl: Boolean; // [29]
  667. function ParseElementDecl: Boolean; // [45]
  668. procedure ExpectChoiceOrSeq; // [49], [50]
  669. procedure ExpectCP; // [48]
  670. begin
  671. if CheckForChar('(') then
  672. ExpectChoiceOrSeq
  673. else
  674. SkipName;
  675. if CheckForChar('?') then
  676. else if CheckForChar('*') then
  677. else if CheckForChar('+') then;
  678. end;
  679. var
  680. delimiter: Char;
  681. begin
  682. SkipWhitespace;
  683. ExpectCP;
  684. SkipWhitespace;
  685. delimiter := #0;
  686. while not CheckForChar(')') do begin
  687. if delimiter = #0 then begin
  688. if (buf[0] = '|') or (buf[0] = ',') then
  689. delimiter := buf[0]
  690. else
  691. RaiseExc('Expected "|" or ","');
  692. Inc(buf);
  693. end else
  694. ExpectString(delimiter);
  695. SkipWhitespace;
  696. ExpectCP;
  697. end;
  698. end;
  699. begin
  700. if CheckFor('<!ELEMENT') then begin
  701. ExpectWhitespace;
  702. SkipName;
  703. ExpectWhitespace;
  704. // Get contentspec [46]
  705. if CheckFor('EMPTY') then
  706. else if CheckFor('ANY') then
  707. else if CheckForChar('(') then begin
  708. SkipWhitespace;
  709. if CheckFor('#PCDATA') then begin
  710. // Parse Mixed section [51]
  711. SkipWhitespace;
  712. if not CheckForChar(')') then
  713. repeat
  714. ExpectString('|');
  715. SkipWhitespace;
  716. SkipName;
  717. until CheckFor(')*');
  718. end else begin
  719. // Parse Children section [47]
  720. ExpectChoiceOrSeq;
  721. if CheckForChar('?') then
  722. else if CheckForChar('*') then
  723. else if CheckForChar('+') then;
  724. end;
  725. end else
  726. RaiseExc('Invalid content specification');
  727. SkipWhitespace;
  728. ExpectString('>');
  729. Result := True;
  730. end else
  731. Result := False;
  732. end;
  733. function ParseAttlistDecl: Boolean; // [52]
  734. var
  735. attr: TDOMAttr;
  736. begin
  737. if CheckFor('<!ATTLIST') then begin
  738. ExpectWhitespace;
  739. SkipName;
  740. SkipWhitespace;
  741. while not CheckForChar('>') do begin
  742. SkipName;
  743. ExpectWhitespace;
  744. // Get AttType [54], [55], [56]
  745. if CheckFor('CDATA') then
  746. else if CheckFor('ID') then
  747. else if CheckFor('IDREF') then
  748. else if CheckFor('IDREFS') then
  749. else if CheckFor('ENTITTY') then
  750. else if CheckFor('ENTITIES') then
  751. else if CheckFor('NMTOKEN') then
  752. else if CheckFor('NMTOKENS') then
  753. else if CheckFor('NOTATION') then begin // [57], [58]
  754. ExpectWhitespace;
  755. ExpectString('(');
  756. SkipWhitespace;
  757. SkipName;
  758. SkipWhitespace;
  759. while not CheckForChar(')') do begin
  760. ExpectString('|');
  761. SkipWhitespace;
  762. SkipName;
  763. SkipWhitespace;
  764. end;
  765. end else if CheckForChar('(') then begin // [59]
  766. SkipWhitespace;
  767. SkipString(Nmtoken);
  768. SkipWhitespace;
  769. while not CheckForChar(')') do begin
  770. ExpectString('|');
  771. SkipWhitespace;
  772. SkipString(Nmtoken);
  773. SkipWhitespace;
  774. end;
  775. end else
  776. RaiseExc('Invalid tokenized type');
  777. ExpectWhitespace;
  778. // Get DefaultDecl [60]
  779. if CheckFor('#REQUIRED') then
  780. else if CheckFor('#IMPLIED') then
  781. else begin
  782. if CheckFor('#FIXED') then
  783. SkipWhitespace;
  784. attr := doc.CreateAttribute('');
  785. ExpectAttValue(attr);
  786. end;
  787. SkipWhitespace;
  788. end;
  789. Result := True;
  790. end else
  791. Result := False;
  792. end;
  793. function ParseEntityDecl: Boolean; // [70]
  794. var
  795. NewEntity: TDOMEntity;
  796. function ParseEntityValue: Boolean; // [9]
  797. var
  798. strdel: Char;
  799. begin
  800. if (buf[0] <> '''') and (buf[0] <> '"') then begin
  801. Result := False;
  802. exit;
  803. end;
  804. strdel := buf[0];
  805. Inc(buf);
  806. while not CheckForChar(strdel) do
  807. if ParsePEReference then
  808. else if ParseReference(NewEntity) then
  809. else begin
  810. Inc(buf); // Normal haracter
  811. end;
  812. Result := True;
  813. end;
  814. begin
  815. if CheckFor('<!ENTITY') then begin
  816. ExpectWhitespace;
  817. if CheckForChar('%') then begin // [72]
  818. ExpectWhitespace;
  819. NewEntity := doc.CreateEntity(ExpectName);
  820. ExpectWhitespace;
  821. // Get PEDef [74]
  822. if ParseEntityValue then
  823. else if ParseExternalID then
  824. else
  825. RaiseExc('Expected entity value or external ID');
  826. end else begin // [71]
  827. NewEntity := doc.CreateEntity(ExpectName);
  828. ExpectWhitespace;
  829. // Get EntityDef [73]
  830. if ParseEntityValue then
  831. else begin
  832. ExpectExternalID;
  833. // Get NDataDecl [76]
  834. ExpectWhitespace;
  835. ExpectString('NDATA');
  836. ExpectWhitespace;
  837. SkipName;
  838. end;
  839. end;
  840. SkipWhitespace;
  841. ExpectString('>');
  842. Result := True;
  843. end else
  844. Result := False;
  845. end;
  846. function ParseNotationDecl: Boolean; // [82]
  847. begin
  848. if CheckFor('<!NOTATION') then begin
  849. ExpectWhitespace;
  850. SkipName;
  851. ExpectWhitespace;
  852. if ParseExternalID then
  853. else if CheckFor('PUBLIC') then begin // [83]
  854. ExpectWhitespace;
  855. SkipPubidLiteral;
  856. end else
  857. RaiseExc('Expected external or public ID');
  858. SkipWhitespace;
  859. ExpectString('>');
  860. Result := True;
  861. end else
  862. Result := False;
  863. end;
  864. begin
  865. Result := False;
  866. while ParseElementDecl or ParseAttlistDecl or ParseEntityDecl or
  867. ParseNotationDecl or ParsePI or ParseComment(doc) or SkipWhitespace do
  868. Result := True;
  869. end;
  870. procedure TXMLReader.ProcessDTD(ABuf: PChar; const AFilename: String);
  871. begin
  872. buf := ABuf;
  873. BufStart := ABuf;
  874. Filename := AFilename;
  875. doc := TXMLReaderDocument.Create;
  876. ParseMarkupDecl;
  877. {
  878. if buf[0] <> #0 then begin
  879. DebugLn('=== Unparsed: ===');
  880. //DebugLn(buf);
  881. DebugLn(StrLen(buf), ' chars');
  882. end;
  883. }
  884. end;
  885. function TXMLReader.ParseCharData(AOwner: TDOMNode): Boolean; // [14]
  886. var
  887. p: PChar;
  888. DataLen: integer;
  889. OldBuf: PChar;
  890. begin
  891. OldBuf := buf;
  892. while not (buf[0] in [#0, '<', '&']) do
  893. begin
  894. Inc(buf);
  895. end;
  896. DataLen:=buf-OldBuf;
  897. if DataLen > 0 then
  898. begin
  899. // Check if chardata has non-whitespace content
  900. p:=OldBuf;
  901. while (p<buf) and (p[0] in WhitespaceChars) do
  902. inc(p);
  903. if p<buf then
  904. AOwner.AppendChild(doc.CreateTextNode(GetString(OldBuf,DataLen)));
  905. Result := True;
  906. end
  907. else
  908. Result := False;
  909. end;
  910. function TXMLReader.ParseCDSect(AOwner: TDOMNode): Boolean; // [18]
  911. var
  912. OldBuf: PChar;
  913. begin
  914. if CheckFor('<![CDATA[') then
  915. begin
  916. OldBuf := buf;
  917. while not CheckFor(']]>') do
  918. begin
  919. Inc(buf);
  920. end;
  921. AOwner.AppendChild(doc.CreateCDATASection(GetString(OldBuf,buf-OldBuf-3))); { Copy CDATA, discarding terminator }
  922. Result := True;
  923. end
  924. else
  925. Result := False;
  926. end;
  927. function TXMLReader.ParseElement(AOwner: TDOMNode): Boolean; // [39] [40] [44]
  928. var
  929. NewElem: TDOMElement;
  930. procedure CreateNameElement;
  931. var
  932. IsEmpty: Boolean;
  933. attr: TDOMAttr;
  934. name: string;
  935. begin
  936. {$IFDEF MEM_CHECK}CheckHeapWrtMemCnt(' CreateNameElement A');{$ENDIF}
  937. GetName(name);
  938. NewElem := doc.CreateElement(name);
  939. AOwner.AppendChild(NewElem);
  940. SkipWhitespace;
  941. IsEmpty := False;
  942. while True do
  943. begin
  944. {$IFDEF MEM_CHECK}CheckHeapWrtMemCnt(' CreateNameElement E');{$ENDIF}
  945. if CheckFor('/>') then
  946. begin
  947. IsEmpty := True;
  948. break;
  949. end;
  950. if CheckForChar('>') then
  951. break;
  952. // Get Attribute [41]
  953. attr := doc.CreateAttribute(ExpectName);
  954. NewElem.Attributes.SetNamedItem(attr);
  955. ExpectEq;
  956. ExpectAttValue(attr);
  957. SkipWhitespace;
  958. end;
  959. if not IsEmpty then
  960. begin
  961. // Get content
  962. SkipWhitespace;
  963. while ParseCharData(NewElem) or ParseCDSect(NewElem) or ParsePI or
  964. ParseComment(NewElem) or ParseElement(NewElem) or
  965. ParseReference(NewElem) do;
  966. // Get ETag [42]
  967. ExpectString('</');
  968. if ExpectName <> name then
  969. RaiseExc('Unmatching element end tag (expected "</' + name + '>")');
  970. SkipWhitespace;
  971. ExpectString('>');
  972. end;
  973. {$IFDEF MEM_CHECK}CheckHeapWrtMemCnt(' CreateNameElement END');{$ENDIF}
  974. ResolveEntities(NewElem);
  975. end;
  976. var
  977. OldBuf: PChar;
  978. begin
  979. OldBuf := Buf;
  980. if CheckForChar('<') then
  981. begin
  982. {$IFDEF MEM_CHECK}CheckHeapWrtMemCnt('TXMLReader.ParseElement A');{$ENDIF}
  983. if not CheckName then
  984. begin
  985. Buf := OldBuf;
  986. Result := False;
  987. end else begin
  988. CreateNameElement;
  989. Result := True;
  990. end;
  991. end else
  992. Result := False;
  993. {$IFDEF MEM_CHECK}CheckHeapWrtMemCnt('TXMLReader.ParseElement END');{$ENDIF}
  994. end;
  995. procedure TXMLReader.ExpectElement(AOwner: TDOMNode);
  996. begin
  997. if not ParseElement(AOwner) then
  998. RaiseExc('Expected element');
  999. end;
  1000. function TXMLReader.ParsePEReference: Boolean; // [69]
  1001. begin
  1002. if CheckForChar('%') then begin
  1003. SkipName;
  1004. ExpectString(';');
  1005. Result := True;
  1006. end else
  1007. Result := False;
  1008. end;
  1009. function TXMLReader.ParseReference(AOwner: TDOMNode): Boolean; // [67] [68]
  1010. begin
  1011. if not CheckForChar('&') then begin
  1012. Result := False;
  1013. exit;
  1014. end;
  1015. if CheckForChar('#') then begin // Test for CharRef [66]
  1016. if CheckForChar('x') then begin
  1017. // !!!: there must be at least one digit
  1018. while buf[0] in ['0'..'9', 'a'..'f', 'A'..'F'] do Inc(buf);
  1019. end else
  1020. // !!!: there must be at least one digit
  1021. while buf[0] in ['0'..'9'] do Inc(buf);
  1022. end else
  1023. AOwner.AppendChild(doc.CreateEntityReference(ExpectName));
  1024. ExpectString(';');
  1025. Result := True;
  1026. end;
  1027. procedure TXMLReader.ExpectReference(AOwner: TDOMNode);
  1028. begin
  1029. if not ParseReference(AOwner) then
  1030. RaiseExc('Expected reference ("&Name;" or "%Name;")');
  1031. end;
  1032. function TXMLReader.ParseExternalID: Boolean; // [75]
  1033. function GetSystemLiteral: String;
  1034. var
  1035. OldBuf: PChar;
  1036. begin
  1037. if buf[0] = '''' then begin
  1038. Inc(buf);
  1039. OldBuf := buf;
  1040. while (buf[0] <> '''') and (buf[0] <> #0) do begin
  1041. Inc(buf);
  1042. end;
  1043. Result := GetString(OldBuf,buf-OldBuf);
  1044. ExpectString('''');
  1045. end else if buf[0] = '"' then begin
  1046. Inc(buf);
  1047. OldBuf := buf;
  1048. while (buf[0] <> '"') and (buf[0] <> #0) do begin
  1049. Inc(buf);
  1050. end;
  1051. Result := GetString(OldBuf,buf-OldBuf);
  1052. ExpectString('"');
  1053. end else
  1054. Result:='';
  1055. end;
  1056. procedure SkipSystemLiteral;
  1057. begin
  1058. if buf[0] = '''' then begin
  1059. Inc(buf);
  1060. while (buf[0] <> '''') and (buf[0] <> #0) do begin
  1061. Inc(buf);
  1062. end;
  1063. ExpectString('''');
  1064. end else if buf[0] = '"' then begin
  1065. Inc(buf);
  1066. while (buf[0] <> '"') and (buf[0] <> #0) do begin
  1067. Inc(buf);
  1068. end;
  1069. ExpectString('"');
  1070. end;
  1071. end;
  1072. begin
  1073. if CheckFor('SYSTEM') then begin
  1074. ExpectWhitespace;
  1075. SkipSystemLiteral;
  1076. Result := True;
  1077. end else if CheckFor('PUBLIC') then begin
  1078. ExpectWhitespace;
  1079. SkipPubidLiteral;
  1080. ExpectWhitespace;
  1081. SkipSystemLiteral;
  1082. Result := True;
  1083. end else
  1084. Result := False;
  1085. end;
  1086. procedure TXMLReader.ExpectExternalID;
  1087. begin
  1088. if not ParseExternalID then
  1089. RaiseExc('Expected external ID');
  1090. end;
  1091. function TXMLReader.ParseEncodingDecl: String; // [80]
  1092. function ParseEncName: String;
  1093. var OldBuf: PChar;
  1094. begin
  1095. if not (buf[0] in ['A'..'Z', 'a'..'z']) then
  1096. RaiseExc('Expected character (A-Z, a-z)');
  1097. OldBuf := buf;
  1098. Inc(buf);
  1099. SkipString(['A'..'Z', 'a'..'z', '0'..'9', '.', '_', '-']);
  1100. Result := GetString(OldBuf,buf-OldBuf);
  1101. end;
  1102. begin
  1103. SetLength(Result, 0);
  1104. SkipWhitespace;
  1105. if CheckFor('encoding') then begin
  1106. ExpectEq;
  1107. if buf[0] = '''' then begin
  1108. Inc(buf);
  1109. Result := ParseEncName;
  1110. ExpectString('''');
  1111. end else if buf[0] = '"' then begin
  1112. Inc(buf);
  1113. Result := ParseEncName;
  1114. ExpectString('"');
  1115. end;
  1116. end;
  1117. end;
  1118. procedure TXMLReader.SkipEncodingDecl;
  1119. procedure ParseEncName;
  1120. begin
  1121. if not (buf[0] in ['A'..'Z', 'a'..'z']) then
  1122. RaiseExc('Expected character (A-Z, a-z)');
  1123. Inc(buf);
  1124. SkipString(['A'..'Z', 'a'..'z', '0'..'9', '.', '_', '-']);
  1125. end;
  1126. begin
  1127. SkipWhitespace;
  1128. if CheckFor('encoding') then begin
  1129. ExpectEq;
  1130. if buf[0] = '''' then begin
  1131. Inc(buf);
  1132. ParseEncName;
  1133. ExpectString('''');
  1134. end else if buf[0] = '"' then begin
  1135. Inc(buf);
  1136. ParseEncName;
  1137. ExpectString('"');
  1138. end;
  1139. end;
  1140. end;
  1141. { Currently, this method will only resolve the entities which are
  1142. predefined in XML: }
  1143. procedure TXMLReader.ResolveEntities(RootNode: TDOMNode);
  1144. var
  1145. Node, NextNode: TDOMNode;
  1146. procedure ReplaceEntityRef(EntityNode: TDOMNode; const Replacement: string);
  1147. var
  1148. PrevSibling, NextSibling: TDOMNode;
  1149. begin
  1150. PrevSibling := EntityNode.PreviousSibling;
  1151. NextSibling := EntityNode.NextSibling;
  1152. if Assigned(PrevSibling) and (PrevSibling.NodeType = TEXT_NODE) then
  1153. begin
  1154. TDOMCharacterData(PrevSibling).AppendData(Replacement);
  1155. RootNode.RemoveChild(EntityNode);
  1156. if Assigned(NextSibling) and (NextSibling.NodeType = TEXT_NODE) then
  1157. begin
  1158. // next sibling is to be removed, so we can't use it anymore
  1159. NextNode := NextSibling.NextSibling;
  1160. TDOMCharacterData(PrevSibling).AppendData(
  1161. TDOMCharacterData(NextSibling).Data);
  1162. RootNode.RemoveChild(NextSibling);
  1163. end
  1164. end else
  1165. if Assigned(NextSibling) and (NextSibling.NodeType = TEXT_NODE) then
  1166. begin
  1167. TDOMCharacterData(NextSibling).InsertData(0, Replacement);
  1168. RootNode.RemoveChild(EntityNode);
  1169. end else
  1170. RootNode.ReplaceChild(Doc.CreateTextNode(Replacement), EntityNode);
  1171. end;
  1172. begin
  1173. Node := RootNode.FirstChild;
  1174. while Assigned(Node) do
  1175. begin
  1176. NextNode := Node.NextSibling;
  1177. if Node.NodeType = ENTITY_REFERENCE_NODE then
  1178. if Node.NodeName = 'amp' then
  1179. ReplaceEntityRef(Node, '&')
  1180. else if Node.NodeName = 'apos' then
  1181. ReplaceEntityRef(Node, '''')
  1182. else if Node.NodeName = 'gt' then
  1183. ReplaceEntityRef(Node, '>')
  1184. else if Node.NodeName = 'lt' then
  1185. ReplaceEntityRef(Node, '<')
  1186. else if Node.NodeName = 'quot' then
  1187. ReplaceEntityRef(Node, '"');
  1188. Node := NextNode;
  1189. end;
  1190. end;
  1191. procedure ReadXMLFile(var ADoc: TXMLDocument; var f: File);
  1192. var
  1193. reader: TXMLReader;
  1194. buf: PChar;
  1195. BufSize: LongInt;
  1196. begin
  1197. ADoc := nil;
  1198. BufSize := FileSize(f) + 1;
  1199. if BufSize <= 1 then
  1200. exit;
  1201. GetMem(buf, BufSize);
  1202. try
  1203. BlockRead(f, buf^, BufSize - 1);
  1204. buf[BufSize - 1] := #0;
  1205. Reader := TXMLReader.Create;
  1206. try
  1207. Reader.ProcessXML(buf, TFileRec(f).name);
  1208. ADoc := TXMLDocument(Reader.doc);
  1209. finally
  1210. Reader.Free;
  1211. end;
  1212. finally
  1213. FreeMem(buf);
  1214. end;
  1215. end;
  1216. procedure ReadXMLFile(var ADoc: TXMLDocument; var f: TStream; const AFilename: String);
  1217. var
  1218. reader: TXMLReader;
  1219. buf: PChar;
  1220. begin
  1221. ADoc := nil;
  1222. if f.Size = 0 then exit;
  1223. GetMem(buf, f.Size + 1);
  1224. try
  1225. f.Read(buf^, f.Size);
  1226. buf[f.Size] := #0;
  1227. Reader := TXMLReader.Create;
  1228. try
  1229. Reader.ProcessXML(buf, AFilename);
  1230. finally
  1231. ADoc := TXMLDocument(Reader.doc);
  1232. Reader.Free;
  1233. end;
  1234. finally
  1235. FreeMem(buf);
  1236. end;
  1237. end;
  1238. procedure ReadXMLFile(var ADoc: TXMLDocument; var f: TStream);
  1239. begin
  1240. ReadXMLFile(ADoc, f, '<Stream>');
  1241. end;
  1242. procedure ReadXMLFile(var ADoc: TXMLDocument; const AFilename: String);
  1243. var
  1244. FileStream: TFileStream;
  1245. MemStream: TMemoryStream;
  1246. begin
  1247. ADoc := nil;
  1248. FileStream := TFileStream.Create(AFilename, fmOpenRead);
  1249. if FileStream=nil then exit;
  1250. MemStream := TMemoryStream.Create;
  1251. try
  1252. MemStream.LoadFromStream(FileStream);
  1253. ReadXMLFile(ADoc, MemStream, AFilename);
  1254. finally
  1255. FileStream.Free;
  1256. MemStream.Free;
  1257. end;
  1258. end;
  1259. procedure ReadXMLFragment(AParentNode: TDOMNode; var f: File);
  1260. var
  1261. Reader: TXMLReader;
  1262. buf: PChar;
  1263. BufSize: LongInt;
  1264. begin
  1265. BufSize := FileSize(f) + 1;
  1266. if BufSize <= 1 then
  1267. exit;
  1268. GetMem(buf, BufSize);
  1269. try
  1270. BlockRead(f, buf^, BufSize - 1);
  1271. buf[BufSize - 1] := #0;
  1272. Reader := TXMLReader.Create;
  1273. try
  1274. Reader.Doc := AParentNode.OwnerDocument;
  1275. Reader.ProcessFragment(AParentNode, buf, TFileRec(f).name);
  1276. finally
  1277. Reader.Free;
  1278. end;
  1279. finally
  1280. FreeMem(buf);
  1281. end;
  1282. end;
  1283. procedure ReadXMLFragment(AParentNode: TDOMNode; var f: TStream; const AFilename: String);
  1284. var
  1285. Reader: TXMLReader;
  1286. buf: PChar;
  1287. begin
  1288. if f.Size = 0 then
  1289. exit;
  1290. GetMem(buf, f.Size + 1);
  1291. try
  1292. f.Read(buf^, f.Size);
  1293. buf[f.Size] := #0;
  1294. Reader := TXMLReader.Create;
  1295. Reader.Doc := AParentNode.OwnerDocument;
  1296. try
  1297. Reader.ProcessFragment(AParentNode, buf, AFilename);
  1298. finally
  1299. Reader.Free;
  1300. end;
  1301. finally
  1302. FreeMem(buf);
  1303. end;
  1304. end;
  1305. procedure ReadXMLFragment(AParentNode: TDOMNode; var f: TStream);
  1306. begin
  1307. ReadXMLFragment(AParentNode, f, '<Stream>');
  1308. end;
  1309. procedure ReadXMLFragment(AParentNode: TDOMNode; const AFilename: String);
  1310. var
  1311. Stream: TStream;
  1312. begin
  1313. Stream := TFileStream.Create(AFilename, fmOpenRead);
  1314. try
  1315. ReadXMLFragment(AParentNode, Stream, AFilename);
  1316. finally
  1317. Stream.Free;
  1318. end;
  1319. end;
  1320. procedure ReadDTDFile(var ADoc: TXMLDocument; var f: File);
  1321. var
  1322. Reader: TXMLReader;
  1323. buf: PChar;
  1324. BufSize: LongInt;
  1325. begin
  1326. ADoc := nil;
  1327. BufSize := FileSize(f) + 1;
  1328. if BufSize <= 1 then
  1329. exit;
  1330. GetMem(buf, BufSize);
  1331. try
  1332. BlockRead(f, buf^, BufSize - 1);
  1333. buf[BufSize - 1] := #0;
  1334. Reader := TXMLReader.Create;
  1335. try
  1336. Reader.ProcessDTD(buf, TFileRec(f).name);
  1337. ADoc := TXMLDocument(Reader.doc);
  1338. finally
  1339. Reader.Free;
  1340. end;
  1341. finally
  1342. FreeMem(buf);
  1343. end;
  1344. end;
  1345. procedure ReadDTDFile(var ADoc: TXMLDocument; var f: TStream; const AFilename: String);
  1346. var
  1347. Reader: TXMLReader;
  1348. buf: PChar;
  1349. begin
  1350. ADoc := nil;
  1351. if f.Size = 0 then
  1352. exit;
  1353. GetMem(buf, f.Size + 1);
  1354. try
  1355. f.Read(buf^, f.Size);
  1356. buf[f.Size] := #0;
  1357. Reader := TXMLReader.Create;
  1358. try
  1359. Reader.ProcessDTD(buf, AFilename);
  1360. ADoc := TXMLDocument(Reader.doc);
  1361. finally
  1362. Reader.Free;
  1363. end;
  1364. finally
  1365. FreeMem(buf);
  1366. end;
  1367. end;
  1368. procedure ReadDTDFile(var ADoc: TXMLDocument; var f: TStream);
  1369. begin
  1370. ReadDTDFile(ADoc, f, '<Stream>');
  1371. end;
  1372. procedure ReadDTDFile(var ADoc: TXMLDocument; const AFilename: String);
  1373. var
  1374. Stream: TStream;
  1375. begin
  1376. ADoc := nil;
  1377. Stream := TFileStream.Create(AFilename, fmOpenRead);
  1378. try
  1379. ReadDTDFile(ADoc, Stream, AFilename);
  1380. finally
  1381. Stream.Free;
  1382. end;
  1383. end;
  1384. end.
  1385. {
  1386. $Log: xmlread.pp,v $
  1387. Revision 1.17 2005/05/02 13:06:51 michael
  1388. + Patch from Vincent Snijders to fix reading of entities
  1389. Revision 1.16 2005/03/14 21:10:12 florian
  1390. * adapated for the new widestring manager
  1391. Revision 1.15 2005/02/14 17:13:18 peter
  1392. * truncate log
  1393. Revision 1.14 2005/02/01 20:23:39 florian
  1394. * adapted to new widestring manager
  1395. Revision 1.13 2005/01/22 20:54:51 michael
  1396. * Patch from Colin Western to correctly read CDATA
  1397. }