unit XMLWriter; {$MODE OBJFPC} {$M+} interface uses classes, contnrs, DOM, type_fixes; type TWriter = class private fBOwnsStream : Boolean; fStream : TStream; fBIndent : Boolean; fIndentation : Integer; public destructor Destroy(); override; published constructor Create(aStream : TStream; aBOwnsStream : Boolean; aBIndent : Boolean = False); // TODO encoding, BFormatted etc. procedure Write(aNode : TNode); procedure WriteAttributes(aAttributes : TNamedNodeMap); procedure WriteDocument(aDocument : TDocument); protected procedure Write(aString : TDOMString; const aReserved : String = ''); inline; procedure WriteNewLine(); inline; end; implementation uses sysutils; { TWriter } constructor TWriter.Create(aStream : TStream; aBOwnsStream : Boolean; aBIndent : Boolean = False); begin fBOwnsStream := aBOwnsStream; fStream := aStream; fBIndent := aBIndent; end; destructor TWriter.Destroy(); begin if fBOwnsStream then FreeAndNil(fStream); inherited Destroy(); end; procedure TWriter.WriteAttributes(aAttributes : TNamedNodeMap); var vIndex : TCardinal; begin if aAttributes.length > 0 then for vIndex := 0 to aAttributes.length - 1 do begin with aAttributes.item(vIndex) do begin Self.Write(nodeName); Self.Write('="'); // TODO handle value-less items. // FIXME escape... Self.Write(nodeValue, '"'); Self.Write('"'); end; if vIndex < aAttributes.length - 1 then Self.Write(' '); end; end; procedure TWriter.WriteNewLine(); inline; var vIndex : Integer; begin if fBIndent then Self.Write(#10); for vIndex := 1 to fIndentation do begin Self.Write(#9); end; end; procedure TWriter.Write(aNode : TNode); var vChildNodes : TNodeList; vChildNode : TNode; vChildIndex : TCardinal; begin if aNode is TElement then begin Self.Write('<'); Self.Write(aNode.nodeName); if aNode.Attributes.length > 0 then begin Self.Write(' '); Self.WriteAttributes(aNode.Attributes); end; // TODO child-less elements for HTML. vChildNodes := aNode.ChildNodes; if not Assigned(vChildNodes) or (vChildNodes.length = 0) then Self.Write('/>') else begin Inc(fIndentation); WriteNewLine(); Self.Write('>'); for vChildIndex := 0 to vChildNodes.length - 1 do begin Self.Write(vChildNodes.item(vChildIndex)); end; Self.Write(''); end; end else if aNode is TText then begin // FIXME escape. Self.Write(aNode.nodeValue); end else Writeln('unknown', aNode.ClassName); end; procedure TWriter.WriteDocument(aDocument : TDocument); begin Self.Write(aDocument.DocumentElement); end; procedure TWriter.Write(aString : TDOMString; const aReserved : String = ''); inline; begin // FIXME escape. fStream.WriteBuffer(aString[1], Length(aString)); end; end.