/*************************************************************************** Copyright (c) Microsoft Corporation 2011. This code is licensed using the Microsoft Public License (Ms-PL). The text of the license can be found here: http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx ***************************************************************************/ using System.Linq; using System.Xml.Linq; using System.Collections.Generic; using DocumentFormat.OpenXml.Packaging; namespace OpenXmlPowerTools { public enum HeaderType { Default, First, Even } /// /// Provides access to header operations /// public class HeaderAccessor { private const string defaultHeaderType = "default"; private static XNamespace ns; private static XNamespace relationshipns; private static XNamespace officens; private static XNamespace vmlns; private static XNamespace wordns; static HeaderAccessor() { ns = "http://schemas.openxmlformats.org/wordprocessingml/2006/main"; relationshipns = "http://schemas.openxmlformats.org/officeDocument/2006/relationships"; officens = "urn:schemas-microsoft-com:office:office"; vmlns = "urn:schemas-microsoft-com:vml"; wordns = "urn:schemas-microsoft-com:office:word"; } /// /// Elements tagged as section properties /// /// IEnumerable<XElement> containing all the section properties elements found it in the document private static IEnumerable SectionPropertiesElements(WordprocessingDocument document) { XDocument mainDocument = document.MainDocumentPart.GetXDocument(); IEnumerable results = mainDocument .Descendants(ns + "p") .Elements(ns + "pPr") .Elements(ns + "sectPr"); if (results.Count() == 0) results = mainDocument.Root.Elements(ns + "body").Elements(ns + "sectPr"); return results; } /// /// Adds a new header reference in the section properties /// /// The header part type /// the header part id public static void AddHeaderReference(WordprocessingDocument document, HeaderType type, string headerPartId, int sectionIndex) { // If the document does not have a property section a new one must be created if (SectionPropertiesElements(document).Count() == 0) { AddDefaultSectionProperties(document); } string typeName = ""; switch ((HeaderType)type) { case HeaderType.First: typeName = "first"; break; case HeaderType.Even: typeName = "even"; break; case HeaderType.Default: typeName = "default"; break; } XElement sectionPropertyElement = SectionPropertiesElements(document).Skip(sectionIndex).FirstOrDefault(); if (sectionPropertyElement != null) { sectionPropertyElement.Add( new XElement(ns + "headerReference", new XAttribute(ns + "type", typeName), new XAttribute(relationshipns + "id", headerPartId))); if (sectionPropertyElement.Element(ns + "titlePg") == null) sectionPropertyElement.Add( new XElement(ns + "titlePg") ); } document.MainDocumentPart.PutXDocument(); } /// /// Adds a new header part in the document /// /// The footer part type /// A XDocument contaning the added header public static XDocument AddNewHeader(WordprocessingDocument document, HeaderType type) { // Creates the new header part HeaderPart newHeaderPart = document.MainDocumentPart.AddNewPart(); XDocument emptyHeader = CreateEmptyHeaderDocument(); newHeaderPart.PutXDocument(emptyHeader); string newHeaderPartId = document.MainDocumentPart.GetIdOfPart(newHeaderPart); AddHeaderReference(document, type, newHeaderPartId, 0); return emptyHeader; } /// /// Creates an empty header document /// /// A XDocument containing the xml of an empty header part private static XDocument CreateEmptyHeaderDocument() { return new XDocument( new XElement(ns + "hdr", new XAttribute(XNamespace.Xmlns + "w", ns), new XAttribute(XNamespace.Xmlns + "r", relationshipns), new XAttribute(XNamespace.Xmlns + "o", officens), new XAttribute(XNamespace.Xmlns + "v", vmlns), new XAttribute(XNamespace.Xmlns + "w10", wordns) ) ); } /// /// Header reference nodes inside the document /// /// The header part type /// XElement containing the part reference in the document public static XElement GetHeaderReference(WordprocessingDocument document, HeaderType type, int sectionIndex) { XDocument mainDocument = document.MainDocumentPart.GetXDocument(); XName headerReferenceTag = ns + "headerReference"; XName typeTag = ns + "type"; string typeName = ""; switch (type) { case HeaderType.First: typeName = "first"; break; case HeaderType.Even: typeName = "even"; break; case HeaderType.Default: typeName = "default"; break; } XElement sectionPropertyElement = SectionPropertiesElements(document).Skip(sectionIndex).FirstOrDefault(); if (sectionPropertyElement != null) { return sectionPropertyElement.Descendants().Where(tag => (tag.Name == headerReferenceTag) && (tag.Attribute(typeTag).Value == typeName)).FirstOrDefault(); } return null; } /// /// Get the specified header from the document /// /// The header part type /// A XDocument containing the header public static XDocument GetHeader(WmlDocument doc, HeaderType type, int sectionIndex) { using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc)) using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument()) { OpenXmlPart header = GetHeaderPart(document, type, sectionIndex); if (header != null) return header.GetXDocument(); return null; } } public static XDocument GetHeader(WordprocessingDocument document, HeaderType type, int sectionIndex) { OpenXmlPart header = GetHeaderPart(document, type, sectionIndex); if (header != null) return header.GetXDocument(); return null; } /// /// The specified header part from the document /// /// The header part type /// A OpenXmlPart containing the header part public static OpenXmlPart GetHeaderPart(WordprocessingDocument document, HeaderType type, int sectionIndex) { // look in the section properties of the main document part, the respective Header // needed to extract XElement headerReferenceElement = GetHeaderReference(document, type, sectionIndex); if (headerReferenceElement != null) { // get the relation id of the Header part to extract from the document string relationId = headerReferenceElement.Attribute(relationshipns + "id").Value; return document.MainDocumentPart.GetPartById(relationId); } else return null; } /// /// Removes the specified header in the document /// /// The header part type public void RemoveHeader(WmlDocument doc, HeaderType type, int sectionIndex) { using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc)) using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument()) { OpenXmlPart headerPart = GetHeaderPart(document, type, sectionIndex); headerPart.RemovePart(); } } /// /// Set a new header in a document /// /// XDocument containing the header to add in the document /// The header part type public static OpenXmlPowerToolsDocument SetHeader(WmlDocument doc, XDocument header, HeaderType type, int sectionIndex) { using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc)) { using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument()) { // Removes the reference in the document.xml and the header part if those already // exist XElement headerReferenceElement = GetHeaderReference(document, type, sectionIndex); if (headerReferenceElement != null) { GetHeaderPart(document, type, sectionIndex).RemovePart(); headerReferenceElement.Remove(); } // Add the new header HeaderPart headerPart = document.MainDocumentPart.AddNewPart(); headerPart.PutXDocument(header); // Creates the relationship of the header inside the section properties in the document string relID = document.MainDocumentPart.GetIdOfPart(headerPart); AddHeaderReference(document, type, relID, sectionIndex); // add in the settings part the EvendAndOddHeaders. this element // allow to see the odd and even headers and headers in the document. SettingAccessor.AddEvenAndOddHeadersElement(document); } return streamDoc.GetModifiedDocument(); } } /// /// Adds a default sectPr element into the main document /// private static void AddDefaultSectionProperties(WordprocessingDocument document) { XDocument mainDocument = document.MainDocumentPart.GetXDocument(); mainDocument.Element(ns + "body").Add( new XElement(ns + "sectPr") ); } } }