【问题标题】:How can I export a piece of a DOCX file and keep the same paragraph numbering?如何导出一段 DOCX 文件并保持相同的段落编号?
【发布时间】:2019-01-10 21:40:38
【问题描述】:

TL;DR:

如何将段落编号捕获为文本的“部分”并将其导出到 DOCX?


问题

我有一个文档,它分为多个部分和子部分,其内容类似于一组州法规(Statute 208,带有子部分 Statute 208.1Statute 208.2 等)。我们通过修改 .docx zip 中的 numbering.xml 文件来创建它。

我想将“子部分”(208.5) 及其文本导出到单独的 .docx 文件中。我的 VSTO 加载项可以很好地导出文本,但 编号重置208.1。这确实有些道理,因为它现在是文档中带有 <ilvl> 的第一段。

PDF 工作正常

有趣的是,我可以调用Word.RangeExportAsFixedFormat 函数并将这个选择导出为PDF 就好了——甚至保留编号。这使我走上了一条尝试“渲染”选择的道路,可能就像它会被打印一样,以便将其放入新的 .docx 文件中,但我也没有弄清楚。


我尝试过的:

  • Range.ExportFragment() 使用 wdFormatStrictOpenXMLDocumentwdFormatDocumentDefault 作为 wdSaveType 值。

    • 这些导出还要重新编号。
  • Document.PrintOut() 使用 PrintToFile = true 和有效的文件名。我现在意识到,从字面上看,这会生成“打印输出指令”,并且不会在路径 filename 处注入具有任何有效文件结构的新文件。

    • 显然不起作用。 :)
  • Application.Selection.XML 到变量 content 并在新添加的 Document 对象上调用 Document.Content.InsertXML(content)

    • 仍会重置编号。

上下文的代码部分

using Word = Microsoft.Office.Interop.Word;

Word.Range range = Application.ActiveDocument.Range(startPosition, endPosition);
range.Select();

//export to DOCX?
Application.Selection.Range.ExportFragment(
    filename, Word.WdSaveFormat.wdFormatDocumentDefault);

【问题讨论】:

  • 您可以尝试设置 Range.ListFormat.ListLevelNumber 看看是否有帮助吗?
  • @Jazimov ListLevelNumber1,我认为这是因为它是顶级“部分”(域术语).. 但是,我确实在 ListLevelNumber 下看到了 ListString同样,这就是我正在谈论的208.5。也许当我导出该内容时,我可以在事后设置ListLevelString。试一试。
  • 太棒了!如果您的想法最终奏效,请告诉我们。
  • 那个发现让我找到了ListValue,它代表列表中 List 对象的“索引”。这也可以,但它只有一个 getter - 没有 setter。接下来,我找到了ListFormat.ConvertNumbersToText() 方法。那行得通! ...但是,我还没有找到如何取消转换原始文本..
  • 您是否尝试设置 ListLevelNumber?它是读/写的。

标签: c# ms-word vsto word-addins


【解决方案1】:

您可以在导出前使用 ConvertNumbersToText(wdNumberAllNumbers),然后在导出后使用 _Document.Undo() 或关闭而不保存。

【讨论】:

  • 请致电ConvertNumbersToText()!根据我的业务规则,关闭而不保存不是一个选项,但我该如何撤消?这就是我目前坚持的部分。
  • 就像 ActiveDocument.Undo 一样简单。
  • 很好的发现 - 不幸的是,在测试之后,看起来 ConvertNumbersToText() 方法实际上并没有注册为“可撤消”操作。我通过删除我放置的Undo() 调用并检查撤消“下拉菜单”是否为空以及“撤消”不执行任何操作来验证这一点。
  • ActiveDocument.ConvertNumbersToText (wdNumberParagraph),然后是 ActiveDocument.Undo 为我工作。在这种情况下,我怀疑 wdNumberAllNumbers 是错误的参数 - 您可能尝试的另一个参数是 wdNumberListNum。无论如何,为什么不能在生成输出后不保存就关闭原始文档?
  • 简而言之,因为业务规则需要它。在“long”中,这是以编程方式将文档的一部分导出到单独的 docx 文件的方法的一部分,但用户希望原始文档保持打开状态。
【解决方案2】:

在这个(过时的)链接中有一些很好的信息,它们仍然应该适用于当前的 Word API: https://forums.windowssecrets.com/showthread.php/27711-Determining-which-ListTemplates-item-is-in-use-(VBA-Word-2000)

该链接上的信息表明您可以为 ListTemplate 创建一个名称/句柄,以便您可以在代码中引用它——只要您的法规样式项目符号与文档的命名样式相关联。这个想法是首先命名与活动文档的法规项目符号样式关联的 ListTemplate,然后在访问 ListLevels 集合时引用该名称。

例如,您的代码可能如下所示:

ActiveDocument.Styles("StatutesBulletStyle").ListTemplate.Name = "StatuteBulletListTemplate";

以上赋值后,可以通过名称引用模板:

ActiveDocument.ListTemplates("StatuteBulletListTemplate").ListLevels(1).StartAt = 5;

使用上述技术不再需要您尝试找出活动模板是什么...

这有帮助吗?

【讨论】:

  • 啊,有趣..嗯。但是我首先如何命名Style?我认为我们编号方案的逻辑在 numbering.xml 文件中。如果这样做的话,我可以将其修改为具有 <name><id> 标记。
  • 我可以看到虽然可以工作.. 如果我能掌握模板,我可能可以将其作为导出文档的模板(它在我们的 Application.ActiveDocument案例)。
  • 如果您在编号部分中的文本上按 Ctrl+Shift+S,您应该能够看到当前应用于该部分的样式。它可能只是“正常”。如果失败,您应该尝试定义一种样式 [这里超出范围] 并将其应用于您的文档或您描述的编号的部分。在不知道整个文档的具体细节的情况下,您至少应该能够利用了解您当前使用的样式作为样式,并尝试使用上述策略从该样式名称中获取当前的 ListTemplate。
  • 它确实是“正常”Style。我已经通过Application.ActiveDocument.Style["Normal"](这是c#)处理了它。但是,ListTemplate 属性为 null.. 仍在研究中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-20
  • 2013-08-13
相关资源
最近更新 更多