2

我正在尝试复制 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 文件已部分损坏。当我打开我的文件时,我收到以下两条消息: 在此处输入图像描述

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

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

在此处输入图像描述

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

复制自身后获得正确工作的 DOCX 文件的任何想法?任何替代代码表示赞赏。

4

2 回答 2

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:document有两个w:body子元素的,它是无效的 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()在追加之前具体化集合。这是为了避免在枚举同时更改的元素时出现任何问题。

于 2019-11-28T12:10:34.230 回答
-1

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

于 2013-04-17T21:19:33.383 回答