Lets Learn

Opinion Matters

Archive for the ‘Word’ Category

Custom UI part In Word and Open XML SDK 2.0

Posted by Ankush on February 24, 2011

Consider a scienrio you have a Word 2010 document in which you aretrying to custmization by adding custom UI part and you want to open this document in Open XML SDK, it WILL NOT WORK.

Why….?

Lets try this:

Create a new Word 2010 document and add a custom UI part [ You can use custom UI editor tool to do this]. Use the following XML to do the ribbon custmization.

<?xml version=”1.0″ encoding=”UTF-8″?>
<customUI xmlns=”http://schemas.microsoft.com/office/2009/07/customui“>
<ribbon>
<tabs>
<tab idMso=”TabDeveloper” visible=”false” />
<tab idMso=”TabReferences” visible=”false” />
</tabs>
</ribbon>
</customUI>

Now if you open this document using Open XML SDK 2.0, you will get an error message.

WordprocessingDocument doc = WordprocessingDocument.Open(“<Path of the document>”, false);

Exception Message : “Specified argument was out of the range of valid values.Parameter name: relationshipType”

Call Stack:

DocumentFormat.OpenXml.Packaging.WordprocessingDocument.CreatePartCore(String relationshipType)
DocumentFormat.OpenXml.Packaging.OpenXmlPartContainer.CreateOpenXmlPart(String relationshipType)DocumentFormat.OpenXml.Packaging.OpenXmlPartContainer.LoadReferencedPartsAndRelationships(OpenXmlPackage openXmlPackage, OpenXmlPart sourcePart, ackageRelationshipCollection
relationshipCollection, Dictionary`2 loadedParts)
DocumentFormat.OpenXml.Packaging.OpenXmlPackage.Load()
DocumentFormat.OpenXml.Packaging.OpenXmlPackage.OpenCore(Stream stream, Boolean readWriteMode)
DocumentFormat.OpenXml.Packaging.WordprocessingDocument.Open(Stream stream, Boolean isEditable, OpenSettings openSettings)DocumentFormat.OpenXml.Packaging.WordprocessingDocument.Open(Stream stream, Boolean isEditable)

Lets get into more detail.

If you look into the callstack, it is failing in CreatePartCore function. So I used .net reflector tool and anlyzed the Open XML SDK assembly i.e. defination of CreatePartCore. This is what I see:

The relationship namespace for Office 2010 is “http://schemas.microsoft.com/office/2007/relationships/ui/extensibility” and if you look at the image, it is not included. In result, you get an exception.

This is all about the problem.

Solution: The only solution which will work her to create an addin and then do the ribbon customization.

Posted in Open XML SDK, Word | Tagged: , , , | 1 Comment »

Content Controls- A Complete Summary

Posted by Ankush on October 22, 2010

While generating a document from a database, it is very important that how you have designed the document. If you have a very good template then the insertion of the data becomes very easy. Word provides a very nice feature “Content Controls” to make this task easy. This blog post provides a collection of links which you can use .

So what is a Content Control. Here I what MSDN doc says:

Content controls are bounded and potentially labeled regions in a document that serve as containers for specific types of content. Individual content controls can contain content such as dates, lists, or paragraphs of formatted text. In some cases, content controls might remind you of forms. However, they are much more powerful, flexible, and useful because they enable you to create rich, structured blocks of content. Content controls also build on the custom XML support introduced in Microsoft Office Word 2003. Content controls enable you to author templates that insert well-defined blocks into your documents. Content controls enable you to:

• Specify structured regions in a template. Each structured region has its own unique ID so that you can read from and write to it. Examples of types of structured regions (or content controls) are combo boxes, pictures, text blocks, and calendars.

• Determine the behavior of content controls. Each content control takes up a portion of a document and, as the template author, you can specify what each region does. For example, if you want a region of your template to be a calendar, you insert a calendar content control in that area of the document, which automatically determines what that block of content does. Similarly, if you want a section of a template to display an image, create a picture content control in that area. In this way, you can build a template with predefined block types.

• Restrict the content of content controls. Each content control can be restricted, so that it cannot be deleted or edited. This is useful if, for example, you have copyright information in a template that the user should be able to read but not edit. You can also lock a template’s content so that a user does not accidentally delete portions of it. This makes templates more robust than in previous versions.

• Map the contents of a content control to data in a custom XML part that is stored with the document. For example, if you insert a document parts content control that contains a table of stock prices, you can map the table cells to nodes in an XML file that contain the current stock prices. When the prices change, an add-in can programmatically update the attached XML file, which is bound to each cell, and the new, updated prices automatically appear in the table.

The easiest way to create a content control is through the user interface (although you can also create them programmatically). To create a content control through the user interface (UI), select the text that you want to turn into a content control and then choose the content control type you want from the content controls section of the Developer ribbon. This creates a content control around the selected text.

Content Controls are a powerful features when it comes to feeding the data into document in an ASP.NET app. If you have created a document template and content control’s mapping is set then you can just replace one XML file and Word will pick the new data.

So here is the list.

Goal: Get the data from SQL Server and feed the Word document. The application is a Web application.

Solution: Create a Word template with content controls.  Bound them with an XML file. Use Open XML to manipulate the document and change the content of the XML file. The advantage of using content control is, they can be easily bound  to an XML file.

• Create a new Word document, drag few content controls onto the document surface. Create an XML file and create a node for every content control

Data-driven document generation with Word 2007 and the Office XML File Formats: Part 1
http://blogs.msdn.com/erikaehrli/archive/2006/08/11/word2007DataDocumentGenerationPart1.aspx

• There are 2 ways by which you do the mapping [ Nodes <-> Content Control]. Using Code, which is already  explained in the above article. If you would like to use an application, there is sample application available which can help you.

Word 2007 Content Control Toolkit
http://www.codeplex.com/wikipage?ProjectName=dbeOnce this is done, the sample XML file which you created, will be a part of the  document package, so you just need to change the content of the XML nodes and when you will open the document, it will reflect the dynamic data.

• Now you need to use Open XML, get the data from SQL and replace the XML contents it in the document. Following article  explains this[It has the sample code as well]

Data-driven document generation with Word 2007 and the Office XML File Formats: Part 2
http://blogs.msdn.com/erikaehrli/archive/2006/08/11/word2007DataDocumentGenerationPart2.aspxCreting documents by using Open XML Format SDK 2.0 (Part 3 of 3)
http://msdn.microsoft.com/en-us/library/dd469465.aspx#CreateDocswithOpenXMLSDK_TakingAdvantageofBoundContentControlsIf you would like to do this through Open XML SDK 2.0, then following article explains about this.

Creating Data-Bound Content Controls using the Open XML SDK and LINQ to XML
http://blogs.msdn.com/ericwhite/archive/2008/10/19/creating-data-bound-content-controls-using-the-open-xml-sdk-and-linq-to-xml.aspxTaking Advantage of Bound Content Controls
http://blogs.msdn.com/brian_jones/archive/2009/01/05/taking-advantage-of-bound-content-controls.aspx
So basically once the template is created, you can use Open XML SDK and do something like. Here I simply get the xml, delete the old XML file and add the new one.

========
string templatePath = Server.MapPath(“./Templates/ModelTemplate.docx”);
string custXMLFilePath = Server.MapPath(“./CustomXML/Model.xml”);
using (wdDoc = OpenXML.WordprocessingDocument.Open(templatePath, true))
{
OpenXML.MainDocumentPart mainPart = wdDoc.MainDocumentPart;
mainPart.DeleteParts<OpenXML.CustomXmlPart>(mainPart.CustomXmlParts);
XmlDataDocument custXML = new XmlDataDocument();
custXML.Load(custXMLFilePath);
OpenXML.CustomXmlPart custXMLPart = mainPart.AddNewPart<OpenXML.CustomXmlPart>();
using (Stream s = custXMLPart.GetStream(FileMode.Create))
{
custXML.Save(s);
}
}
=========
Inserting Repeating Data Items into a Word 2007 Table by Using the Open XML API
http://msdn.microsoft.com/en-us/library/cc197932.aspxCreating Valid Open XML Documents by Using the Validation Tools in the Open XML Format SDK
http://msdn.microsoft.com/en-us/library/dd633612.aspx

Let me know what you think about this::

Ankush

Posted in Open XML SDK, Word | Tagged: , , , | Leave a Comment »

AltChunk – An Interesting Scenario

Posted by Ankush on October 22, 2010

Merging multiple word documents into a single document is a very common requirement.  This  becomes a bit complex when you are trying to do this in a Web application which should not automates Office (http://support.microsoft.com/kb/257757). As an alternative, Microsoft has introduced Open XML SDK which you can use to read/write the data into Office application.  altChunk, which is a special feature of Open XML word processing markup that enables you to embed an entire Open XML document or an html page at a specific location in a document.

So basically there are 3 ways to merge the documents in a non-interactive environment:

1. Use AltChunk
2. Manually merge the document
3. Use Power Tools

By far the first option of using altChunks is the easiest method for merging multiple documents together. Not only can altChunks import other WordprocessingML documents, but it can also import html, xml, rtf, or plain text. Manually merging multiple documents together is feasible, but requires you to handle a number of issues. For example, you will need to manually merge and deal with conflicts related to styles, bullets and numbering, comments, headers and footers, etc.

Now lets consider a scenario and the solution:

Scenario:

Consider a scenario where I have merge multiple documents into one. These documents are coming from different sources and after merging, it should be sent to the management. The application should be a web application and no temp file should be generated.

Solution:

My solution contains

1. Test.docx the source document. They can be multiple which are supposed to be merged. In my example I am assuming its one
2. Test1.docx. The merged document which contains the content control [kind of bookmark] so that source documents can be inserted easily. I will create a separate blog as how you work with content control

Here is the complete code. Remarks are added to explain the code and the flow.

// Function which Opens the Document and Modify it

private static void OpenAndModifyDocument()
{

//  Open the document using Stream and bytes
byte[] byteArray = File.ReadAllBytes(“Test.docx”);

using (MemoryStream mem = new MemoryStream())
{
mem.Write(byteArray, 0, (int)byteArray.Length);
// Modify the document. For ex:: I am inserting a Paragrapgh
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(mem, true))
{
wordDoc.MainDocumentPart.Document.Body.InsertAt(
new Paragraph(
new Run(
new Text(“Newly inserted paragraph.”))), 0);
}
SaveDocument(mem);

}
}
// Function to do Merging with the Stream

Private static void SaveDocument(MemoryStream ms)
{
// Test1.docx is the templates which contains different placeholders (basically a content control) where I am going to the different document streams
using (WordprocessingDocument myDoc = WordprocessingDocument.Open(“Test1.docx”, true))
{
MainDocumentPart mainPart = myDoc.MainDocumentPart;
// Make sure to have a unique AltChunk Id
string altChunkId = “AltChunkId” + 30;
// Create an AltChunk element
AlternativeFormatImportPart chunk = mainPart.AddAlternativeFormatImportPart(AlternativeFormatImportPartType.WordprocessingML, altChunkId);
// Here we can also use FeedData method to pass the document stream into AltChunk but that requires a physical file . Hence I am using Streams
Stream chunkStream = chunk.GetStream(FileMode.Create, FileAccess.Write);
StreamWriter stringStream = new StreamWriter(chunkStream);
ms.WriteTo(chunkStream);
AltChunk altChunk = new AltChunk();
altChunk.Id = altChunkId;
// Find the Content Controls. I am assuming that there is only one content control but if have multiples then you just modify this query
SdtBlock sdt = mainPart.Document.Descendants<SdtBlock>().First();
OpenXmlElement parent = sdt.Parent;
// Insert the AltChunk element and remove the content control
parent.InsertAfter(altChunk, sdt);
sdt.Remove();
mainPart.Document.Save();

}

}

Please note that until a document that contains altChunk elements is opened and saved in Office, it still contains the altChunk parts, and not normal WordprocessingML markup of paragraphs, runs, and text elements.  The solution with SharePoint 2010 is that you can use Word Automation Services to update the documents that contain altChunk elements.  After Word Automation Services processes it, the document will contain paragraphs, runs, and text elements.

Let me know about your thoughts!!!

Posted in Open XML SDK, Word | Tagged: , , | 14 Comments »

 
%d bloggers like this: