none
FlatOPC / WordOpenXML changes not updating in header RRS feed

  • Question

  • I have a VSTO Word add-in that takes the FlatOPC content for the document, passes it to some external OpenXML processing and gives me back modified FlatOPC to update the active document with.  It works great for the document body, but fails to update the headers.

    I have boiled it down to the following code that demonstrates the problem:

    private void ModifyTest() {
    	var doc = Globals.ThisAddIn.Application.ActiveDocument;
    	var docRange = doc.Range();
    	var flat = docRange.WordOpenXML;
    
    	const string find = "<w:t>Foo</w:t>";
    	const string replace = "<w:t>Bar</w:t>";
    	var flatReplace = flat.Replace(find, replace);
    	if(!flatReplace.Contains("Bar")) {
    		throw new Exception("You have to type Foo in the document.");
    	}
    
    	docRange.InsertXML(flatReplace);
    }

    If you type "Foo" into the body and run this code, you'll notice it changes to "Bar".  Do the same thing in the header and nothing happens.

    I suspect that InsertXML is ignoring package parts that aren't document.xml ?  If so, I'm not sure why they're included in the WordOpenXML, and I'm unsure how to proceed.

    It is important that the external processing I do receives the full FlatOPC.


    • Edited by Phlow2001 Tuesday, June 3, 2014 10:59 PM Change function name to represent current code.
    Tuesday, June 3, 2014 10:57 PM

Answers

  • Hi Phlow

    I highly recommend you inspect the Package contents of a document similar to what you need to work with. Rename it with the *.zip extension and you can view all the files and how they're put together.

    Office Open XML uses RELATIONSHIPS to "glue" the various files together. Relationships can be found in the *.rels files. There will be an ID, on the one hand, and a file name, on the other. The ID value for a header, for example, will be stored in a section break element in document.xml. Look up that ID in the document.xml.rels file and you'll see the "path" to that header.xml file.

    All of this is reflected in the flat OPC.


    Cindy Meister, VSTO/Word MVP, my blog

    Saturday, June 7, 2014 4:30 PM
    Moderator

All replies

  • Well, we unfortunately cannot run your sample code since you don't provide the class "flat"...

    .InsertXML is run on a RANGE object. If you provide ActiveDocument.Content (that's more correct than ActiveDocument.Range), then that's the StoryRange it will work on.

    If you want to affect a different StoryRange, such as a Header or Footer, then you need to call InsertXML on that Range, specifically.

    Word.Range rngHeader = doc.Sections[indexValue].Headers[indexValue - see WdHeaderFooter Enum].Range;


    Cindy Meister, VSTO/Word MVP, my blog

    Wednesday, June 4, 2014 3:40 PM
    Moderator
  • flat is just the string variable.  I have this code sitting in a ribbon class, and it's simply called in response to a button click.  Not sure what problem you're running into.  I can try to upload a sample project somewhere if you need.

    In any case, how do I go about getting the entire document's FlatOPC (or OpenXML, or Package), including the headers and footers, and then how do I get that entire document's FlatOPC back into Word?

    For some reason when I look at the Header's WordOpenXML property, the contents of that header are in a <w:document> element, not a <w:hdr> as I would have expected.

    Am I expected to parse the FlatOPC of each header and footer, figure out how its w:document is related to the main document's w:document and piecemeal try to construct a proper Package?  Then do the same thing in reverse?  Surely there's got to be a better way.

    Thank you for your time.

    Wednesday, June 4, 2014 7:36 PM
  • InsertXML is not a panacea.

    For example

    If your FlatOPC contains the XML for a CustomXMLPart, what happens to that part? I think it probably disappears. So what happens to anything that references that part?

    If your FlatOPC has a document.xml part containg the text "Insert me!" and you InsertXML the file into a range in a header, should the text "INsert me!" appear in the header, or in the body of the document?

    What happens if the FlatOPC contains style defintions that conflict with definitions that are in the document you're inserting into? 

    ... And so on.

    I do not think you will find detailed documentation of how this works, or is even supposed to work, anywhere. 

    If so, it's probably best to assume to restrict the use of InsertXML to very simple scenarios where
     a. the XML is "simple" (not sure how you could pin that down) and 
     b. you can test your code and its impact to your satisfaction


    Peter Jamieson

    Wednesday, June 4, 2014 11:04 PM
  • Hi Phlow

    Mmm, it's a matter of how you view the way it works. In order to get the WordOpenXML you requested Range.WordOpenXML, I assume? As far as Word is concerned, all it needs to deliver is the valid WordOpenXML to define the RANGE (not the Story in which it stands) that can be inserted back into any Word document at any RANGE. And the correct format for such WordOpenXML is the same as for an entire document.

    If you request the WordOpenXML of the entire document - Document.Content.WordOpenXML - then you'll get the the definition of the Zip package in an XML string. Since each header and footer is saved as a separate file in the Zip package, you can identify the file from the package element, for example: <pkg:part pkg:name="/word/header2.xml"...

    And then you do get the w:hdr element you expect: <pkg:xmlData><w:hdr ...


    Cindy Meister, VSTO/Word MVP, my blog

    Friday, June 6, 2014 3:15 PM
    Moderator
  • How would I associate the package part for a header /word/header2.xml with the correct doc.Sections[].Headers[].Range ?  There doesn't seem to be any identifying information to connect them.  Like you say, the WordOpenXML is constructed so as to be plugged in at any range.

    The only thing I can think of is tracking the headers/footers/sections I modify in OpenXML by index, find them in Word, transform the w:hdr / w:ftr section into w:document's and update the relevant ranges.

    Is there really no better way?

    Thanks for your time

    Saturday, June 7, 2014 12:12 AM
  • Hi Phlow

    I highly recommend you inspect the Package contents of a document similar to what you need to work with. Rename it with the *.zip extension and you can view all the files and how they're put together.

    Office Open XML uses RELATIONSHIPS to "glue" the various files together. Relationships can be found in the *.rels files. There will be an ID, on the one hand, and a file name, on the other. The ID value for a header, for example, will be stored in a section break element in document.xml. Look up that ID in the document.xml.rels file and you'll see the "path" to that header.xml file.

    All of this is reflected in the flat OPC.


    Cindy Meister, VSTO/Word MVP, my blog

    Saturday, June 7, 2014 4:30 PM
    Moderator