我有单页输入 docx 模板文件,用户设计使用某些变量,例如contact_name。在使用 OpenXml SDK + Open-Xml-PowerTools 进行处理期间,我基于此模板创建了许多 docx 文件实例,并用实际值替换变量。最后,我需要一个 docx 输出,因此我使用 Open-Xml-PowerTools DocumentBuilder 合并到一个 docx 中。
在用户将编号列表放入模板之前,这似乎有效。我最初的问题是编号列表在合并后跨文档实例继续编号,即列表第二页上的数字是 11-20 而不是 1-10,因为文档认为它们都引用了相同的列表 ID。
我设法通过确保 num id 在文档正文中是唯一的来解决这个问题,但是现在列表的格式在第一页之外丢失了,例如在第一页上,编号的列表项是缩进的,但是从第二页开始,它们很难留在页面就像它们不是正确的编号列表。似乎我需要更新样式和编号部分以拥有这些匹配的新 num id,但我无法使其正常工作。
我在 ericwhite.com 的论坛上发布了有关此问题的信息,但尚未收到有关最新问题的回复 ( http://ericwhite.com/blog/forums/topic/list-numbering-on-merged-docs/ )。
我最近解决这个问题的尝试是在 OpenXml-Power-Tools 中抛出一个异常,所以我认为我错过了使用新列表 ID 更新某些部分。有谁知道如何做到这一点?下面的代码尝试与以下异常。
public bool Merge(List<InterchangeableWordProcessingDocument> inputFiles, string outputFilePath)
{
if (inputFiles == null)
{
logger.LogDebug("No files to merge.");
return true;
}
try
{
List<OpenXmlPowerTools.Source> sources = new List<OpenXmlPowerTools.Source>();
int highestListNumbering = 0;
int highestAbstractListNumbering = 0;
foreach (var inputFile in inputFiles)
{
//Sometimes merge puts start of next page onto end of previous one so prevent
//Seems to cause extra blank page when there are labels so don't do on labels pages
if (inputFile.DocType == DocType.Letter)
{
using (var wordDoc = inputFile.GetAsWordProcessingDocument())
{
var para = wordDoc.MainDocumentPart.Document.Body.ChildElements.First<Paragraph>();
if (para.ParagraphProperties == null)
{
para.ParagraphProperties = new ParagraphProperties();
}
para.ParagraphProperties.PageBreakBefore = new PageBreakBefore();
//http://ericwhite.com/blog/forums/topic/list-numbering-on-merged-docs/
//Numberings should be unique to each page otherwise they continue from the previous
//Keep track of how many we have so we can add on to always have a unique number
var numIds = wordDoc.MainDocumentPart.Document.Body.Descendants<NumberingId>().ToList();
logger.LogDebug("Found " + numIds.Count + " num ids.");
foreach (var numId in numIds)
numId.Val += highestListNumbering;
var styleNumIds = wordDoc.MainDocumentPart.StyleDefinitionsPart.RootElement.Descendants<NumberingId>().ToList();
if (wordDoc.MainDocumentPart.StyleDefinitionsPart != null)
{
logger.LogDebug("Found " + styleNumIds.Count + " stlye num ids.");
foreach (var styleNumId in styleNumIds)
styleNumId.Val += highestListNumbering;
}
if (wordDoc.MainDocumentPart.NumberingDefinitionsPart != null)
{
var numberingNumIds = wordDoc.MainDocumentPart.NumberingDefinitionsPart.RootElement.Descendants<NumberingInstance>().ToList();
logger.LogDebug("Found " + numberingNumIds.Count + " numbering num ids.");
foreach (var numberingNumId in numberingNumIds)
{
numberingNumId.NumberID += highestListNumbering;
numberingNumId.AbstractNumId.Val += highestAbstractListNumbering;
}
var abstractNumberingNumIds = wordDoc.MainDocumentPart.NumberingDefinitionsPart.RootElement.Descendants<AbstractNumId>().ToList();
logger.LogDebug("Found " + abstractNumberingNumIds.Count + " abstract num ids." + wordDoc.MainDocumentPart.NumberingDefinitionsPart.RootElement.XName.LocalName);
foreach (var abstractNumberingNumId in abstractNumberingNumIds)
abstractNumberingNumId.Val += highestAbstractListNumbering;
//Keep the max nums up to date
if (abstractNumberingNumIds.Count > 0)
highestAbstractListNumbering = Math.Max(highestAbstractListNumbering, abstractNumberingNumIds.Max(ln => (ln.Val.HasValue ? ln.Val.Value : 0)));
}
if (numIds.Count > 0)
highestListNumbering = Math.Max(highestListNumbering, numIds.Max(ln => (ln.Val.HasValue ? ln.Val.Value : 0)));
wordDoc.MainDocumentPart.Document.Save();
}
}
sources.Add(new OpenXmlPowerTools.Source(inputFile.GetAsWmlDocument(), true));
}
DocumentBuilder.BuildDocument(sources, outputFilePath);
return true;
}
catch (SystemException ex)
{
logger.LogError("Error occured while generating bereavement letters. ", ex);
return false;
}
finally
{
foreach (var inputFile in inputFiles)
{
inputFile.Dispose();
}
}
}
例外:
System.InvalidOperationException: Sequence contains no elements
at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
at OpenXmlPowerTools.DocumentBuilder.CopyNumbering(WordprocessingDocument sourceDocument, WordprocessingDocument newDocument, IEnumerable1 newContent, List1 images)
at OpenXmlPowerTools.DocumentBuilder.AppendDocument(WordprocessingDocument sourceDocument, WordprocessingDocument newDocument, List1 newContent, Boolean keepSection, String insertId, List1 images)
at OpenXmlPowerTools.DocumentBuilder.BuildDocument(List`1 sources, WordprocessingDocument output)
at OpenXmlPowerTools.DocumentBuilder.BuildDocument(List`1 sources, String fileName)
at BereavementMailing.TemplateEngine.Merge(List`1 inputFiles, String outputFilePath) in C:\caw\Underdog\Apps\Services\BereavementMailingEngine\BM_RequestProcessor\TemplateEngine.cs:line 508