nissl-lab / npoi

a .NET library that can read/write Office formats without Microsoft Office installed. No COM+, no interop.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Support DOCM file type

TomLingWu opened this issue · comments

NPOI Version Used

Version 2.6.2

File Type

  • XLSX
  • XLS
  • DOCX
  • XLSM
  • OTHER

Use Case

We use the XWPFDocument , and want to generate *.docm document format with some VBA macros enabled, it also uses hyperlinks and table of contents etc.
The current official supported file types only include DOCX and XLSM, but without DOCM. Could we add the support for DOCM file type, please?

Description

One of the uses of the VBA macro is to avoid the EnforceUpdateFields() to ask two questions when opening the docx file, and the user directly saves it doesn't work since Word considers the updated fields are not a real change. So the workaround using a macro is like this:

Sub AutoOpen()
        ActiveDocument.TablesOfContents(1).Update
        ActiveDocument.TablesOfContents(1).UpdatePageNumbers
End Sub

Notes:

My test code with a hyperlink:
MS Word cannot open the saved hyperlink-docm.docm.

using NPOI.XWPF.UserModel;

class Program
{
    static void Main(string[] args)
    {
        try
        {
            using var doc = new XWPFDocument();

            var paragraph = doc.CreateParagraph();
            var run = paragraph.CreateRun();
            run.SetText("This is a text paragraph having ");

            AddHyperlinkToParagraph(paragraph, @"https://www.google.com", "a link to Google");

            run = paragraph.CreateRun();
            run.SetText(" in it.");

            using var out1 = new FileStream(@"hyperlink-docm.docm", FileMode.Create);
            doc.Write(out1);

            using var out2 = new FileStream(@"hyperlink-docx.docx", FileMode.Create);
            doc.Write(out2);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

    static XWPFHyperlinkRun CreateHyperlinkRun(XWPFParagraph paragraph, string url)
    {
        var rId = paragraph.Document.GetPackagePart().AddExternalRelationship(
            url,
            XWPFRelation.HYPERLINK.Relation
        ).Id;

        return paragraph.CreateHyperlinkRun(rId);
    }

    static void AddHyperlinkToParagraph(XWPFParagraph paragraph, string url, string displayText)
    {
        var hyperlinkRun = CreateHyperlinkRun(paragraph, url);

        // Set the text of the run to the display text
        hyperlinkRun.SetText(displayText);
        hyperlinkRun.Underline = UnderlinePatterns.Single;
        hyperlinkRun.SetColor("0000FF");
    }
}

It seems there is NO option to specify the 'ContentType' when to create the instance of XWPFDocument.
And it would be nice to inject a parameter and let use to specify document type in the constructor.

/**
* Create a new WordProcessingML package and Setup the default minimal content
*/
protected static OPCPackage NewPackage()
{
try {
OPCPackage pkg = OPCPackage.Create(new MemoryStream());
// Main part
PackagePartName corePartName = PackagingUriHelper.CreatePartName(XWPFRelation.DOCUMENT.DefaultFileName);
// Create main part relationship
pkg.AddRelationship(corePartName, TargetMode.Internal, PackageRelationshipTypes.CORE_DOCUMENT);
// Create main document part
pkg.CreatePart(corePartName, XWPFRelation.DOCUMENT.ContentType);

          pkg.GetPackageProperties().SetCreatorProperty(DOCUMENT_CREATOR);
          return pkg;
       }
       catch (Exception e)
       {
           throw new POIXMLException(e);
       }
  }

and using the 'MACRO_DOCUMENT'

public class XWPFRelation : POIXMLRelation
{

    /**
     * A map to lookup POIXMLRelation by its relation type
     */
    private static Dictionary<String, XWPFRelation> _table = new Dictionary<String, XWPFRelation>();


    public static XWPFRelation DOCUMENT = new XWPFRelation(
            "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml",
        "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
        "/word/document.xml",
            null
    );
    public static XWPFRelation TEMPLATE = new XWPFRelation(
          "application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml",
      "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
      "/word/document.xml",
          null
    );
    public static XWPFRelation MACRO_DOCUMENT = new XWPFRelation(
            "application/vnd.ms-word.document.macroEnabled.main+xml",
        "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
        "/word/document.xml",
            null
    );