动态创建的 Word 文档中缺少打开的 XML 部分

Posted

技术标签:

【中文标题】动态创建的 Word 文档中缺少打开的 XML 部分【英文标题】:Open XML parts are missing in dynamically created Word document 【发布时间】:2019-12-02 17:51:39 【问题描述】:

我正在使用 Open XML SDK 在 C# 中创建 WordprocessingDocuments,然后将它们转换为 pdf。最初,我使用 Interop 将文档保存为 PDF 格式,但现在这不是一个选项。我发现 LibreOffice 可以转换从 cmd 调用 soffice.exe 的文档,并且我对普通文档有很好的效果。然而,当我用我的动态文档测试 LibreOffice 转换器时,转换器崩溃了。

我复制了其中一个文档并用 LibreOffice Writer 打开它,它的结构错误,然后我用 Microsoft Word 打开同一个文档,它的结构很好。最后,我用 Microsoft Word 保存它,并将两个文档都打开为 ZIP 文件,如下所示:

这个不错:

这是一个坏的:

我注意到,当我将文档保存在 Microsoft Word 中时,会出现这些 Open XML 部分(我在此问题的早期版本中将其称为“文件”)。当我在 LibreOffice 中打开之前使用 Microsoft Word 保存的文档时,该文档又正常了。

那么,有没有办法在不打开 Microsoft Word 的情况下生成这些 Open XML 部分(在 Word 文档中)?

我使用以下代码(检查它是否正在创建所有文件):

        using (MemoryStream mem = new MemoryStream())
        
            // Create Document
            using (WordprocessingDocument wordDocument =
                WordprocessingDocument.Create(mem, WordprocessingDocumentType.Document, true))
            
                // Add a main document part. 
                MainDocumentPart mainPart = wordDocument.AddMainDocumentPart();

                // Create the document structure and add some text.
                mainPart.Document = new Document();
                Body docBody = new Body();

                // Add your docx content here
                CreateParagraph(docBody);
                CreateStyledParagraph(docBody);
                CreateTable(docBody);
                CreateList(docBody);

                Paragraph pImg = new Paragraph();
                ImagePart imagePart = mainPart.AddImagePart(ImagePartType.Jpeg);
                string imgPath = "https://cdn.pixabay.com/photo/2019/11/15/05/23/dog-4627679_960_720.png";
                HttpWebRequest req = (HttpWebRequest)WebRequest.Create(imgPath);
                req.UseDefaultCredentials = true;
                req.PreAuthenticate = true;
                req.Credentials = CredentialCache.DefaultCredentials;
                HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
                imagePart.FeedData(resp.GetResponseStream());

                // 1500000 and 1092000 are img width and height
                Run rImg = new Run(DrawingManager(mainPart.GetIdOfPart(imagePart), "PictureName", 1500000, 1092000, string.Empty));
                pImg.Append(rImg);
                docBody.Append(pImg);

                Paragraph pLink = new Paragraph();
                // For the mainpart see above
                pLink.Append(HyperLinkManager("http://YourLink", "My awesome link", mainPart));
                docBody.Append(pLink);

                mainPart.Document.Append(docBody);
                mainPart.Document.Save();
                wordDocument.Close();
            

            result = Convert.ToBase64String(mem.ToArray());
        

上面的代码创建了一个名为 Result.docx 的 Word 文档,其结构如下:

但没有任何其他 Open XML 部分(如 app.xmlstyles.xml

【问题讨论】:

这个问题与编程无关,因此不适合在这里提问。您正在寻找 Super User。 由于这些是 docx,Word 的本机文件格式,Word 旨在能够处理“基本”并补充缺少的内容。 可能有另一个软件,可以以类似的方式处理丢失的内容,我不知道。但是,要么您需要编写一个程序来满足您的需求(例如,使用 Open XML SDK),要么找到这样的软件(这个问题在 Stack Overflow 上是题外话),要么在 Word 中打开“部分”文档。如果您有权访问本地 SharePoint,Word Automation Services 应该能够处理它,以及转换为 PDF。 您能否分享一个最小可复制示例来说明您如何创建这些 Word 文档?听起来您创建的 Open XML 标记存在问题。 Word 可能比 LibreOffice 更宽容。此外,Word 将在保存文档时生成自己的 Open XML 标记,并且 Word 创建的标记将包含您最初未创建的部分(例如,app.xml、core.xml、styles.xml)。 刚刚添加了示例代码及其结果。请检查它:D @LuisBarajas,我编辑了您的问题以改进术语,例如,因为您的“文件”实际上是“部分”。根据您的示例代码和您的 Word 文档的包内容,我提供了答案。 【参考方案1】:

您需要在以下方面有所不同:

Open XML 标准及其对WordprocessingDocument 的最低要求和 由 Microsoft Word 或其他应用程序创建的“最小”文档。

按照标准,最小的WordprocessingDocument只需要一个主文档部分(MainDocumentPartdocument.xml),内容如下:

<w:document xmlns:w="...">
  <w:body>
    <w:p />
  </w:body>
</w:document>

仅当您具有样式或编号时才需要其他部分,例如 StyleDefinitionsPart (styles.xml) 或 NumberingDefintionsPart (numbering.xml),在这种情况下,您必须在代码中明确创建它们。

接下来,查看您的示例代码,您似乎正在创建:

    引用样式的段落(参见CreateStyledParagraph(docBody)),必须在StyleDefinitionsPartstyles.xml)中定义;和 编号列表(例如CreateList(docBody)),必须在NumberingDefinitionsPart (numbering.xml) 中定义。

但是,您的代码既没有创建 StyleDefinitionsPart 也没有创​​建 NumberingDefintionsPart,这意味着您的文档可能不是有效的 Open XML 文档。

现在,Word 非常宽容,可以默默地修复各种问题,忽略部分 Open XML 标记(例如,您可能已分配给段落的样式)。

相比之下,根据 LibreOffice 的容错程度,无效的 Open XML 标记可能会导致崩溃。例如,如果 LibreOffice 在您的 w:document 中找到类似 &lt;w:pStyle w:val="MyStyleName" /&gt; 的元素时只是假设存在 StyleDefinitionsPart,然后在请求 StyleDefinitionsPart 时不检查它是否获得 null 引用,它可以崩溃。

最后,要向 Word 文档添加部分,您可以使用 Open XML SDK,如下所示:

[Fact]
public void CanAddParts()

    const string path = "Document.docx";
    const WordprocessingDocumentType type = WordprocessingDocumentType.Document;

    using WordprocessingDocument wordDocument = WordprocessingDocument.Create(path, type);

    // Create minimum main document part.
    MainDocumentPart mainDocumentPart = wordDocument.AddMainDocumentPart();
    mainDocumentPart.Document = new Document(new Body(new Paragraph()));

    // Create empty style definitions part.
    var styleDefinitionsPart = mainDocumentPart.AddNewPart<StyleDefinitionsPart>();
    styleDefinitionsPart.Styles = new Styles();

    // Create empty numbering definitions part.
    var numberingDefinitionsPart = mainDocumentPart.AddNewPart<NumberingDefinitionsPart>();
    numberingDefinitionsPart.Numbering = new Numbering();

【讨论】:

感谢您的回答和解释,我已经尝试过了,它可以工作:) 动态文档现在很好:D

以上是关于动态创建的 Word 文档中缺少打开的 XML 部分的主要内容,如果未能解决你的问题,请参考以下文章

freemarker根据模板生成word文件实现导出功能

freemarker根据模板生成word文件实现导出功能

word出现无法打开office open XML文件,因为内容有错误,该怎么办?

java动态生成word,该怎么解决

打开word提示“ 根据架构,XML数据无效”,求救!

你好,我的word文档出现“无法打开office open xml”问题,求解决