动态创建的 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# 中创建 WordprocessingDocument
s,然后将它们转换为 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.xml
或 styles.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
只需要一个主文档部分(MainDocumentPart
,document.xml
),内容如下:
<w:document xmlns:w="...">
<w:body>
<w:p />
</w:body>
</w:document>
仅当您具有样式或编号时才需要其他部分,例如 StyleDefinitionsPart
(styles.xml
) 或 NumberingDefintionsPart
(numbering.xml
),在这种情况下,您必须在代码中明确创建它们。
接下来,查看您的示例代码,您似乎正在创建:
-
引用样式的段落(参见
CreateStyledParagraph(docBody)
),必须在StyleDefinitionsPart
(styles.xml
)中定义;和
编号列表(例如CreateList(docBody)
),必须在NumberingDefinitionsPart
(numbering.xml
) 中定义。
但是,您的代码既没有创建 StyleDefinitionsPart
也没有创建 NumberingDefintionsPart
,这意味着您的文档可能不是有效的 Open XML 文档。
现在,Word 非常宽容,可以默默地修复各种问题,忽略部分 Open XML 标记(例如,您可能已分配给段落的样式)。
相比之下,根据 LibreOffice 的容错程度,无效的 Open XML 标记可能会导致崩溃。例如,如果 LibreOffice 在您的 w:document
中找到类似 <w:pStyle w:val="MyStyleName" />
的元素时只是假设存在 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 部分的主要内容,如果未能解决你的问题,请参考以下文章