'The documents were not zipped correctly

I'm making a class to create a docx document, directly from code. An example is shown in the code below. Using this code, MS WORD opens the document, but libreoffice, openoffice show that the document is damaged.

However, if I rename the docx document to zip type, using Windows explorer, and unpack the document, then using the "Send to compressed (zipped) folder" option and change the document type to docx, all mentioned text editors open the document. Where am I wrong?

unit uWordX;

interface

uses
  System.Classes, Xml.xmldom, Xml.XMLIntf, Xml.XmlDoc;

    type
      TWordxClass = class
      private
        FOwner    : TComponent;
        procedure CreateXmlHeader(XmlDocument: TXmlDocument);
        function SaveXmlDocToStream(XmlDocument: TXmlDocument): TStream;
        function AddAttributes(RootAttribute: IXMLNode; NodeName: string; attrNames: Array of string; attrValues: array of string): IXMLNode;

    function CreateRelsRels: TStream;
    function CreateRelsDocumentXMLRels: TStream;
    function CreateContentTypes: TStream;

    function CreateSimpleDoc: TStream;
  public
    Constructor Create(AOwner: TComponent); virtual;

    procedure CreateFile(AFileName: string);
  end;

implementation

uses
  System.SysUtils, System.Zip;

{ TWordxClass }

function TWordxClass.AddAttributes(RootAttribute: IXMLNode; NodeName: string;
  attrNames, attrValues: array of string): IXMLNode;
begin
  Result  := RootAttribute.AddChild(NodeName);
  for var idx := Low(attrValues) to High(attrValues) do
    Result.Attributes[attrNames[idx]] := attrValues[idx];
end;

constructor TWordxClass.Create(AOwner: TComponent);
begin
  FOwner    := AOwner;
end;

function TWordxClass.CreateContentTypes: TStream;
begin
  var XmlDocument := TXmlDocument.Create(FOwner);
  try
    CreateXmlHeader(XmlDocument);
    // Root Node
    var Root := XmlDocument.addChild('Types',
      'http://schemas.openxmlformats.org/package/2006/content-types');
    var Def := AddAttributes(Root, 'Default', ['Extension', 'ContentType'],
                ['rels', 'application/vnd.openxmlformats-package.relationships+xml']);
    Def     := AddAttributes(Root, 'Default', ['Extension', 'ContentType'],
                ['xml', 'application/xml']);
    var Ovr := AddAttributes(Root, 'Override',
                ['PartName', 'ContentType'],
                ['/word/document.xml', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml']);

    Result := SaveXmlDocToStream(XmlDocument);
  finally
    XmlDocument.Free;
  end;
end;

procedure TWordxClass.CreateFile(AFileName: string);
begin
  var FZipFile := TZipFile.Create;
  try
    FZipFile.Open(AFileName, TZipMode.zmWrite);
    var CntType := CreateContentTypes();
    try

      FZipFile.Add(CntType, '[Content_Types].xml');
    finally
      CntType.Free;
    end;

    var RelsStream := CreateRelsRels();
    try

      FZipFile.Add(RelsStream, '_rels\.rels');
    finally
      RelsStream.Free;
    end;

    var RelsDocumentXMLRels := CreateRelsDocumentXMLRels();
    try
      FZipFile.Add(RelsDocumentXMLRels, 'word/_rels/document.xml.rels');
    finally
      RelsDocumentXMLRels.Free;
    end;

    var Document := CreateSimpleDoc();
    try
      FZipFile.Add(Document, 'word/document.xml');
    finally
      Document.Free;
    end;
    FZipFile.Close;
  finally
    FZipFile.Free;
  end;
end;

function TWordxClass.CreateRelsDocumentXMLRels: TStream;
begin
  var XmlDocument := TXmlDocument.Create(FOwner);
  try
    CreateXmlHeader(XmlDocument);
    // Root Node
    var Root := XmlDocument.addChild('Relationships',
      'http://schemas.openxmlformats.org/package/2006/relationships');
    Result := SaveXmlDocToStream(XmlDocument);
  finally
    XmlDocument.Free;
  end;
end;

function TWordxClass.CreateRelsRels: TStream;
begin
  var XmlDocument := TXmlDocument.Create(FOwner);
  try
    CreateXmlHeader(XmlDocument);
    // Root Node
    var Root := XmlDocument.addChild('Relationships',
      'http://schemas.openxmlformats.org/package/2006/relationships');
    // Relationship Definition
    var Rel := Root.addChild('Relationship');
    Rel.Attributes['Id'] := 'rId1';
    Rel.Attributes['Type'] :=
      'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument';
    Rel.Attributes['Target'] := 'word/document.xml';
    Result := SaveXmlDocToStream(XmlDocument);
  finally
    XmlDocument.Free;
  end;
end;

function TWordxClass.CreateSimpleDoc: TStream;
begin
  var XmlDocument := TXmlDocument.Create(FOwner);
  try
    CreateXmlHeader(XmlDocument);
    // Root Node
    var Doc := XmlDocument.AddChild('w:document');
    Doc.DeclareNamespace('wpc', 'http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas');
    Doc.DeclareNamespace('mc', 'http://schemas.openxmlformats.org/markup-compatibility/2006');
    Doc.DeclareNamespace('o', 'urn:schemas-microsoft-com:office:office');
    Doc.DeclareNamespace('r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
    Doc.DeclareNamespace('m', 'http://schemas.openxmlformats.org/officeDocument/2006/math');
    Doc.DeclareNamespace('v', 'urn:schemas-microsoft-com:vml');
    Doc.DeclareNamespace('wp14', 'http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing');
    Doc.DeclareNamespace('wp', 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing');
    Doc.DeclareNamespace('w10', 'urn:schemas-microsoft-com:office:word');
    Doc.DeclareNamespace('w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main');
    Doc.DeclareNamespace('w14', 'http://schemas.microsoft.com/office/word/2010/wordml');
    Doc.DeclareNamespace('wpg', 'http://schemas.microsoft.com/office/word/2010/wordprocessingGroup');
    Doc.DeclareNamespace('wpi', 'http://schemas.microsoft.com/office/word/2010/wordprocessingInk');
    Doc.DeclareNamespace('wne', 'http://schemas.microsoft.com/office/word/2006/wordml');
    Doc.DeclareNamespace('wps', 'http://schemas.microsoft.com/office/word/2010/wordprocessingShape');
    Doc.Attributes['mc:Ignorable']  := 'w14 wp14';

    var Body  := Doc.AddChild('w:body');
    var Paragraf  := AddAttributes(Body, 'w:p', ['w:rsidR', 'w:rsidRDefault'], ['005F670F', '005F79F5']);
    var Text  := Paragraf.AddChild('w:r').AddChild('w:t');
    Text.NodeValue    := 'Tekst';


    var bookmarkStart := AddAttributes(Paragraf, 'w:bookmarkStart', ['w:id', 'w:name'], ['0', '_GoBack']);
    var bookmarkEnd := AddAttributes(Paragraf, 'w:bookmarkEnd', ['w:id'], ['0']);

    var SectPtr := AddAttributes(Body, 'w:sectPr', ['w:rsidR'], ['005F670F']);
    var PageSize  := AddAttributes(SectPtr, 'w:pgSz', ['w:w', 'w:h'], ['12240', '15840']);
    var PageMargine := AddAttributes(SectPtr, 'w:pgMar', ['w:top', 'w:right', 'w:bottom', 'w:left', 'w:header', 'w:footer', 'w:gutter'],
                                                         ['1440', '1440', '1440', '1440', '720', '720', '0']);
    var Cols    := AddAttributes(SectPtr, 'w:cols', ['w:space'], ['720']);
    var DocGrid := AddAttributes(SectPtr, 'w:docGrid', ['w:linePitch'], ['360']);

    Result := SaveXmlDocToStream(XmlDocument);
  finally
    XmlDocument.Free;
  end;
end;

procedure TWordxClass.CreateXmlHeader(XmlDocument: TXmlDocument);
begin
  XmlDocument.Options := [doNodeAutoIndent];
  XmlDocument.Active := True;
  XmlDocument.Encoding := 'UTF-8';
  XmlDocument.Version := '1.0';
  XmlDocument.StandAlone := 'yes';
end;

function TWordxClass.SaveXmlDocToStream(XmlDocument: TXmlDocument): TStream;
begin
  Result  := TMemoryStream.Create;
  XmlDocument.SaveToStream(Result);
  Result.Seek(0, soBeginning);
end;

end.

Documents are uploaded on address: https://drive.google.com/drive/u/0/folders/1GPfLjMYPwaI-E5ZEEwxlORy_b_PZI1cJ

Document TestSimple.docx was generated by the code, and [Content_Types].docx is rezipped document. MSWord and Mac's TextEdit open TestSimple.docx, and applications OpenOffice and LibreOffice can't open it. After unzipping the original document, recompressing and renaming to docx extension using Windows Explorer, all mentioned applications open the new document.

Thanks in advance,

Bojan



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source