【问题标题】:C# Duplicate DOCX File Using OpenXMLC# 使用 OpenXML 复制 DOCX 文件
【发布时间】:2013-04-10 18:28:46
【问题描述】:

我正在尝试复制 docx 文件内容并使用 C# 中的 OpenXML 将它们保存在同一个文件中

代码如下:

using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(wordFileNamePath, true))
{
    foreach(OpenXmlElement element in wordDoc.MainDocumentPart.Document.ChildElements)
    {
        OpenXmlElement cloneElement = (OpenXmlElement)element.Clone();
        wordDoc.MainDocumentPart.Document.Append(cloneElement);
    }
    wordDoc.MainDocumentPart.Document.Save();
}

代码运行良好,可以满足我的需要。我的问题是生成的 docx 文件已部分损坏。当我打开我的文件时,我收到以下两条消息:

单击“确定”然后单击“是”将正常打开文件。但是,该文件一直被损坏,直到我“另存为”它(使用相同或不同的名称)。新保存的文件就是这样固定的。

通过使用 Open XML SDK 2.5 Productivity Tool for Microsoft Office,我可以验证文件并查看反映的代码。验证文件会出现以下 5 个错误:

所以我认为我在代码中使用的“克隆”功能会按原样复制元素,因此当它附加到文档时,会发生一些 ID 重复。

有没有办法在复制自身后获得一个正常工作的 DOCX 文件?任何替代代码表示赞赏。

【问题讨论】:

    标签: c# .net clone openxml


    【解决方案1】:

    您的方法的问题在于它创建了无效的 Open XML 标记。这就是原因。

    假设您有一个由以下标记表示的非常简单的 Word 文档:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
      <w:body>
        <w:p>
          <w:r>
            <w:t>First paragraph</w:t>
          </w:r>
        </w:p>
        <w:p>
          <w:r>
            <w:t>Second paragraph</w:t>
          </w:r>
        </w:p>
      <w:body>
    <w:document>
    

    在您的 foreach 循环中,wordDoc.MainDocumentPart.Document.ChildElements 将是一个仅包含 w:body 元素的单元素列表。因此,您创建了w:body 元素的深层克隆并将其附加到w:document。生成的 Open XML 标记如下所示:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
      <w:body>
        <w:p>
          <w:r>
            <w:t>First paragraph</w:t>
          </w:r>
        </w:p>
        <w:p>
          <w:r>
            <w:t>Second paragraph</w:t>
          </w:r>
        </w:p>
      <w:body>
      <w:body>
        <w:p>
          <w:r>
            <w:t>First paragraph</w:t>
          </w:r>
        </w:p>
        <w:p>
          <w:r>
            <w:t>Second paragraph</w:t>
          </w:r>
        </w:p>
      <w:body>
    <w:document>
    

    以上是带有两个w:body 子元素的w:document,这是无效的Open XML 标记,因为w:document 必须只有一个w:body 子元素。因此,Word 会显示该错误消息。

    要解决此问题,您需要使用Document.Body,只要您使用Document。以下简化的示例显示了如何执行此操作。

    using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(wordFileNamePath, true))
    {
        Body body = wordDoc.MainDocumentPart.Document.Body;
        IEnumerable<OpenXmlElement> clonedElements = body
            .Elements()
            .Select(e => e.CloneNode(true))
            .ToList();
    
        body.Append(clonedElements);
    }
    

    您会看到我没有显式保存Document,因为using 语句和默认情况下自动保存这些文档的事实没有必要这样做。其次,我使用ToList() 在追加之前实现集合。这是为了避免在枚举同时更改的元素时出现任何问题。

    【讨论】:

      【解决方案2】:

      为什么不会被破坏?您正在打开一个文档,获取所有子元素,并将它们写入同一个文档。我不确定那应该做什么。

      【讨论】:

      • 是的,假设您有图像、文本和任何元素。我希望它们会被重复(附加)到文档中。
      • @yazanpro,那么你应该只从正文中获取元素。类似:wordDoc.MainDocumentPart.Document.Body.ChildElements。并将它们附加到正文wordDoc.MainDocumentPart.Document.Body.Append(cloneElement);
      • 您的意思是:使用 (WordprocessingDocument wordDoc = WordprocessingDocument.Open(wordFileNamePath, true)) { foreach(wordDoc.MainDocumentPart.Document.Body.ChildElements 中的 OpenXmlElement 元素) { OpenXmlElement cloneElement = (OpenXmlElement)element。克隆(); wordDoc.MainDocumentPart.Document.Body.Append(cloneElement); } wordDoc.MainDocumentPart.Document.Save(); } 我遇到了同样的问题
      • 我的意思是在元素中具有重复 ID 的完全相同的结果文件
      • @Yazanpro,有点离题,但你为什么要这样做?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-18
      • 1970-01-01
      相关资源
      最近更新 更多