以下作为xUnit单元测试编写的示例代码说明了如何实现所需的功能。我添加了代码注释来解释执行的操作和原因。
public class AltChunkAssemblyTests
{
// Sample template file names for unit testing purposes.
private readonly string[] _templateFileNames =
{
"report-Part1.docx","report-Part2.docx","report-Part3.docx"
};
// Sample content maps for unit testing purposes.
// Each Dictionary<string,string> represents data used to replace the
// content of block-level w:sdt elements identified by w:tag values of
// "firstTag" and "secondTag".
private readonly List<Dictionary<string,string>> _contentMaps = new List<Dictionary<string,string>>
{
new Dictionary<string,string>
{
{ "firstTag","report-Part1: First value" },{ "secondTag","report-Part1: Second value" }
},new Dictionary<string,"report-Part2: First value" },"report-Part2: Second value" }
},"report-Part3: First value" },"report-Part3: Second value" }
}
};
[Fact]
public void CanAssembleDocumentUsingAltChunks()
{
// Create some sample "templates" (technically documents) for unit
// testing purposes.
CreateSampleTemplates();
// Create an empty result document.
using WordprocessingDocument wordDocument = WordprocessingDocument.Create(
"AltChunk.docx",WordprocessingDocumentType.Document);
MainDocumentPart mainPart = wordDocument.AddMainDocumentPart();
var body = new Body();
mainPart.Document = new Document(body);
// Add one w:altChunk element for each sample template,using the
// sample content maps for mapping sample data to the content
// controls contained in the templates.
for (var index = 0; index < 3; index++)
{
if (index > 0) body.AppendChild(new Paragraph(new Run(new Break { Type = BreakValues.Page })));
body.AppendChild(CreateAltChunk(_templateFileNames[index],_contentMaps[index],wordDocument));
}
}
private void CreateSampleTemplates()
{
// Create a sample template for each sample template file names.
foreach (string templateFileName in _templateFileNames)
{
CreateSampleTemplate(templateFileName);
}
}
private static void CreateSampleTemplate(string templateFileName)
{
// Create a new Word document with paragraphs marking the start and
// end of the template (for testing purposes) and two block-level
// structured document tags identified by w:tag elements with values
// "firstTag" and "secondTag" and values that are going to be
// replaced by the ContentControlWriter during document assembly.
using WordprocessingDocument wordDocument = WordprocessingDocument.Create(
templateFileName,WordprocessingDocumentType.Document);
MainDocumentPart mainPart = wordDocument.AddMainDocumentPart();
mainPart.Document =
new Document(
new Body(
new Paragraph(
new Run(
new Text($"Start of template '{templateFileName}'"))),new SdtBlock(
new SdtProperties(
new Tag { Val = "firstTag" }),new SdtContentBlock(
new Paragraph(
new Run(
new Text("First template value"))))),new SdtBlock(
new SdtProperties(
new Tag { Val = "secondTag" }),new SdtContentBlock(
new Paragraph(
new Run(
new Text("Second template value"))))),new Paragraph(
new Run(
new Text($"End of template '{templateFileName}'")))));
}
private static AltChunk CreateAltChunk(
string templateFileName,Dictionary<string,string> contentMap,WordprocessingDocument wordDocument)
{
// Copy the template file contents to a MemoryStream to be able to
// update the content controls without altering the template file.
using FileStream fileStream = File.Open(templateFileName,FileMode.Open);
using var memoryStream = new MemoryStream();
fileStream.CopyTo(memoryStream);
// Open the copy of the template on the MemoryStream,update the
// content controls,save the updated template back to the
// MemoryStream,and reset the position within the MemoryStream.
using (WordprocessingDocument chunkDocument = WordprocessingDocument.Open(memoryStream,true))
{
var contentControlWriter = new ContentControlWriter(contentMap);
contentControlWriter.WriteContentControls(chunkDocument);
}
memoryStream.Seek(0,SeekOrigin.Begin);
// Create an AlternativeFormatImportPart from the MemoryStream.
string altChunkId = "AltChunkId" + Guid.NewGuid();
AlternativeFormatImportPart chunk = wordDocument.MainDocumentPart.AddAlternativeFormatImportPart(
AlternativeFormatImportPartType.WordprocessingML,altChunkId);
chunk.FeedData(memoryStream);
// Return the w:altChunk element to be added to the w:body element.
return new AltChunk { Id = altChunkId };
}
}
我已经使用创建的ContentControlWriter
类测试了代码,以回答有关如何create a new document from word template with multiple pages using documentformat.openxml的其他问题。效果很好。完整的代码可以在我的CodeSnippets GitHub存储库中找到。寻找AltChunkAssemblyTests和ContentControlWriter。
CreateSampleTemplates()
方法创建三个示例文档。例如,report-Part1.docx
的主要文档部分具有以下内容:
<?xml version="1.0" encoding="utf-8"?>
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:body>
<w:p>
<w:r>
<w:t>Start of template 'report-Part1.docx'</w:t>
</w:r>
</w:p>
<w:sdt>
<w:sdtPr>
<w:tag w:val="firstTag" />
</w:sdtPr>
<w:sdtContent>
<w:p>
<w:r>
<w:t>First template value</w:t>
</w:r>
</w:p>
</w:sdtContent>
</w:sdt>
<w:sdt>
<w:sdtPr>
<w:tag w:val="secondTag" />
</w:sdtPr>
<w:sdtContent>
<w:p>
<w:r>
<w:t>Second template value</w:t>
</w:r>
</w:p>
</w:sdtContent>
</w:sdt>
<w:p>
<w:r>
<w:t>End of template 'report-Part1.docx'</w:t>
</w:r>
</w:p>
</w:body>
</w:document>
在组装后并且没有让Word再次保存文档,AltChunk.docx
的主要文档部分如下所示:
<?xml version="1.0" encoding="utf-8"?>
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:body>
<w:altChunk r:id="AltChunkId81885280-e38d-4ffb-b8a3-38d96992c2eb" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" />
<w:p>
<w:r>
<w:br w:type="page" />
</w:r>
</w:p>
<w:altChunk r:id="AltChunkId6d862de7-c477-42bc-baa4-c42441e5b03b" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" />
<w:p>
<w:r>
<w:br w:type="page" />
</w:r>
</w:p>
<w:altChunk r:id="AltChunkIdbfd7ea64-4cd0-4acf-9d6f-f3d405c021ca" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" />
</w:body>
</w:document>
我不确定为什么您确切地使用那些w:altChunk
元素和相关部分来组合多个Word文档。这需要Microsoft Word进行“繁重的工作”,尽管在您的情况下,直接生成正确的标记可能非常容易。例如,将文档保存在Microsoft Word中后,主文档部分将如下所示(带有其他XML命名空间,为清楚起见,我将其删除):
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:document xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml"
mc:Ignorable="w14">
<w:body>
<w:p w14:paraId="76D6BC46" w14:textId="77777777" w:rsidR="00EA51EB" w:rsidRDefault="00B25FEF">
<w:r>
<w:t>Start of template 'report-Part1.docx'</w:t>
</w:r>
</w:p>
<w:sdt>
<w:sdtPr>
<w:tag w:val="firstTag"/>
<w:id w:val="-1950995891"/>
</w:sdtPr>
<w:sdtEndPr/>
<w:sdtContent>
<w:p w14:paraId="2701CE6E" w14:textId="77777777" w:rsidR="00EA51EB" w:rsidRDefault="00B25FEF">
<w:r>
<w:t>report-Part1: First value</w:t>
</w:r>
</w:p>
</w:sdtContent>
</w:sdt>
<w:sdt>
<w:sdtPr>
<w:tag w:val="secondTag"/>
<w:id w:val="551584029"/>
</w:sdtPr>
<w:sdtEndPr/>
<w:sdtContent>
<w:p w14:paraId="0B591553" w14:textId="77777777" w:rsidR="00EA51EB" w:rsidRDefault="00B25FEF">
<w:r>
<w:t>report-Part1: Second value</w:t>
</w:r>
</w:p>
</w:sdtContent>
</w:sdt>
<w:p w14:paraId="7393CFF0" w14:textId="77777777" w:rsidR="00E60EE9" w:rsidRDefault="00B25FEF">
<w:r>
<w:t>End of template 'report-Part1.docx'</w:t>
</w:r>
</w:p>
<w:p w14:paraId="089D32A3" w14:textId="77777777" w:rsidR="00E60EE9" w:rsidRDefault="00B25FEF">
<w:r>
<w:br w:type="page"/>
</w:r>
</w:p>
<w:p w14:paraId="11AC41DA" w14:textId="77777777" w:rsidR="00716CCA" w:rsidRDefault="00B25FEF">
<w:r>
<w:lastRenderedPageBreak/>
<w:t>Start of template 'report-Part2.docx'</w:t>
</w:r>
</w:p>
<w:sdt>
<w:sdtPr>
<w:tag w:val="firstTag"/>
<w:id w:val="-1559003811"/>
</w:sdtPr>
<w:sdtEndPr/>
<w:sdtContent>
<w:p w14:paraId="1867093C" w14:textId="77777777" w:rsidR="00716CCA" w:rsidRDefault="00B25FEF">
<w:r>
<w:t>report-Part2: First value</w:t>
</w:r>
</w:p>
</w:sdtContent>
</w:sdt>
<w:sdt>
<w:sdtPr>
<w:tag w:val="secondTag"/>
<w:id w:val="-1480071868"/>
</w:sdtPr>
<w:sdtEndPr/>
<w:sdtContent>
<w:p w14:paraId="43DA0FC0" w14:textId="77777777" w:rsidR="00716CCA" w:rsidRDefault="00B25FEF">
<w:r>
<w:t>report-Part2: Second value</w:t>
</w:r>
</w:p>
</w:sdtContent>
</w:sdt>
<w:p w14:paraId="1F9B0122" w14:textId="77777777" w:rsidR="00E60EE9" w:rsidRDefault="00B25FEF">
<w:r>
<w:t>End of template 'report-Part2.docx'</w:t>
</w:r>
</w:p>
<w:p w14:paraId="18873AAA" w14:textId="77777777" w:rsidR="00E60EE9" w:rsidRDefault="00B25FEF">
<w:r>
<w:br w:type="page"/>
</w:r>
</w:p>
<w:p w14:paraId="16E23FE9" w14:textId="77777777" w:rsidR="003C3D2D" w:rsidRDefault="00B25FEF">
<w:r>
<w:lastRenderedPageBreak/>
<w:t>Start of template 'report-Part3.docx'</w:t>
</w:r>
</w:p>
<w:sdt>
<w:sdtPr>
<w:tag w:val="firstTag"/>
<w:id w:val="780077040"/>
</w:sdtPr>
<w:sdtEndPr/>
<w:sdtContent>
<w:p w14:paraId="00BA914F" w14:textId="77777777" w:rsidR="003C3D2D" w:rsidRDefault="00B25FEF">
<w:r>
<w:t>report-Part3: First value</w:t>
</w:r>
</w:p>
</w:sdtContent>
</w:sdt>
<w:sdt>
<w:sdtPr>
<w:tag w:val="secondTag"/>
<w:id w:val="-823814304"/>
</w:sdtPr>
<w:sdtEndPr/>
<w:sdtContent>
<w:p w14:paraId="10653801" w14:textId="77777777" w:rsidR="003C3D2D" w:rsidRDefault="00B25FEF">
<w:r>
<w:t>report-Part3: Second value</w:t>
</w:r>
</w:p>
</w:sdtContent>
</w:sdt>
<w:p w14:paraId="1622299A" w14:textId="77777777" w:rsidR="00E60EE9" w:rsidRDefault="00B25FEF">
<w:r>
<w:t>End of template 'report-Part3.docx'</w:t>
</w:r>
</w:p>
<w:sectPr w:rsidR="00E60EE9">
<w:pgSz w:w="12240" w:h="15840"/>
<w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440" w:header="708" w:footer="708" w:gutter="0"/>
<w:cols w:space="708"/>
<w:docGrid w:linePitch="360"/>
</w:sectPr>
</w:body>
</w:document>
Word将添加不必添加的w:sectPr
元素(除非您需要特定的页面布局)。它还添加了不需要的w:lastRenderedPageBreaks
。此外,添加到w:p
(Paragraph
)元素的属性和添加到w:id
元素的元素(例如w:sdtEndPr
,w:sdt
)是可选的。
本文链接:https://www.f2er.com/3050564.html