htmwrite.pp 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. {
  2. $Id$
  3. This file is part of the Free Component Library
  4. HTML writing routines
  5. Copyright (c) 2000-2002 by
  6. Areca Systems GmbH / Sebastian Guenther, [email protected]
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. unit HTMWrite;
  14. {$MODE objfpc}
  15. {$H+}
  16. interface
  17. uses Classes, DOM;
  18. procedure WriteHTMLFile(doc: TXMLDocument; const AFileName: String);
  19. procedure WriteHTMLFile(doc: TXMLDocument; var AFile: Text);
  20. procedure WriteHTMLFile(doc: TXMLDocument; AStream: TStream);
  21. procedure WriteHTML(Element: TDOMElement; const AFileName: String);
  22. procedure WriteHTML(Element: TDOMElement; var AFile: Text);
  23. procedure WriteHTML(Element: TDOMElement; AStream: TStream);
  24. // ===================================================================
  25. implementation
  26. uses SysUtils, HTMLDefs;
  27. // -------------------------------------------------------------------
  28. // Writers for the different node types
  29. // -------------------------------------------------------------------
  30. procedure WriteElement(node: TDOMNode); forward;
  31. procedure WriteAttribute(node: TDOMNode); forward;
  32. procedure WriteText(node: TDOMNode); forward;
  33. procedure WriteCDATA(node: TDOMNode); forward;
  34. procedure WriteEntityRef(node: TDOMNode); forward;
  35. procedure WriteEntity(node: TDOMNode); forward;
  36. procedure WritePI(node: TDOMNode); forward;
  37. procedure WriteComment(node: TDOMNode); forward;
  38. procedure WriteDocument(node: TDOMNode); forward;
  39. procedure WriteDocumentType(node: TDOMNode); forward;
  40. procedure WriteDocumentFragment(node: TDOMNode); forward;
  41. procedure WriteNotation(node: TDOMNode); forward;
  42. type
  43. TWriteNodeProc = procedure(node: TDOMNode);
  44. const
  45. WriteProcs: array[ELEMENT_NODE..NOTATION_NODE] of TWriteNodeProc =
  46. (@WriteElement, @WriteAttribute, @WriteText, @WriteCDATA, @WriteEntityRef,
  47. @WriteEntity, @WritePI, @WriteComment, @WriteDocument, @WriteDocumentType,
  48. @WriteDocumentFragment, @WriteNotation);
  49. procedure WriteNode(node: TDOMNode);
  50. begin
  51. WriteProcs[node.NodeType](node);
  52. end;
  53. // -------------------------------------------------------------------
  54. // Text file and TStream support
  55. // -------------------------------------------------------------------
  56. type
  57. TOutputProc = procedure(s: String);
  58. var
  59. f: ^Text;
  60. stream: TStream;
  61. wrt, wrtln: TOutputProc;
  62. InsideTextNode: Boolean;
  63. procedure Text_Write(s: String);
  64. begin
  65. Write(f^, s);
  66. end;
  67. procedure Text_WriteLn(s: String);
  68. begin
  69. WriteLn(f^, s);
  70. end;
  71. procedure Stream_Write(s: String);
  72. begin
  73. if Length(s) > 0 then
  74. stream.Write(s[1], Length(s));
  75. end;
  76. procedure Stream_WriteLn(s: String);
  77. begin
  78. if Length(s) > 0 then
  79. stream.Write(s[1], Length(s));
  80. stream.WriteByte(10);
  81. end;
  82. // -------------------------------------------------------------------
  83. // String conversion
  84. // -------------------------------------------------------------------
  85. type
  86. TCharacters = set of Char;
  87. TSpecialCharCallback = procedure(c: Char);
  88. const
  89. AttrSpecialChars = ['"', '&'];
  90. TextSpecialChars = ['<', '>', '&'];
  91. procedure ConvWrite(const s: String; const SpecialChars: TCharacters;
  92. const SpecialCharCallback: TSpecialCharCallback);
  93. var
  94. StartPos, EndPos: Integer;
  95. begin
  96. StartPos := 1;
  97. EndPos := 1;
  98. while EndPos <= Length(s) do
  99. begin
  100. if s[EndPos] in SpecialChars then
  101. begin
  102. wrt(Copy(s, StartPos, EndPos - StartPos));
  103. SpecialCharCallback(s[EndPos]);
  104. StartPos := EndPos + 1;
  105. end;
  106. Inc(EndPos);
  107. end;
  108. if EndPos > StartPos then
  109. wrt(Copy(s, StartPos, EndPos - StartPos));
  110. end;
  111. procedure AttrSpecialCharCallback(c: Char);
  112. begin
  113. if c = '"' then
  114. wrt('&quot;')
  115. else if c = '&' then
  116. wrt('&amp;')
  117. else
  118. wrt(c);
  119. end;
  120. procedure TextnodeSpecialCharCallback(c: Char);
  121. begin
  122. if c = '<' then
  123. wrt('&lt;')
  124. else if c = '>' then
  125. wrt('&gt;')
  126. else if c = '&' then
  127. wrt('&amp;')
  128. else
  129. wrt(c);
  130. end;
  131. function IsTextNode(Node: TDOMNode): Boolean;
  132. begin
  133. Result := Node.NodeType in [TEXT_NODE, ENTITY_REFERENCE_NODE];
  134. end;
  135. // -------------------------------------------------------------------
  136. // Node writers implementations
  137. // -------------------------------------------------------------------
  138. procedure WriteElement(node: TDOMNode);
  139. var
  140. i: Integer;
  141. attr, child: TDOMNode;
  142. s: String;
  143. SavedInsideTextNode: Boolean;
  144. ElFlags: THTMLElementFlags;
  145. begin
  146. s := LowerCase(node.NodeName);
  147. ElFlags := [efSubelementContent, efPCDATAContent]; // default flags
  148. for i := Low(HTMLElProps) to High(HTMLElProps) do
  149. if HTMLElProps[i].Name = s then
  150. begin
  151. ElFlags := HTMLElProps[i].Flags;
  152. break;
  153. end;
  154. wrt('<' + node.NodeName);
  155. for i := 0 to node.Attributes.Length - 1 do
  156. begin
  157. attr := node.Attributes.Item[i];
  158. wrt(' ' + attr.NodeName + '=');
  159. s := attr.NodeValue;
  160. // !!!: Replace special characters in "s" such as '&', '<', '>'
  161. wrt('"');
  162. ConvWrite(s, AttrSpecialChars, @AttrSpecialCharCallback);
  163. wrt('"');
  164. end;
  165. wrt('>');
  166. if (not InsideTextNode) and not (efPCDATAContent in ElFlags) then
  167. wrtln('');
  168. Child := node.FirstChild;
  169. if Assigned(Child) then
  170. begin
  171. SavedInsideTextNode := InsideTextNode;
  172. repeat
  173. InsideTextNode := efPCDATAContent in ElFlags;
  174. WriteNode(Child);
  175. Child := Child.NextSibling;
  176. until not Assigned(child);
  177. InsideTextNode := SavedInsideTextNode;
  178. end;
  179. if ElFlags * [efSubelementContent, efPCDATAContent] <> [] then
  180. begin
  181. wrt('</' + node.NodeName + '>');
  182. if not InsideTextNode then
  183. wrtln('');
  184. end;
  185. end;
  186. procedure WriteAttribute(node: TDOMNode);
  187. begin
  188. WriteLn('WriteAttribute');
  189. end;
  190. procedure WriteText(node: TDOMNode);
  191. begin
  192. ConvWrite(node.NodeValue, TextSpecialChars, @TextnodeSpecialCharCallback);
  193. end;
  194. procedure WriteCDATA(node: TDOMNode);
  195. begin
  196. if InsideTextNode then
  197. wrt('<![CDATA[' + node.NodeValue + ']]>')
  198. else
  199. wrtln('<![CDATA[' + node.NodeValue + ']]>')
  200. end;
  201. procedure WriteEntityRef(node: TDOMNode);
  202. begin
  203. wrt('&' + node.NodeName + ';');
  204. end;
  205. procedure WriteEntity(node: TDOMNode);
  206. begin
  207. WriteLn('WriteEntity');
  208. end;
  209. procedure WritePI(node: TDOMNode);
  210. var
  211. s: String;
  212. begin
  213. s := '<!' + TDOMProcessingInstruction(node).Target + ' ' +
  214. TDOMProcessingInstruction(node).Data + '>';
  215. if InsideTextNode then
  216. wrt(s)
  217. else
  218. wrtln( s);
  219. end;
  220. procedure WriteComment(node: TDOMNode);
  221. begin
  222. if InsideTextNode then
  223. wrt('<!--' + node.NodeValue + '-->')
  224. else
  225. wrtln('<!--' + node.NodeValue + '-->')
  226. end;
  227. procedure WriteDocument(node: TDOMNode);
  228. begin
  229. WriteLn('WriteDocument');
  230. end;
  231. procedure WriteDocumentType(node: TDOMNode);
  232. begin
  233. WriteLn('WriteDocumentType');
  234. end;
  235. procedure WriteDocumentFragment(node: TDOMNode);
  236. begin
  237. WriteLn('WriteDocumentFragment');
  238. end;
  239. procedure WriteNotation(node: TDOMNode);
  240. begin
  241. WriteLn('WriteNotation');
  242. end;
  243. procedure InitWriter;
  244. begin
  245. InsideTextNode := False;
  246. end;
  247. procedure RootWriter(doc: TXMLDocument);
  248. var
  249. Child: TDOMNode;
  250. begin
  251. InitWriter;
  252. child := doc.FirstChild;
  253. while Assigned(Child) do
  254. begin
  255. WriteNode(Child);
  256. Child := Child.NextSibling;
  257. end;
  258. end;
  259. // -------------------------------------------------------------------
  260. // Interface implementation
  261. // -------------------------------------------------------------------
  262. procedure WriteHTMLFile(doc: TXMLDocument; const AFileName: String);
  263. begin
  264. Stream := TFileStream.Create(AFileName, fmCreate);
  265. wrt := @Stream_Write;
  266. wrtln := @Stream_WriteLn;
  267. RootWriter(doc);
  268. Stream.Free;
  269. end;
  270. procedure WriteHTMLFile(doc: TXMLDocument; var AFile: Text);
  271. begin
  272. f := @AFile;
  273. wrt := @Text_Write;
  274. wrtln := @Text_WriteLn;
  275. RootWriter(doc);
  276. end;
  277. procedure WriteHTMLFile(doc: TXMLDocument; AStream: TStream);
  278. begin
  279. Stream := AStream;
  280. wrt := @Stream_Write;
  281. wrtln := @Stream_WriteLn;
  282. RootWriter(doc);
  283. end;
  284. procedure WriteHTML(Element: TDOMElement; const AFileName: String);
  285. begin
  286. Stream := TFileStream.Create(AFileName, fmCreate);
  287. wrt := @Stream_Write;
  288. wrtln := @Stream_WriteLn;
  289. InitWriter;
  290. WriteNode(Element);
  291. Stream.Free;
  292. end;
  293. procedure WriteHTML(Element: TDOMElement; var AFile: Text);
  294. begin
  295. f := @AFile;
  296. wrt := @Text_Write;
  297. wrtln := @Text_WriteLn;
  298. InitWriter;
  299. WriteNode(Element);
  300. end;
  301. procedure WriteHTML(Element: TDOMElement; AStream: TStream);
  302. begin
  303. stream := AStream;
  304. wrt := @Stream_Write;
  305. wrtln := @Stream_WriteLn;
  306. InitWriter;
  307. WriteNode(Element);
  308. end;
  309. end.
  310. {
  311. $Log$
  312. Revision 1.5 2002-11-29 18:04:25 sg
  313. * Improved HTML writing, now uses the HTML definition unit
  314. (moved from FPDoc into FCL)
  315. Revision 1.4 2002/09/07 15:15:29 peter
  316. * old logs removed and tabs fixed
  317. }