2
0

htmwrite.pp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  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. J : THTMLElementTag;
  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 j := Low(THTMLElementTag) to High(THTMLElementTag) do
  149. if HTMLElementProps[J].Name = s then
  150. begin
  151. ElFlags := HTMLElementProps[j].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.