问题
We have a master docx with the header and footer in and nothing else (formatted with images). We have 100s of word documents with body content but no header and footer and we want to be able to process these when we populate them and add the header and footer from the master header and footer docx.
I have looked at the MSDN documentation here: https://msdn.microsoft.com/en-us/library/cc546917.aspx but it doesn't seem to work and when I open the target document the formatting is wrong and the images are missing.
Is there a way to make this exactly copy the header and footer from one document to another?
回答1:
I also had to implement this for a client at work. I'll give you the methods I wrote for headers and footers.
I wrote trying to keep all styles, fonts, dimensions and images inside header and footer.
This is the method that i use to attach header to another docx.
Try to understand reading the comments I've written.
headerTemplatePath: path of docx where take header
documentPath: path of docx where append header
public void PrependHeader(string headerTemplatePath, string documentPath)
{
// Open docx where we need to add header
using (var wdDoc = WordprocessingDocument.Open(documentPath, true))
{
var mainPart = wdDoc.MainDocumentPart;
// Delete exist header
mainPart.DeleteParts(mainPart.HeaderParts);
// Create new header
var headerPart = mainPart.AddNewPart<HeaderPart>();
// Get id of new header
var rId = mainPart.GetIdOfPart(headerPart);
// Open the header document to be copied
using (var wdDocSource = WordprocessingDocument.Open(headerTemplatePath, true))
{
// Get header part
var firstHeader = wdDocSource.MainDocumentPart.HeaderParts.FirstOrDefault();
if (firstHeader != null)
{
// Copy content of header to new header
headerPart.FeedData(firstHeader.GetStream());
// Keep formatting
foreach (var childElement in headerPart.Header.Descendants<Paragraph>())
{
var paragraph = (Paragraph) childElement;
if (paragraph.ParagraphProperties.SpacingBetweenLines == null)
{
paragraph.ParagraphProperties.SpacingBetweenLines = new SpacingBetweenLines
{
After = "0"
};
paragraph.ParagraphProperties.ParagraphStyleId = new ParagraphStyleId
{
Val = "No Spacing"
};
}
}
// Get all ids of every 'Parts'
var listToAdd = new List<KeyValuePair<Type, Stream>>();
foreach (var idPart in firstHeader.Parts)
{
var part = firstHeader.GetPartById(idPart.RelationshipId);
if (part is ImagePart)
{
headerPart.AddNewPart<ImagePart>("image/png", idPart.RelationshipId);
listToAdd.Add(new KeyValuePair<Type, Stream>(typeof (ImagePart), part.GetStream()));
}
else if (part is DiagramStylePart)
{
headerPart.AddNewPart<DiagramStylePart>(idPart.RelationshipId);
listToAdd.Add(new KeyValuePair<Type, Stream>(typeof (DiagramStylePart), part.GetStream()));
}
else if (part is DiagramColorsPart)
{
headerPart.AddNewPart<DiagramColorsPart>(idPart.RelationshipId);
listToAdd.Add(new KeyValuePair<Type, Stream>(typeof (DiagramColorsPart),
part.GetStream()));
}
else if (part is DiagramDataPart)
{
headerPart.AddNewPart<DiagramDataPart>(idPart.RelationshipId);
listToAdd.Add(new KeyValuePair<Type, Stream>(typeof (DiagramDataPart), part.GetStream()));
}
else if (part is DiagramLayoutDefinitionPart)
{
headerPart.AddNewPart<DiagramStylePart>(idPart.RelationshipId);
listToAdd.Add(new KeyValuePair<Type, Stream>(typeof (DiagramStylePart), part.GetStream()));
}
else if (part is DiagramPersistLayoutPart)
{
headerPart.AddNewPart<DiagramPersistLayoutPart>(idPart.RelationshipId);
listToAdd.Add(new KeyValuePair<Type, Stream>(typeof (DiagramPersistLayoutPart),
part.GetStream()));
}
}
// Foreach Part, copy stream to new header
var i = 0;
foreach (var idPart in headerPart.Parts)
{
var part = headerPart.GetPartById(idPart.RelationshipId);
if (part.GetType() == listToAdd[i].Key)
{
part.FeedData(listToAdd[i].Value);
}
i++;
}
}
else
{
mainPart.DeleteParts(mainPart.HeaderParts);
var sectToRemovePrs = mainPart.Document.Body.Descendants<SectionProperties>();
foreach (var sectPr in sectToRemovePrs)
{
// Delete reference of old header
sectPr.RemoveAllChildren<HeaderReference>();
}
return;
}
}
// Get all sections, and past header to each section (Page)
var sectPrs = mainPart.Document.Body.Descendants<SectionProperties>();
foreach (var sectPr in sectPrs)
{
// Remove old header reference
sectPr.RemoveAllChildren<HeaderReference>();
// Add new header reference
sectPr.PrependChild(new HeaderReference { Id = rId });
}
}
}
Footer method:
footerTemplatePath: path of docx where take footer
documentPath: path of docx where append footer
public void PrependFooter(string footerTemplatePath, string documentPath)
{
// Open docx where append footer
using (var wdDoc = WordprocessingDocument.Open(documentPath, true))
{
var mainPart = wdDoc.MainDocumentPart;
// Remove exist footer
mainPart.DeleteParts(mainPart.FooterParts);
// Create new footer
var footerParts = mainPart.AddNewPart<FooterPart>();
// Get Id of new footer
var rId = mainPart.GetIdOfPart(footerParts);
// Open the footer document to be copied
using (var wdDocSource = WordprocessingDocument.Open(footerTemplatePath, true))
{
var firstFooter = wdDocSource.MainDocumentPart.FooterParts.LastOrDefault();
if (firstFooter != null)
{
// Copy content of footer
footerParts.FeedData(firstFooter.GetStream());
// Keep formatting
foreach (var childElement in footerParts.Footer.Descendants<Paragraph>())
{
var paragraph = (Paragraph) childElement;
if (paragraph.ParagraphProperties.SpacingBetweenLines == null)
{
paragraph.ParagraphProperties.SpacingBetweenLines = new SpacingBetweenLines
{
After = "0"
};
paragraph.ParagraphProperties.ParagraphStyleId = new ParagraphStyleId
{
Val = "No Spacing"
};
}
}
// Create list of Parts ID needed to new footer
var listToAdd = new List<KeyValuePair<Type, Stream>>();
foreach (var idPart in firstFooter.Parts)
{
var part = firstFooter.GetPartById(idPart.RelationshipId);
if (part is ImagePart)
{
footerParts.AddNewPart<ImagePart>("image/png", idPart.RelationshipId);
listToAdd.Add(new KeyValuePair<Type, Stream>(typeof (ImagePart), part.GetStream()));
}
else if (part is DiagramStylePart)
{
footerParts.AddNewPart<DiagramStylePart>(idPart.RelationshipId);
listToAdd.Add(new KeyValuePair<Type, Stream>(typeof (DiagramStylePart), part.GetStream()));
}
else if (part is DiagramColorsPart)
{
footerParts.AddNewPart<DiagramColorsPart>(idPart.RelationshipId);
listToAdd.Add(new KeyValuePair<Type, Stream>(typeof (DiagramColorsPart),
part.GetStream()));
}
else if (part is DiagramDataPart)
{
footerParts.AddNewPart<DiagramDataPart>(idPart.RelationshipId);
listToAdd.Add(new KeyValuePair<Type, Stream>(typeof (DiagramDataPart), part.GetStream()));
}
else if (part is DiagramLayoutDefinitionPart)
{
footerParts.AddNewPart<DiagramStylePart>(idPart.RelationshipId);
listToAdd.Add(new KeyValuePair<Type, Stream>(typeof (DiagramStylePart), part.GetStream()));
}
else if (part is DiagramPersistLayoutPart)
{
footerParts.AddNewPart<DiagramPersistLayoutPart>(idPart.RelationshipId);
listToAdd.Add(new KeyValuePair<Type, Stream>(typeof (DiagramPersistLayoutPart),
part.GetStream()));
}
}
// Foreach ID, copy stream to new footer
var i = 0;
foreach (var idPart in footerParts.Parts)
{
var part = footerParts.GetPartById(idPart.RelationshipId);
if (part.GetType() == listToAdd[i].Key)
{
part.FeedData(listToAdd[i].Value);
}
i++;
}
}
else
{
mainPart.DeleteParts(mainPart.FooterParts);
var sectToRemovePrs = mainPart.Document.Body.Descendants<SectionProperties>();
foreach (var sectPr in sectToRemovePrs)
{
// Delete reference of footer
sectPr.RemoveAllChildren<FooterReference>();
}
return;
}
}
// Get all sections, and past footer to each section (Page)
var sectPrs = mainPart.Document.Body.Descendants<SectionProperties>();
foreach (var sectPr in sectPrs)
{
// Delete old reference
sectPr.RemoveAllChildren<FooterReference>();
// Add new footer reference
sectPr.PrependChild(new FooterReference { Id = rId });
}
}
}
Sorry for my English, if you have any questions, let me know.
Bye.
来源:https://stackoverflow.com/questions/46560269/copy-header-and-footer-to-all-other-documents-openxml