通过C#

时间:2019-12-11 20:44:46

标签: c# windows macos ms-word openxml-sdk

其行为如下:下载在服务器上动态创建的文档,然后在Mac上打开该文档后,该文档将不会“另存为”。它会自动失败,将文档名称设置为以前的名称,并且在保存目标文件夹中没有文档。

内幕:代码创建文档并附加文本,然后在该文件的末尾附加由另一个人为该创建的文档上载的word文档。该代码使用的是AltChunk类,如MSDN文档here中所述。这样效果很好,除了间歇性地使用上述某些附件外,没有什么其他问题。

这似乎是一个单词错误,我不确定在用文字或OpenXML修补此错误之前,我是否可以做任何事情。

要在下面复制的代码

以下是重现此错误所需的步骤:

  1. 在Mac上的Visual Studio中创建新的控制台应用程序
  2. 在顶层添加一个名为“文档”的文件夹
  3. 下载Nuget依赖项DocumentFormat.OpenXml
  4. 创建一个新单词doc,名称为“ test-source.docx”
    1. 在其中放一些测试文本,没关系
    2. 将文档添加到“文档”文件夹中的解决方案中
    3. 将属性更改为“始终复制”
  5. 创建一个名为“ test-append.docx”的新单词文档(嵌入式单词doc)

    1. 在顶部插入一些测试文本
    2. 复制您选择的jpg。我用来复制的图像类型是jpg。我从http://apod.nasa.gov/apod/处获得了我的照片,他们的其中一张大照片应该可以做到。
    3. 添加到解决方案的“文档”文件夹中
    4. 将文档的属性更改为“始终复制”
  6. 复制将以下代码粘贴到您的Program.cs文件中:

using System.IO;
using System.Linq;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using Text = DocumentFormat.OpenXml.Wordprocessing.Text;

namespace TestWordAppend
{
    class Program
    {
        static void Main(string[] args)
        {
            var destinationDoc = "Docs/test-destination.docx";
            var sourceDoc = "Docs/test-source.docx";
            var appendedDoc = "Docs/test-append2.docx";

            File.Delete(destinationDoc);
            File.Copy(sourceDoc, destinationDoc);

            using (var doc = WordprocessingDocument.Open(destinationDoc, true))
            {
                var body = doc.MainDocumentPart.Document.Body;

                var p2 = body.InsertAfter(
                    new Paragraph(
                        new ParagraphProperties(
                            new PageBreakBefore()
                    )),
                    body.Elements<Paragraph>().Last()
                );


                var altChunkId = "AltChunkId";
                var chunk = doc.MainDocumentPart.AddAlternativeFormatImportPart(
                    AlternativeFormatImportPartType.WordprocessingML,
                    altChunkId);

                using (var fs = File.Open(appendedDoc, FileMode.Open))
                    chunk.FeedData(fs);

                var altChunk = new AltChunk { Id = altChunkId };
                var run = new Run(new TabChar(), new Text(appendedDoc), new Break());
                run.PrependChild(new RunProperties { RunStyle = new RunStyle { Val = "Bold" } });
                var fileP = p2.InsertAfterSelf(new Paragraph());
                fileP.Append(run);
                run = new Run(new TabChar(), new Text("Uploaded by: "), new TabChar(), new Text("Test User"));
                run.PrependChild(new RunProperties { RunStyle = new RunStyle { Val = "Italic" } });
                fileP.Append(run);

                body.Append(altChunk);
                doc.MainDocumentPart.Document.Save();
            }
        }
    }
}
  1. 运行
  2. 检查~/bin/Debug/netcoreapp.3.0/Docs/test-destination.docx中的文档,其中~是解决方案所在的基本路径。
  3. 打开它,尝试在~/Documents文件夹中进行“另存为”,其中~是用户的主路径。
  4. 它不应保存,实际上它应恢复为“ test-destination.docx”名称。当您检查文件文件夹时,在该文件夹中将看不到新文件。

1 个答案:

答案 0 :(得分:0)

我找到了另一种可以帮助缓解此问题的解决方案,但我认为这只是一种解决方法。我已将此错误发布到OpenXML。我不确定这是否实际上是OpenXML的问题,似乎可能是Word引起的,但至少在某个地方引发并指出了该问题。

否则,我不得不在下面找到此解决方案。相反,我必须遍历每个元素并将其克隆,然后将其附加到源文档中。  如果克隆的元素中有图像,则必须执行一些额外的步骤,以将图像复制到新文档中。

private static void GenerateByCopying()
{
    using (var doc = WordprocessingDocument.Open(DestinationDoc, true))
    using (var appendedDoc = WordprocessingDocument.Open(AppendedDoc, true))
    {
        var body = doc.MainDocumentPart.Document.Body;
        var appendedBody = appendedDoc.MainDocumentPart.Document.Body;
        AppendNecessaryText(body);

        foreach (var part in appendedBody.Elements())
        {
            var clonedElement = part.CloneNode(true);
            clonedElement.Descendants<DocumentFormat.OpenXml.Drawing.Blip>()
                .ToList()
                .ForEach(imageData =>
                {
                    var newRelation = CopyImage(doc, imageData.Embed, appendedDoc);
                    imageData.Embed = newRelation;

                });
            clonedElement.Descendants<DocumentFormat.OpenXml.Vml.ImageData>()
                .ToList()
                .ForEach(imageData =>
                {
                    var newRelation = CopyImage(doc, imageData.RelationshipId, appendedDoc);
                    imageData.RelationshipId = newRelation;
                });
            body.Append(clonedElement);
        }

        doc.MainDocumentPart.Document.Save();
    }
}

public static string CopyImage(WordprocessingDocument doc, string relId, WordprocessingDocument source)
{
    var p = source.MainDocumentPart.GetPartById(relId) as ImagePart;
    var np = doc.MainDocumentPart.AddPart(p);
    np.FeedData(p.GetStream());
    return doc.MainDocumentPart.GetIdOfPart(np);
}

调整控制台应用程序,在File.Copy()之后运行此方法,我确实能够使用图像打开文档并保存更改。