添加 CustomXmlPart 后 Word 无法打开文档

Word can't open document after adding CustomXmlPart

我正在尝试将自定义xml部件添加到 docm 文件,但没有成功。 显然文件太大(超过 10mb)无法包含在包中。

如果 xml 文件大小小于 7 mb,则可以成功打开文档。

有什么想法吗?

感谢您的帮助。

using (WordprocessingDocument wordDoc = WordprocessingDocument.Open("doc.docm", true))
{
    MainDocumentPart mainPart = wordDoc.MainDocumentPart;

    if (wordDoc.MainDocumentPart.CustomXmlParts != null)
    {
        wordDoc.MainDocumentPart.DeleteParts<CustomXmlPart>(wordDoc.MainDocumentPart.CustomXmlParts);
    }

    CustomXmlPart myXmlPart = mainPart.AddCustomXmlPart(CustomXmlPartType.CustomXml);

    using (FileStream stream = new FileStream("10mbfile.xml", FileMode.Open))
    {
        myXmlPart.FeedData(stream);
    }

    wordDoc.Package.Flush();
}

编辑:我发现了问题,xml 文件包含大量回车 return + 换行符。删除它们后,我可以将文件嵌入为 CustomXmlPart。

以下单元测试演示了您可以将非常大的自定义 XML 部分(在示例中最多 30MB)添加到 Word 文档:

using System;
using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using Xunit;

namespace CodeSnippets.Tests.OpenXml.Wordprocessing
{
    public class LargeCustomXmlPartsTests
    {
        public static readonly XNamespace W = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";

        [Theory]
        [InlineData(5)]
        [InlineData(10)]
        [InlineData(15)]
        [InlineData(20)]
        [InlineData(30)]
        public void CanCreateLargeCustomXmlParts(int size)
        {
            int desiredStreamLength = size * 1024 * 1024;
            string path = $"Document_{size:D2}MB.docm";

            // Create a macro-enabled Word document with a custom XML part having
            // at least the desired size in MB.
            CreateMacroEnabledWordDocument(path, size);

            // Assert that the document does have a custom XML part with at least
            // the desired size.
            using WordprocessingDocument wordDocument = WordprocessingDocument.Open(path, false);
            CustomXmlPart customXmlPart = wordDocument.MainDocumentPart.CustomXmlParts.First();
            using Stream stream = customXmlPart.GetStream(FileMode.Open, FileAccess.Read);
            Assert.True(stream.Length > desiredStreamLength);
        }

        private static void CreateMacroEnabledWordDocument(string path, int size)
        {
            const WordprocessingDocumentType type = WordprocessingDocumentType.MacroEnabledDocument;
            using WordprocessingDocument wordDocument = WordprocessingDocument.Create(path, type);

            // Create a main document part with an empty document.
            MainDocumentPart mainDocumentPart = wordDocument.AddMainDocumentPart();
            WriteRootElement(mainDocumentPart,
                new XElement(W + "document",
                    new XElement(W + "body",
                        new XElement(W + "p"))));

            // Create a custom XML part with the desired size in MB.
            CustomXmlPart customXmlPart = mainDocumentPart.AddCustomXmlPart(CustomXmlPartType.CustomXml);
            WriteRootElement(customXmlPart, CreatePartRootElement(size));
        }

        private static void WriteRootElement(OpenXmlPart part, XElement partRootElement)
        {
            using Stream stream = part.GetStream(FileMode.Create, FileAccess.Write);
            using XmlWriter writer = XmlWriter.Create(stream);

            partRootElement.WriteTo(writer);
        }

        private static XElement CreatePartRootElement(int size)
        {
            var random = new Random();

            return new XElement("root",
                Enumerable.Range(0, size).Select(paragraphIndex =>
                    new XElement("p",
                        new XAttribute("i", paragraphIndex),
                        Enumerable.Range(0, 1000).Select(runIndex =>
                            new XElement("r",
                                new XAttribute("i", runIndex),
                                new XElement("t", CreateRandomString(random)))))));
        }

        private static string CreateRandomString(Random random)
        {
            char[] value = Enumerable
                .Range(0, 930)
                .Select(i => Convert.ToChar(random.Next(33, 125)))
                .ToArray();

            return new string(value);
        }
    }
}

在我的 Windows 10 笔记本上,Microsoft Word for Office 365 打开带有 30MB 自定义 XML 部分的文档没有任何问题。因此,我想说,您的问题一定是由其他因素或多种因素的组合引起的,包括评论中提到的 VSTO 加载项执行的自定义 XML 部分的任何处理。

我发现了问题,xml 文件包含大量回车 return + 换行符。删除它们后,我可以将文件嵌入为 CustomXmlPart。