mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-07-28 01:46:12 +02:00

element is now handled as indicator to stop the insertion of automatic linefeeds. Until now this was only the case with text nodes.)
387 lines
8.6 KiB
ObjectPascal
387 lines
8.6 KiB
ObjectPascal
{
|
|
$Id$
|
|
This file is part of the Free Component Library
|
|
|
|
HTML writing routines
|
|
Copyright (c) 2000 by
|
|
Areca Systems GmbH / Sebastian Guenther, sg@freepascal.org
|
|
|
|
See the file COPYING.FPC, included in this distribution,
|
|
for details about the copyright.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
**********************************************************************}
|
|
|
|
|
|
unit HTMWrite;
|
|
|
|
{$MODE objfpc}
|
|
{$H+}
|
|
|
|
interface
|
|
|
|
uses Classes, DOM;
|
|
|
|
procedure WriteHTMLFile(doc: TXMLDocument; const AFileName: String);
|
|
procedure WriteHTMLFile(doc: TXMLDocument; var AFile: Text);
|
|
procedure WriteHTMLFile(doc: TXMLDocument; var AStream: TStream);
|
|
|
|
procedure WriteHTML(Element: TDOMElement; const AFileName: String);
|
|
procedure WriteHTML(Element: TDOMElement; var AFile: Text);
|
|
procedure WriteHTML(Element: TDOMElement; var AStream: TStream);
|
|
|
|
|
|
// ===================================================================
|
|
|
|
implementation
|
|
|
|
uses SysUtils;
|
|
|
|
// -------------------------------------------------------------------
|
|
// Writers for the different node types
|
|
// -------------------------------------------------------------------
|
|
|
|
procedure WriteElement(node: TDOMNode); forward;
|
|
procedure WriteAttribute(node: TDOMNode); forward;
|
|
procedure WriteText(node: TDOMNode); forward;
|
|
procedure WriteCDATA(node: TDOMNode); forward;
|
|
procedure WriteEntityRef(node: TDOMNode); forward;
|
|
procedure WriteEntity(node: TDOMNode); forward;
|
|
procedure WritePI(node: TDOMNode); forward;
|
|
procedure WriteComment(node: TDOMNode); forward;
|
|
procedure WriteDocument(node: TDOMNode); forward;
|
|
procedure WriteDocumentType(node: TDOMNode); forward;
|
|
procedure WriteDocumentFragment(node: TDOMNode); forward;
|
|
procedure WriteNotation(node: TDOMNode); forward;
|
|
|
|
|
|
type
|
|
TWriteNodeProc = procedure(node: TDOMNode);
|
|
|
|
const
|
|
WriteProcs: array[ELEMENT_NODE..NOTATION_NODE] of TWriteNodeProc =
|
|
(WriteElement, WriteAttribute, WriteText, WriteCDATA, WriteEntityRef,
|
|
WriteEntity, WritePI, WriteComment, WriteDocument, WriteDocumentType,
|
|
WriteDocumentFragment, WriteNotation);
|
|
|
|
procedure WriteNode(node: TDOMNode);
|
|
begin
|
|
WriteProcs[node.NodeType](node);
|
|
end;
|
|
|
|
|
|
// -------------------------------------------------------------------
|
|
// Text file and TStream support
|
|
// -------------------------------------------------------------------
|
|
|
|
type
|
|
TOutputProc = procedure(s: String);
|
|
|
|
var
|
|
f: ^Text;
|
|
stream: TStream;
|
|
wrt, wrtln: TOutputProc;
|
|
InsideTextNode: Boolean;
|
|
|
|
|
|
procedure Text_Write(s: String);
|
|
begin
|
|
Write(f^, s);
|
|
end;
|
|
|
|
procedure Text_WriteLn(s: String);
|
|
begin
|
|
WriteLn(f^, s);
|
|
end;
|
|
|
|
procedure Stream_Write(s: String);
|
|
begin
|
|
if Length(s) > 0 then
|
|
stream.Write(s[1], Length(s));
|
|
end;
|
|
|
|
procedure Stream_WriteLn(s: String);
|
|
begin
|
|
if Length(s) > 0 then
|
|
stream.Write(s[1], Length(s));
|
|
stream.WriteByte(10);
|
|
end;
|
|
|
|
|
|
// -------------------------------------------------------------------
|
|
// String conversion
|
|
// -------------------------------------------------------------------
|
|
|
|
type
|
|
TCharacters = set of Char;
|
|
TSpecialCharCallback = procedure(c: Char);
|
|
|
|
const
|
|
AttrSpecialChars = ['"', '&'];
|
|
TextSpecialChars = ['<', '>', '&'];
|
|
|
|
|
|
procedure ConvWrite(const s: String; const SpecialChars: TCharacters;
|
|
const SpecialCharCallback: TSpecialCharCallback);
|
|
var
|
|
StartPos, EndPos: Integer;
|
|
begin
|
|
StartPos := 1;
|
|
EndPos := 1;
|
|
while EndPos <= Length(s) do
|
|
begin
|
|
if s[EndPos] in SpecialChars then
|
|
begin
|
|
wrt(Copy(s, StartPos, EndPos - StartPos));
|
|
SpecialCharCallback(s[EndPos]);
|
|
StartPos := EndPos + 1;
|
|
end;
|
|
Inc(EndPos);
|
|
end;
|
|
if EndPos > StartPos then
|
|
wrt(Copy(s, StartPos, EndPos - StartPos));
|
|
end;
|
|
|
|
procedure AttrSpecialCharCallback(c: Char);
|
|
begin
|
|
if c = '"' then
|
|
wrt('"')
|
|
else if c = '&' then
|
|
wrt('&')
|
|
else
|
|
wrt(c);
|
|
end;
|
|
|
|
procedure TextnodeSpecialCharCallback(c: Char);
|
|
begin
|
|
if c = '<' then
|
|
wrt('<')
|
|
else if c = '>' then
|
|
wrt('>')
|
|
else if c = '&' then
|
|
wrt('&')
|
|
else
|
|
wrt(c);
|
|
end;
|
|
|
|
function IsTextNode(Node: TDOMNode): Boolean;
|
|
begin
|
|
Result := Node.NodeType in [TEXT_NODE, ENTITY_REFERENCE_NODE];
|
|
end;
|
|
|
|
|
|
// -------------------------------------------------------------------
|
|
// Node writers implementations
|
|
// -------------------------------------------------------------------
|
|
|
|
procedure WriteElement(node: TDOMNode);
|
|
var
|
|
i: Integer;
|
|
attr, child: TDOMNode;
|
|
SavedInsideTextNode: Boolean;
|
|
s: String;
|
|
begin
|
|
wrt('<' + node.NodeName);
|
|
for i := 0 to node.Attributes.Length - 1 do
|
|
begin
|
|
attr := node.Attributes.Item[i];
|
|
wrt(' ' + attr.NodeName + '=');
|
|
s := attr.NodeValue;
|
|
// !!!: Replace special characters in "s" such as '&', '<', '>'
|
|
wrt('"');
|
|
ConvWrite(s, AttrSpecialChars, @AttrSpecialCharCallback);
|
|
wrt('"');
|
|
end;
|
|
Child := node.FirstChild;
|
|
if Child = nil then
|
|
if InsideTextNode then
|
|
wrt(' />')
|
|
else
|
|
wrtln(' />')
|
|
else
|
|
begin
|
|
SavedInsideTextNode := InsideTextNode;
|
|
if InsideTextNode or IsTextNode(Child) then
|
|
wrt('>')
|
|
else
|
|
wrtln('>');
|
|
repeat
|
|
if IsTextNode(Child) then
|
|
InsideTextNode := True;
|
|
WriteNode(Child);
|
|
Child := Child.NextSibling;
|
|
until child = nil;
|
|
InsideTextNode := SavedInsideTextNode;
|
|
s := '</' + node.NodeName + '>';
|
|
if InsideTextNode then
|
|
wrt(s)
|
|
else
|
|
wrtln(s);
|
|
end;
|
|
end;
|
|
|
|
procedure WriteAttribute(node: TDOMNode);
|
|
begin
|
|
WriteLn('WriteAttribute');
|
|
end;
|
|
|
|
procedure WriteText(node: TDOMNode);
|
|
begin
|
|
ConvWrite(node.NodeValue, TextSpecialChars, @TextnodeSpecialCharCallback);
|
|
end;
|
|
|
|
procedure WriteCDATA(node: TDOMNode);
|
|
begin
|
|
if InsideTextNode then
|
|
wrt('<![CDATA[' + node.NodeValue + ']]>')
|
|
else
|
|
wrtln('<![CDATA[' + node.NodeValue + ']]>')
|
|
end;
|
|
|
|
procedure WriteEntityRef(node: TDOMNode);
|
|
begin
|
|
wrt('&' + node.NodeName + ';');
|
|
end;
|
|
|
|
procedure WriteEntity(node: TDOMNode);
|
|
begin
|
|
WriteLn('WriteEntity');
|
|
end;
|
|
|
|
procedure WritePI(node: TDOMNode);
|
|
var
|
|
s: String;
|
|
begin
|
|
s := '<!' + TDOMProcessingInstruction(node).Target + ' ' +
|
|
TDOMProcessingInstruction(node).Data + '>';
|
|
if InsideTextNode then
|
|
wrt(s)
|
|
else
|
|
wrtln( s);
|
|
end;
|
|
|
|
procedure WriteComment(node: TDOMNode);
|
|
begin
|
|
if InsideTextNode then
|
|
wrt('<!--' + node.NodeValue + '-->')
|
|
else
|
|
wrtln('<!--' + node.NodeValue + '-->')
|
|
end;
|
|
|
|
procedure WriteDocument(node: TDOMNode);
|
|
begin
|
|
WriteLn('WriteDocument');
|
|
end;
|
|
|
|
procedure WriteDocumentType(node: TDOMNode);
|
|
begin
|
|
WriteLn('WriteDocumentType');
|
|
end;
|
|
|
|
procedure WriteDocumentFragment(node: TDOMNode);
|
|
begin
|
|
WriteLn('WriteDocumentFragment');
|
|
end;
|
|
|
|
procedure WriteNotation(node: TDOMNode);
|
|
begin
|
|
WriteLn('WriteNotation');
|
|
end;
|
|
|
|
|
|
procedure InitWriter;
|
|
begin
|
|
InsideTextNode := False;
|
|
end;
|
|
|
|
procedure RootWriter(doc: TXMLDocument);
|
|
var
|
|
Child: TDOMNode;
|
|
begin
|
|
InitWriter;
|
|
child := doc.FirstChild;
|
|
while Assigned(Child) do
|
|
begin
|
|
WriteNode(Child);
|
|
Child := Child.NextSibling;
|
|
end;
|
|
end;
|
|
|
|
|
|
// -------------------------------------------------------------------
|
|
// Interface implementation
|
|
// -------------------------------------------------------------------
|
|
|
|
procedure WriteHTMLFile(doc: TXMLDocument; const AFileName: String);
|
|
begin
|
|
Stream := TFileStream.Create(AFileName, fmCreate);
|
|
wrt := @Stream_Write;
|
|
wrtln := @Stream_WriteLn;
|
|
RootWriter(doc);
|
|
Stream.Free;
|
|
end;
|
|
|
|
procedure WriteHTMLFile(doc: TXMLDocument; var AFile: Text);
|
|
begin
|
|
f := @AFile;
|
|
wrt := @Text_Write;
|
|
wrtln := @Text_WriteLn;
|
|
RootWriter(doc);
|
|
end;
|
|
|
|
procedure WriteHTMLFile(doc: TXMLDocument; var AStream: TStream);
|
|
begin
|
|
Stream := AStream;
|
|
wrt := @Stream_Write;
|
|
wrtln := @Stream_WriteLn;
|
|
RootWriter(doc);
|
|
end;
|
|
|
|
|
|
procedure WriteHTML(Element: TDOMElement; const AFileName: String);
|
|
begin
|
|
Stream := TFileStream.Create(AFileName, fmCreate);
|
|
wrt := @Stream_Write;
|
|
wrtln := @Stream_WriteLn;
|
|
InitWriter;
|
|
WriteNode(Element);
|
|
Stream.Free;
|
|
end;
|
|
|
|
procedure WriteHTML(Element: TDOMElement; var AFile: Text);
|
|
begin
|
|
f := @AFile;
|
|
wrt := @Text_Write;
|
|
wrtln := @Text_WriteLn;
|
|
InitWriter;
|
|
WriteNode(Element);
|
|
end;
|
|
|
|
procedure WriteHTML(Element: TDOMElement; var AStream: TStream);
|
|
begin
|
|
stream := AStream;
|
|
wrt := @Stream_Write;
|
|
wrtln := @Stream_WriteLn;
|
|
InitWriter;
|
|
WriteNode(Element);
|
|
end;
|
|
|
|
|
|
end.
|
|
|
|
|
|
{
|
|
$Log$
|
|
Revision 1.2 2000-10-15 15:31:26 sg
|
|
* Improved whitespace handling (entity references as first child of an
|
|
element is now handled as indicator to stop the insertion of automatic
|
|
linefeeds. Until now this was only the case with text nodes.)
|
|
|
|
Revision 1.1 2000/10/03 20:33:22 sg
|
|
* Added new Units "htmwrite" and "xhtml"
|
|
|
|
}
|