htmwrite.pp 8.5 KB

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