Merge 3 document, discard footer or header separatly into one document

Home Forums Open-Xml-PowerTools Merge 3 document, discard footer or header separatly into one document

Tagged: , , ,

This topic contains 6 replies, has 2 voices, and was last updated by  josh.gomez 8 years, 1 month ago.

Viewing 7 posts - 1 through 7 (of 7 total)
  • Author
    Posts
  • #2485

    josh.gomez
    Participant

    Hello,

    I need help on how to merge 3 documents. One that only holds the footer and the other one hold the header.

    It kind of works but it show some kind of message in the word that the section is ongoing or something. Which is only visible when editing the document. It seems like it a extra copy of the section or something. Could you help me with this?

    I have modified the source:

        public partial class Source
        {
            public bool DiscardHeadersInKeptSections { get; set; }
            public bool DiscardFootersInKeptSections { get; set; }
    
            public bool IsDiscardingParts
            {
                get
                {
                    return DiscardHeadersInKeptSections || DiscardFootersInKeptSections;
                }
            }
        }
    
    
        public static partial class DocumentBuilder
        {
            private static void RemoveHeadersFromSections(WordprocessingDocument doc)
            {
                var mdXDoc = doc.MainDocumentPart.GetXDocument();
                var sections = mdXDoc.Descendants(W.sectPr).ToList();
                foreach (var sect in sections)
                {
                    sect.Elements(W.headerReference).Remove();
                }
    
                doc.MainDocumentPart.PutXDocument();
            }
    
            private static void RemoveFootersFromSections(WordprocessingDocument doc)
            {
                var mdXDoc = doc.MainDocumentPart.GetXDocument();
                var sections = mdXDoc.Descendants(W.sectPr).ToList();
                foreach (var sect in sections)
                {
                    sect.Elements(W.footerReference).Remove();
                }
    
                doc.MainDocumentPart.PutXDocument();
            }
    
            private static void ProcessSectionsForLinkToPreviousHeaders(WordprocessingDocument doc)
            {
                CachedHeaderFooter[] cachedHeaderFooter = new[]
                {
                    new CachedHeaderFooter() { Ref = W.headerReference, Type = "first" },
                    new CachedHeaderFooter() { Ref = W.headerReference, Type = "even" },
                    new CachedHeaderFooter() { Ref = W.headerReference, Type = "default" },
                };
    
                var mdXDoc = doc.MainDocumentPart.GetXDocument();
                var sections = mdXDoc.Descendants(W.sectPr).ToList();
                var firstSection = true;
                foreach (var sect in sections)
                {
                    if (firstSection)
                    {
                        var headerFirst = FindReference(sect, W.headerReference, "first");
                        var headerDefault = FindReference(sect, W.headerReference, "default");
                        var headerEven = FindReference(sect, W.headerReference, "even");
    
                        if (headerEven == null)
                        {
                            if (headerDefault != null)
                                AddReferenceToExistingHeaderOrFooter(doc.MainDocumentPart, sect, (string)headerDefault.Attribute(R.id), W.headerReference, "even");
                            else
                                InitEmptyHeaderOrFooter(doc.MainDocumentPart, sect, W.headerReference, "even");
                        }
    
                        if (headerFirst == null)
                        {
                            if (headerDefault != null)
                                AddReferenceToExistingHeaderOrFooter(doc.MainDocumentPart, sect, (string)headerDefault.Attribute(R.id), W.headerReference, "first");
                            else
                                InitEmptyHeaderOrFooter(doc.MainDocumentPart, sect, W.headerReference, "first");
                        }
    
                        foreach (var hf in cachedHeaderFooter)
                        {
                            if (sect.Elements(hf.Ref).FirstOrDefault(z => (string)z.Attribute(W.type) == hf.Type) == null)
                                InitEmptyHeaderOrFooter(doc.MainDocumentPart, sect, hf.Ref, hf.Type);
                            var reference = sect.Elements(hf.Ref).FirstOrDefault(z => (string)z.Attribute(W.type) == hf.Type);
                            if (reference == null)
                                throw new OpenXmlPowerToolsException("Internal error");
                            hf.CachedPartRid = (string)reference.Attribute(R.id);
                        }
    
                        firstSection = false;
                        continue;
                    }
                    else
                    {
                        CopyOrCacheHeaderOrFooter(doc, cachedHeaderFooter, sect, W.headerReference, "first");
                        CopyOrCacheHeaderOrFooter(doc, cachedHeaderFooter, sect, W.headerReference, "even");
                        CopyOrCacheHeaderOrFooter(doc, cachedHeaderFooter, sect, W.headerReference, "default");
                    }
                }
    
                doc.MainDocumentPart.PutXDocument();
            }
    
            private static void ProcessSectionsForLinkToPreviousFooters(WordprocessingDocument doc)
            {
                CachedHeaderFooter[] cachedHeaderFooter = new[]
                {
                    new CachedHeaderFooter() { Ref = W.footerReference, Type = "first" },
                    new CachedHeaderFooter() { Ref = W.footerReference, Type = "even" },
                    new CachedHeaderFooter() { Ref = W.footerReference, Type = "default" },
                };
    
                var mdXDoc = doc.MainDocumentPart.GetXDocument();
                var sections = mdXDoc.Descendants(W.sectPr).ToList();
                var firstSection = true;
                foreach (var sect in sections)
                {
                    if (firstSection)
                    {
                        var footerFirst = FindReference(sect, W.footerReference, "first");
                        var footerDefault = FindReference(sect, W.footerReference, "default");
                        var footerEven = FindReference(sect, W.footerReference, "even");
    
                        if (footerEven == null)
                        {
                            if (footerDefault != null)
                                AddReferenceToExistingHeaderOrFooter(doc.MainDocumentPart, sect, (string)footerDefault.Attribute(R.id), W.footerReference, "even");
                            else
                                InitEmptyHeaderOrFooter(doc.MainDocumentPart, sect, W.footerReference, "even");
                        }
    
                        if (footerFirst == null)
                        {
                            if (footerDefault != null)
                                AddReferenceToExistingHeaderOrFooter(doc.MainDocumentPart, sect, (string)footerDefault.Attribute(R.id), W.footerReference, "first");
                            else
                                InitEmptyHeaderOrFooter(doc.MainDocumentPart, sect, W.footerReference, "first");
                        }
    
                        foreach (var hf in cachedHeaderFooter)
                        {
                            if (sect.Elements(hf.Ref).FirstOrDefault(z => (string)z.Attribute(W.type) == hf.Type) == null)
                                InitEmptyHeaderOrFooter(doc.MainDocumentPart, sect, hf.Ref, hf.Type);
                            var reference = sect.Elements(hf.Ref).FirstOrDefault(z => (string)z.Attribute(W.type) == hf.Type);
                            if (reference == null)
                                throw new OpenXmlPowerToolsException("Internal error");
                            hf.CachedPartRid = (string)reference.Attribute(R.id);
                        }
    
                        firstSection = false;
                        continue;
                    }
                    else
                    {
                        CopyOrCacheHeaderOrFooter(doc, cachedHeaderFooter, sect, W.footerReference, "first");
                        CopyOrCacheHeaderOrFooter(doc, cachedHeaderFooter, sect, W.footerReference, "even");
                        CopyOrCacheHeaderOrFooter(doc, cachedHeaderFooter, sect, W.footerReference, "default");
                    }
                }
    
                doc.MainDocumentPart.PutXDocument();
            }
        }
    

    Line:393 in DocumentBuilder.cs

                                    if (source.KeepSections && source.IsDiscardingParts)
                                    {
                                        if(source.DiscardHeadersInKeptSections)
                                        {
                                            RemoveHeadersFromSections(doc);
                                        }
                                        else
                                        {
                                            ProcessSectionsForLinkToPreviousHeaders(doc);
                                        }
    
                                        if(source.DiscardFootersInKeptSections)
                                        {
                                            RemoveFootersFromSections(doc);
                                        }
                                        else
                                        {
                                            ProcessSectionsForLinkToPreviousFooters(doc);
                                        }
                                    }
                                    else if (source.KeepSections)
                                        ProcessSectionsForLinkToPreviousHeadersAndFooters(doc);
    
                                    List<XElement> contents = doc.MainDocumentPart.GetXDocument()
                                        .Root
                                        .Element(W.body)
                                        .Elements()
                                        .Skip(source.Start)
                                        .Take(source.Count)
                                        .ToList();
                                    try
                                    {
                                        AppendDocument(doc, output, contents, source.KeepSections, source.InsertId, images);
                                    }
                                    catch (DocumentBuilderInternalException dbie)
                                    {
                                        if (dbie.Message.Contains("{0}"))
                                            throw new DocumentBuilderException(string.Format(dbie.Message, sourceNum));
                                        else
                                            throw dbie;
                                    }
                                }
                            }
                        }
                        else
                        {
                            using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(source.WmlDocument))
                            using (WordprocessingDocument doc = streamDoc.GetWordprocessingDocument())
                            {
    #if TestForUnsupportedDocuments
                                // throws exceptions if a document contains unsupported content
                                TestForUnsupportedDocument(doc, sources.IndexOf(source));
    #endif
                                if (source.KeepSections && source.IsDiscardingParts)
                                {
                                    if(source.DiscardHeadersInKeptSections)
                                    {
                                        RemoveHeadersFromSections(doc);
                                    }
                                    else
                                    {
                                        ProcessSectionsForLinkToPreviousHeaders(doc);
                                    }
    
                                    if(source.DiscardFootersInKeptSections)
                                    {
                                        RemoveFootersFromSections(doc);
                                    }
                                    else
                                    {
                                        ProcessSectionsForLinkToPreviousFooters(doc);
                                    }
                                }
                                else if (source.KeepSections)
                                    ProcessSectionsForLinkToPreviousHeadersAndFooters(doc);
    

    How I use it:

    sources.Add(new Source(settings.TemplateFilePath, false));
    sources[0].DiscardFootersInKeptSections = true;
    sources[0].DiscardHeadersInKeptSections = true;
    
    sources.Add(new Source(tempHeaderPath, true) { DiscardFootersInKeptSections = true });
    sources.Add(new Source(tempFooterPath, true) { DiscardHeadersInKeptSections = true });
    • This topic was modified 8 years, 1 month ago by  josh.gomez.
    • This topic was modified 8 years, 1 month ago by  josh.gomez.
    • This topic was modified 8 years, 1 month ago by  josh.gomez.
    #2489

    josh.gomez
    Participant

    I could not edit the thread any more so I do another post with additional information.

    Here is the end of the document.xml

    
    <...>
    		<w:p w:rsidR="005C6B96" w:rsidRPr="00B14B81" w:rsidRDefault="005C6B96" w:rsidP="004F23F1"/>
    		<w:p w:rsidR="00077D08" w:rsidRDefault="00D14262">
    			<w:pPr>
    				<w:sectPr w:rsidR="00077D08" w:rsidSect="0018015B">
    					<w:footerReference w:type="even" r:id="rId7"/>
    					<w:footerReference w:type="default" r:id="rId8"/>
    					<w:headerReference w:type="first" r:id="rId9"/>
    					<w:footerReference w:type="first" r:id="rId10"/>
    					<w:type w:val="continuous"/>
    					<w:pgSz w:w="11906" w:h="16838" w:code="9"/>
    					<w:pgMar w:top="1418" w:right="1418" w:bottom="2552" w:left="1418" w:header="318" w:footer="851" w:gutter="0"/>
    					<w:cols w:space="708"/>
    					<w:titlePg/>
    					<w:docGrid w:linePitch="360"/>
    				</w:sectPr>
    			</w:pPr>
    			<w:r>
    				<w:t>Josh Gomez</w:t>
    			</w:r>
    			<w:bookmarkStart w:id="0" w:name="_GoBack"/>
    			<w:bookmarkEnd w:id="0"/>
    		</w:p>
    		<w:p w:rsidR="00D14262" w:rsidRDefault="00D14262"/>
    		<w:sectPr w:rsidR="00D14262" w:rsidSect="0018015B">
    			<w:footerReference w:type="even" r:id="rId11"/>
    			<w:footerReference w:type="default" r:id="rId12"/>
    			<w:footerReference w:type="first" r:id="rId13"/>
    			<w:type w:val="continuous"/>
    			<w:pgSz w:w="11906" w:h="16838" w:code="9"/>
    			<w:pgMar w:top="1418" w:right="1418" w:bottom="2552" w:left="1418" w:header="318" w:footer="851" w:gutter="0"/>
    			<w:cols w:space="708"/>
    			<w:titlePg/>
    			<w:docGrid w:linePitch="360"/>
    		</w:sectPr>
    	</w:body>
    </w:document>
    
    #2491

    Eric White
    Keymaster

    Hi,

    There is no functionality in DocumentBuilder to take the header from one section and the footer from another section. It is not a feature of DocumentBuilder. It is possible to manually write code to do this – it is probably only 30 or so lines of code. But you need to understand the below information.

    I am not clear on the error that you are seeing.

    Actually, sections / headers / footers are more complicated than would seem on first glance.

    First of all, there can be 1, 2, or 3 headers per section. Ditto for footers. Depending on default, even, or odd, then the others are set per some specific rules, documented in the standard. Further, sections can inherit from previous sections.

    In DocumentBuilder, there is a method, ProcessSectionsForLinkToPreviousHeadersAndFooters, which ‘normalizes’ headers and footers in sections. For instance, it makes sure that there are 3 headers and 3 footers per section, therefore the ‘interesting’ rules about how to determine the header or footer for a section are eliminated. Further, if a section inherits from a previous section, then the previous section’s headers and footers are placed in the section. After executing the method, every section has 3 headers and 3 footers, and no section inherits from a previous section.

    Then processing gets easier and more predictable within DocumentBuilder. Developers should be aware of these dynamics when using DocumentBuilder.

    Given my current schedule, I’m afraid I can’t debug the modifications to DocumentBuilder. It would take some time to get back into the internals of DocumentBuilder, and given what I need to get done, isn’t possible at the moment.

    You have an interesting use-case, and would be interested to hear more. Why do you need to get the header from one document, but the footer from another? Would love to hear the specific scenario. I love to learn new things about how people use Word.

    Cheers, Eric

    • This reply was modified 8 years, 1 month ago by  Eric White.
    #2494

    josh.gomez
    Participant

    Hello Eric White,

    Thanks for fast reply.

    The purpose is to have multiple footer and header documents, they will have same section settings I only want to combine different content stored in those document for easier modification where I can focus on making templates that only include a body.

    I could use your library too merge header and body and then using something else to combine the footer from another document.

    I have seen some example but it does not include images stored in the footer.
    Is it AltChunk I should use? Do you know any good example? Thanks.

    I also posted the question on StackOverflow:
    http://stackoverflow.com/questions/35873789/c-sharp-how-to-merge-3-documents-header-footer-and-body-separated-in-each-docu

    • This reply was modified 8 years, 1 month ago by  josh.gomez.
    #2528

    josh.gomez
    Participant

    I can’t edit anymore so I post again. I just want to say I solved the problem. First it was another “bug” which made the section references different.

    It was actually a duplicated which contained same section reference actually 6 reference in both section which was identical so I just had to search for the sections with duplicated id and remove the first one and it’s parent <w:pPr>.

    #2530

    Eric White
    Keymaster

    Sorry, not clear. Is it a bug in your code, or in DocumentBuilder?

    #2532

    josh.gomez
    Participant

    No it was not a bug in DocumentBuilder, I used the OpenXML library to remove header in the document which I stored footer and after I did the merge with DocumentBuilder but with the code above I don’t need to do that but I forgot to remove the method which made the document section sort “invalid” but it still “worked”.

    When I removed the method the section became a duplicate instead. So I just had to remove the duplicated section bind searching for duplicates.

    The only thing I need to delete now is the paragraph in header and footer document.
    and then merge with the code above and remove the duplicated section and it works.

Viewing 7 posts - 1 through 7 (of 7 total)

You must be logged in to reply to this topic.