Xml schema word 2010

Hello there I wish to create an XML Schema for word 2010 and specify that to a word document so that the word doc is now based on my own Custom XML schema and so that I can apply my own XML elements to that word file? There’s an option in the developer tab in MS word 2010 to apply your XML elements but for that you have to specify a XML schema. I have googled on creating custom xml schema for word 2010 it but no luck! Any thoughts are sample code would do a great favour Thanks in advance!

Kind Regards!

asked May 18, 2012 at 15:51

Muhammad Usman's user avatar

Muhammad UsmanMuhammad Usman

1711 gold badge4 silver badges20 bronze badges

3

answered May 18, 2012 at 16:05

Lars Hovden's user avatar

2

title description ms.date ms.topic dev_langs helpviewer_keywords author ms.author manager ms.technology ms.workload

Walkthrough: Bind content controls to custom XML parts

Learn how to bind content controls in a document-level customization for Word to XML data that is stored in the document.

02/02/2017

conceptual

VB

CSharp

PlainTextContentControl, binding to a custom XML part

custom XML parts, binding to content controls

content controls [Office development in Visual Studio], data binding

data binding [Office development in Visual Studio], content controls

DropDownListContentControl, binding items to a custom XML part

DatePickerContentControl, binding to a custom XML part

John-Hart

johnhart

jmartens

office-development

office

Walkthrough: Bind content controls to custom XML parts

[!INCLUDE Visual Studio]
This walkthrough demonstrates how to bind content controls in a document-level customization for Word to XML data that is stored in the document.

[!INCLUDEappliesto_wdalldoc]

Word enables you to store XML data, named custom XML parts, in a document. You can control the display of this data by binding content controls to elements in a custom XML part. The example document in this walkthrough displays employee information that is stored in a custom XML part. When you open the document, the content controls display the values of the XML elements. Any changes that you make to the text in the content controls are saved in the custom XML part.

This walkthrough illustrates the following tasks:

  • Adding content controls to the Word document in a document-level project at design time.

  • Creating an XML data file and an XML schema that defines the elements to bind to the content controls.

  • Attaching the XML schema to the document at design time.

  • Adding the contents of the XML file to a custom XML part in the document at run time.

  • Binding the content controls to elements in the custom XML part.

  • Binding a xref:Microsoft.Office.Tools.Word.DropDownListContentControl to a set of values that are defined in the XML schema.

    [!INCLUDEnote_settings_general]

Prerequisites

You need the following components to complete this walkthrough:

  • [!INCLUDEvsto_vsprereq]

  • Microsoft Word.

Create a new Word document project

Create a Word document that you will use in the walkthrough.

To create a new Word document project

  1. Create a Word document project with the name EmployeeControls. Create a new document for the solution. For more information, see How to: Create Office projects in Visual Studio.

    [!INCLUDEvsprvs] opens the new Word document in the designer and adds the EmployeeControls project to Solution Explorer.

Add content controls to the document

Create a table that contains three different types of content controls where the user can view or edit information about an employee.

To add content controls to the document

  1. In the Word document that is hosted in the [!INCLUDEvsprvs] designer, on the Ribbon, choose the Insert tab.

  2. In the Tables group, choose Table, and insert a table with 2 columns and 3 rows.

  3. Type text in the first column so that it resembles the following column:

    Employee Name
    Hire Date
    Title
  4. In the second column of the table, choose the first row (next to Employee Name).

  5. On the Ribbon, choose the Developer tab.

    [!NOTE]
    If the Developer tab is not visible, you must first show it. For more information, see How to: Show the developer tab on the ribbon.

  6. In the Controls group, choose the Text button PlainTextContentControl to add a xref:Microsoft.Office.Tools.Word.PlainTextContentControl to the first cell.

  7. In the second column of the table, choose the second row (next to Hire Date).

  8. In the Controls group, choose the Date Picker button DatePickerContentControl to add a xref:Microsoft.Office.Tools.Word.DatePickerContentControl to the second cell.

  9. In the second column of the table, choose the third row (next to Title).

  10. In the Controls group, choose the Drop-Down List button DropDownListContentControl to add a xref:Microsoft.Office.Tools.Word.DropDownListContentControl to the last cell.

    That is the entire user interface for this project. If you run the project now, you can type text in the first row and select a date in the second row. The next step is to attach the data that you want to display to the document in an XML file.

Create the XML data file

Typically, you will obtain XML data to store in a custom XML part from an external source, such as a file or a database. In this walkthrough, you create an XML file that contains the employee data, marked by elements that you will bind to the content controls in the document. To make the data available at run time, embed the XML file as a resource in the customization assembly.

To create the data file

  1. On the Project menu, choose Add New Item.

    The Add New Item dialog box appears.

  2. In the Templates pane, select XML File.

  3. Name the file employees.xml, and then choose the Add button.

    The employees.xml file opens in the Code Editor.

  4. Replace the contents of the employees.xml file with the following text.

    <?xml version="1.0" encoding="utf-8" ?>
    <employees xmlns="http://schemas.microsoft.com/vsto/samples">
      <employee>
        <name>Karina Leal</name>
        <hireDate>1999-04-01</hireDate>
        <title>Manager</title>
      </employee>
    </employees>
  5. In Solution Explorer, choose the employees.xml file.

  6. In the Properties window, select the Build Action property, and then change the value to Embedded Resource.

    This step embeds the XML file as a resource in the assembly when you build the project. This enables you to access the contents of the XML file at run time.

Create an XML Schema

If you want to bind a content control to a single element in a custom XML part, you do not have to use an XML schema. However, to bind the xref:Microsoft.Office.Tools.Word.DropDownListContentControl to a set of values, you must create an XML schema that validates the XML data file that you created earlier. The XML schema defines the possible values for the title element. You will bind the xref:Microsoft.Office.Tools.Word.DropDownListContentControl to this element later in this walkthrough.

To create an XML schema

  1. On the Project menu, choose Add New Item.

    The Add New Item dialog box appears.

  2. In the Templates pane, select XML Schema.

  3. Name the schema employees.xsd and choose the Add button.

    The schema designer opens.

  4. In Solution Explorer, open the shortcut menu for employees.xsd, and then choose View Code.

  5. Replace the contents of the employees.xsd file with the following schema.

    <?xml version="1.0" encoding="utf-8" ?>
    <xs:schema xmlns="http://schemas.microsoft.com/vsto/samples"
        targetNamespace="http://schemas.microsoft.com/vsto/samples"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        elementFormDefault="qualified">
      <xs:element name="employees" type="EmployeesType"></xs:element>
      <xs:complexType name="EmployeesType">
        <xs:all>
          <xs:element name="employee" type="EmployeeType"/>
        </xs:all>
      </xs:complexType>
      <xs:complexType name="EmployeeType">
        <xs:sequence>
          <xs:element name="name" type="xs:string" minOccurs="1" maxOccurs="1"/>
          <xs:element name="hireDate" type="xs:date" minOccurs="1" maxOccurs="1"/>
          <xs:element name="title" type="TitleType" minOccurs="1" maxOccurs="1"/>
        </xs:sequence>
      </xs:complexType>
      <xs:simpleType name="TitleType">
        <xs:restriction base="xs:string">
          <xs:enumeration value ="Engineer"/>
          <xs:enumeration value ="Designer"/>
          <xs:enumeration value ="Manager"/>
        </xs:restriction>
      </xs:simpleType>
    </xs:schema>
  6. On the File menu, click Save All to save your changes to the employees.xml and the employees.xsd files.

Attach the XML schema to the document

You must attach the XML schema to the document to bind the xref:Microsoft.Office.Tools.Word.DropDownListContentControl to the valid values of the title element.

To attach the XML schema to the document ( [!INCLUDEWord_15_short])

  1. Activate EmployeeControls.docx in the designer.

  2. On the Ribbon, choose the Developer tab, and then choose the Add-Ins button.

  3. In the Templates and Add-ins dialog box, choose the XML Schema tab, and then choose the Add Schema button.

  4. Browse to the employees.xsd schema you created earlier, which is located in your project directory, and then choose the Open button.

  5. Choose the OK button in the Schema Settings dialog box.

  6. Choose the OK button to close the Templates and Add-ins dialog box.

To attach the XML schema to the document (Word 2010)

  1. Activate EmployeeControls.docx in the designer.

  2. On the Ribbon, choose the Developer tab.

  3. In the XML group, choose the Schema button.

  4. In the Templates and Add-ins dialog box, choose the XML Schema tab, and then choose the Add Schema button.

  5. Browse to the employees.xsd schema that you created earlier, which is located in your project directory, and choose the Open button.

  6. Choose the OK button in the Schema Settings dialog box.

  7. Choose the OK button to close the Templates and Add-ins dialog box.

    The XML Structure task pane opens.

  8. Close the XML Structure task pane.

Add a custom XML part to the document

Before you can bind the content controls to the elements in the XML file, you must add the contents of the XML file to a new custom XML part in the document.

To add a custom XML part to the document

  1. In Solution Explorer, open the shortcut menu for ThisDocument.cs or ThisDocument.vb, and then choose View Code.

  2. Add the following declarations to the ThisDocument class. This code declares several objects that you will use to add a custom XML part to the document.

    C#

    :::code language=»csharp» source=»../vsto/codesnippet/CSharp/EmployeeControls/ThisDocument.cs» id=»Snippet1″:::

    VB

    :::code language=»vb» source=»../vsto/codesnippet/VisualBasic/EmployeeControls/ThisDocument.vb» id=»Snippet1″:::

  3. Add the following method to the ThisDocument class. This method gets the contents of the XML data file that is embedded as a resource in the assembly, and returns the contents as an XML string.

    C#

    :::code language=»csharp» source=»../vsto/codesnippet/CSharp/EmployeeControls/ThisDocument.cs» id=»Snippet3″:::

    VB

    :::code language=»vb» source=»../vsto/codesnippet/VisualBasic/EmployeeControls/ThisDocument.vb» id=»Snippet3″:::

  4. Add the following method to the ThisDocument class. The AddCustomXmlPart method creates a new custom XML part that contains an XML string that is passed to the method.

    To ensure that the custom XML part is only created once, the method creates the custom XML part only if a custom XML part with a matching GUID does not already exist in the document. The first time this method is called, it saves the value of the xref:Microsoft.Office.Core._CustomXMLPart.Id%2A property to the employeeXMLPartID string. The value of the employeeXMLPartID string is persisted in the document because it was declared by using the xref:Microsoft.VisualStudio.Tools.Applications.Runtime.CachedAttribute attribute.

    C#

    :::code language=»csharp» source=»../vsto/codesnippet/CSharp/EmployeeControls/ThisDocument.cs» id=»Snippet4″:::

    VB

    :::code language=»vb» source=»../vsto/codesnippet/VisualBasic/EmployeeControls/ThisDocument.vb» id=»Snippet4″:::

Bind the content controls to elements in the custom XML part

Bind each content control to an element in the custom XML part by using the XMLMapping property of each content control.

To bind the content controls to elements in the custom XML part

  1. Add the following method to the ThisDocument class. This method binds each content control to an element in the custom XML part and sets the date display format of the xref:Microsoft.Office.Tools.Word.DatePickerContentControl.

    C#

    :::code language=»csharp» source=»../vsto/codesnippet/CSharp/EmployeeControls/ThisDocument.cs» id=»Snippet5″:::

    VB

    :::code language=»vb» source=»../vsto/codesnippet/VisualBasic/EmployeeControls/ThisDocument.vb» id=»Snippet5″:::

Run your code when the document is opened

Create the custom XML part and bind the custom controls to the data when the document is opened.

To run your code when the document is opened

  1. Add the following code to the ThisDocument_Startup method of the ThisDocument class. This code gets the XML string from the employees.xml file, adds the XML string to a new custom XML part in the document, and binds the content controls to elements in the custom XML part.

    C#

    :::code language=»csharp» source=»../vsto/codesnippet/CSharp/EmployeeControls/ThisDocument.cs» id=»Snippet2″:::

    VB

    :::code language=»vb» source=»../vsto/codesnippet/VisualBasic/EmployeeControls/ThisDocument.vb» id=»Snippet2″:::

Test the project

When you open the document, the content controls display data from the elements in the custom XML part. You can click the xref:Microsoft.Office.Tools.Word.DropDownListContentControl to select one of three valid values for the title element, which are defined in the employees.xsd file. If you edit the data in any of the content controls, the new values are saved in the custom XML part in the document.

To test the content controls

  1. Press F5 to run the project.

  2. Verify that the table in the document resembles the following table. Each of the strings in the second column is obtained from an element in the custom XML part in the document.

    Column Value
    Employee Name Karina Leal
    Hire Date April 1, 1999
    Title Manager
  3. Choose the cell to the right of the Employee Name cell and type a different name.

  4. Choose the cell to the right of the Hire Date cell and select a different date in the date picker.

  5. Choose the cell to the right of the Title cell and select a new item from the drop-down list.

  6. Save and close the document.

  7. In File Explorer, open the binDebug folder under the location of your project.

  8. Open the shortcut menu for EmployeeControls.docx and then choose Rename.

  9. Name the file EmployeeControls.docx.zip.

    The EmployeeControls.docx document is saved in the Open XML Format. By renaming this document with the .zip file name extension, you can examine the contents of the document. For more information about Open XML, see the technical article Introducing the Office (2007) Open XML file formats.

  10. Open the EmployeeControls.docx.zip file.

  11. Open the customXml folder.

  12. Open the shortcut menu for item2.xml and then choose Open.

    This file contains the custom XML part that you added to the document.

  13. Verify that the name, hireDate, and title elements contain the new values that you entered into the content controls in the document.

  14. Close the item2.xml file.

Next steps

You can learn more about how to use content controls from these topics:

  • Use all the available content controls to create a template. For more information, see Walkthrough: Create a template by using content controls.

  • Modify the data in the custom XML parts while the document is closed. The next time the user opens the document, the content controls that are bound to the XML elements will display the new data.

  • Use content controls to protect parts of a document. For more information, see How to: Protect parts of documents by using content controls.

See also

  • Automate Word by using extended objects
  • Content controls
  • How to: Add content controls to Word documents
  • How to: Protect parts of documents by using content controls
  • Host items and host controls overview
  • Programmatic limitations of host items and host controls
  • Add controls to Office documents at run time
  • Download source — 73.4 KB

Introduction (ramble)

Another boring day in my life. I often wonder why it has to be like this – I either have no obligations at all, or I’m packed with them. Most people tell me that it has to do with planning. They wear their favorite serious face and say: you, my son, just don’t know how to properly make your schedule. Time is the essence, do not use it improperly! You must divide your time in million little pieces, label each one of them, implement some kind of sorting, import everything into Microsoft Outlook, and stick to that plan. Then, and only then, you’ll be a man who is not a campaigner, but an organized, equally time pressured «snooze-dismiss» monkey individual.

My answer is way simpler, I often reply with just – hey, screw you! ;)

Because, really, I’ve always believed it’s not about planning, but about the way universe has been built. Think about it – everything important was created in just those few seconds after the Big Bang. All that followed was just plain simple boring processes of waiting for the fruits of planted seeds to grow; the stage setting for another big moment.

So, I hope you’ll agree that it is – as Derek Ager once wrote – like the life of a soldier… long periods of boredom, and short periods of terror. One can just hope that those «long periods of boredom» can be filled with small joys of doing something you like; something that’ll ease your wait for those important «short periods».

This article is just that, my way of getting along with boredom… if it helps someone else, or fills his spare time, my joy will only be greater.

Index

  • Problem
  • Brief solution description
  • Producing the XSL transformation
    • Defining the XML schema based on the report
    • Binding data from the Word document to the appropriate fields in the XML schema
    • Saving into WordML and the generation of XSLT
    • Solving problems with multiple used elements
    • Inserting images into the document
    • Opening the document in read-only mode
  • Preparing data and applying the transformation
    • T-SQL and XML
    • Binding XML to schema
  • Applying the transformation on XML data
  • XML->XSLT->HTML->Word, the easy way out
  • Organization of resources used for the generation in the Visual Studio project
  • FAQ
  • Conclusion
  • References
  • History

Problem

I don’t know if you are in a club, but I’ve met numerous .NET developers who had much trouble with choosing the right tool to build reports. Apart from praise for the Access report building capabilities, you won’t hear many compliments for the reporting tools.

I guess we have all tried Crystal Reports embedded into Visual Studio .NET — they are OK, but are demanding. And often, small bugs, along with ridiculous option placements, will drive you nuts.

SQL Reporting Services are somewhat a new option that is praised all over the web by Microsoft evangelists. In practice, however, I’ve often stumbled on projects where the team is paralyzed with problems concerning configuration and specific aspects of report writing.

Finally, there are numerous custom reporting frameworks such as ActiveReports or DevExpress’ (I love these guys) Reporting Tools.

Specific maladies aside, the common problem with all the previously laid options is that they have a modest learning curve. I’m not talking about the time needed to acquire the knowledge for generating a list of employees from an «It’s easy to use our report suite»™ example. I’m talking about the time needed to acquire the knowledge for developing real-life reports which have three tables that properly expand and contract (along with its columns and rows) over pages.

Also, none of these options provide you with the solution for frequent user requirements – when a report is rendered, it should be possible to modify it a bit. The workaround is to use report exporting to popular formats that are known to most users, like Word.

As I’ve experienced, this is the point when the bulb shines above the head of the developer and the idea comes — why not generate reports in Word in the first place. In the majority of projects, clients are provided with the needed output reports in Word format, which they print and fill by hand. And if not… well, you have one of the best «report designers» in the world, as it was tweaked and improved over numerous versions.

So, how to do it?

Brief solution description

One big, big problem with Word documents before the 2003 version was their binary format. Word’s file format was not publicly available, and all utilities that could parse it were mostly developed by reverse-engineering, or by stealing using documentation available to Microsoft partners. You can guess that results weren’t too satisfying…

However, in 2003, Microsoft introduced XML formats for storing Office documents. Those formats were succeeded by Office Open XML formats in Office 2007 (which are default, instead of their binary counterparts), so you can safely bet that they are here to stay.

So, in order to generate a Word file now, you basically need to apply the appropriate XSLT (XSL Transform) onto the XML data used in a report. This process can be divided into several operational steps:

  1. Defining the XML schema based on the report
  2. Binding data from the Word document to the appropriate fields in XML schema
  3. Saving the Word document in WordML format and the generation of XSLT using the WML2XSLT tool
  4. Retrieving the needed data from a source (mostly a SQL Server database), it’s structuring into appropriate XML
  5. Applying XSLT onto XML data in order to generate the Word document, which then can be further manipulated (sending over wire, displaying to user, and similar)

The biggest problem is to produce valid XSLT; from five steps, three are taken to do that. The generation of XML is far easier, while the transformation is completely trivial.

Producing the XSL transformation

Defining the XML schema based on the report

In order to start making the report, it is required to define the necessary data. A picture talks more than a thousand words, an example talks almost an equal amount… so let’s look at the picture of the report that we’ll use as an example:

Figure 1 – Report that should be generated

Figure 1 – Report that should be generated

It is obvious that we first have the buyer’s name, the document date follows. Then we have, from the developer point of view, an interesting table of invoice items… and so on. The structure of the XML which will hold this data is described using an XML schema. Visual Studio 2005 has nice support for visual design of schemas, which we will utilize – after starting the IDE, take option File –> New –> File (CTRL+N): this gives a list of possible document types from which we choose XML Schema.

An element from the Toolbox should then be dragged-and-dropped on the workspace and filled with content. This process is shown on the picture that follows:

Figure 2 – Schema that defines structure of data for report

Figure 2 – Schema that defines the structure of data for the report

In order to be properly mapped, items on the invoice need to be described as child elements of the Invoice entity. Add -> New element from the context menu shown after right click gives the option to perform this action.

Figure 3 – Adding child to Invoice entity

Figure 3 – Adding a child to the Invoice entity

Adding the rest of the elements, assigning types to variables, and setting the targetNamespace (in the Properties window) gets the job done.

Assigning types to variables is optional in most cases – if you use special formats for printing out documents (like dd.MM.yyyy) or monetary values ($10.99), it’s easier to leave everything in the schema in string type, and do the formatting and validation during the generation of XML with the data.

On the other hand, setting the targetNamespace shouldn’t be optional – the produced schema will get the default value http://tempuri.org/XMLSchema.xsd. We can put aside the rules of good practice that tells us not to use the http://tempuri.org/ namespace in production; but, if you don’t give unique names to your schemas, you’ll stumble into problems during import and usage – Word’s schema library can’t hold two different schemas with the same namespace. So, be sure to set the targetNamespace (the convention http://Organization/Project/SchemaName.xsd is used mostly) before you close the definition.

Figure 4 – Resulting XML schema

Figure 4 – Resulting XML schema

Binding data from the Word document to the appropriate fields in the XML schema

Schema importing is performed by using the XML Structure dialog. In the 2003 version of Office Word, this dialog is accessible through Task Pane (CTRL+F1); it should be chosen from the list shown when clicked on the triangle in the header (left from the small x). If schemas aren’t previously imported, and the Template and Add-Ins option is chosen, the picture that follows will faithfully resemble the resulting state of the screen.

Figure 5 – Adding new XML Schema in Word document

Figure 5 – Adding the new XML schema in the Word document

In the dialog shown after clicking on the Add Schema button, it is needed to point to the location of the defined XML schema. Its fields will be then shown in the XML Structure dialog, from where they are further bound to the document data. Before starting that sweet job, some additional options should be set:

  • Check Ignore mixed content – This allows mixing data from the XML with data from the document. As documents are almost always made of fixed and variable parts, this avoids frequent signalization by Word that between the data defined in the XML schema there are «some others that don’t belong there».
  • Check Show advanced XML error messages – Choosing developer-friendly messages over user-friendly ones.
  • Check Allow saving as XML even if not valid – Most often, you just can’t «validly» mark data in the report document. For example, if some data from the XML is used twice in the document, Word will signal error in validation because according to the XML schema, that data appears only once. The same problem happens with order.
  • This is present to force valid entry of data in the Word document (another application of the technique that is being described). However, our current goal is diametrically opposite – we are not marking fields for entry, but for space in which data from the XML will be inserted, so it’s not needed to force a unique appearance and order.

Figure 6 – Dialog for setting XML data

Figure 6 – Dialog for setting XML data

After the schema is imported in to the document and the options set, it’s time to move onto binding the schema and the data. Initially, only the root element (in our case, Invoice) is available. After choosing it, Word will offer options for assigning the schema to the appropriate range in the document.

Figure 7 – Options for applying schema on appropriate range in document

Figure 7 – Options for applying the schema on the appropriate range in the document

In this example, applying the schema to the entire document is a needed option (possible multi-schematic Word files aren’t interesting from the reporting point of view). Now, what is left is to mark the data – the selected text is bound to the schema either by choosing the field from the Task Pane, or by using the option Apply XML Element shown after a right click.

Figure 8 – Binding data from Word document to fields of XML schema

Figure 8 – Binding data from a Word document to fields of the XML schema

Two things are interesting here. First, to define child items, you need to select and map the whole row in the table to the InvoiceItems element, after which Name and Price will be available for bounding to the cell’s data. If the document contains a large number of items, there is no need to map every single row; mapping just the first row is fine, the rest can be deleted. The structure of report, not the content, is what matters at the moment.

Second, Word, for previously explained reasons, signals error for double usage of the Buyer element (look at the picture). It’ll cause problems later, during the generation of the XSLT, but we can omit that problem for now (if Allow saving as XML even if not valid is checked in the XML options).

Saving into WordML and the generation of XSLT

The marked document contains all the data needed for the generation of valid XSLT. The WML2XSLT tool accepts WordML as input, so it’s required to save the Word document in this format. You can do this by using the Save As option from the File menu – when the dialog is shown in Save as Type, choose XML document (*.xml). The option Apply transform is used in the opposite direction, Data only when XML data is fetched from the document, so both fields should be left unchecked.

The prepared WML file is processed using this statement in the Command Prompt (the following is valid assuming that everything is in the same directory):

WML2XSLT.exe "WordGeneratedInvoice.xml" –o "WordGeneratedInvoice.xslt"

In case you run into problems (FileNotFoundException) while using the WML2XSLT.exe packed with the article source, be sure to download the tool from the previously given link and perform the installation (as mobfigr noted in his comment).

Solving problems with multiple used elements

The generated XSL transform will almost always be satisfying. One exception is when an element from the XML with data is used multiple times. In the example we are developing, the Buyer element is used twice, and for its second appearance, the following will be generated (you need to open the XSLT in Notepad or Visual Studio .NET and search for the value ns1:Buyer):

<w:r> <w:t><xsl:text>(Buyer: </xsl:text></w:t></w:r>
<xsl:apply-templates select="ns1:Buyer[position() >= 2]" />
<w:r> <w:t><xsl:text>)</xsl:text></w:t></w:r>

It’s obvious we aren’t interested in the element Buyer on the second position, but the same one that is referenced earlier in the file. Because of that, the following correction should be made:

<w:r> <w:t><xsl:text>(Buyer: </xsl:text></w:t></w:r>
<xsl:apply-templates select="ns1:Buyer" />
<w:r> <w:t><xsl:text>)</xsl:text></w:t></w:r>

Inserting images into the document

Naturally, WordML has good support for images, but it is very poorly documented. So, in order to see how images are represented in WML format, we’ll perform a little experiment and save the marked Word document displayed below as XML:

Figure 9 – Document with image

Figure 9 – Document with image

After processing the saved document using the WML2XML tool (with the WML2XML ExampleImage.xml -o ExampleImage.xslt command), and opening the generated XSLT file, we can scroll to the SomeImage tag and see the following:

<ns0:SomeImage>
  <xsl:for-each select="@ns0:*|@*[namespace-uri()='']">
    <xsl:attribute name="{name()}" namespace="{namespace-uri()}">
      <xsl:value-of select="." />
    </xsl:attribute>
  </xsl:for-each>
  <w:r>
    <w:pict>
      <v:shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" 
              o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f">
        <v:stroke joinstyle="miter" />
        <v:formulas>
          <v:f eqn="if lineDrawn pixelLineWidth 0" />
          <v:f eqn="sum @0 1 0" />
          <v:f eqn="sum 0 0 @1" />
          <v:f eqn="prod @2 1 2" />
          <v:f eqn="prod @3 21600 pixelWidth" />
          <v:f eqn="prod @3 21600 pixelHeight" />
          <v:f eqn="sum @0 0 1" />
          <v:f eqn="prod @6 1 2" />
          <v:f eqn="prod @7 21600 pixelWidth" />
          <v:f eqn="sum @8 21600 0" />
          <v:f eqn="prod @7 21600 pixelHeight" />
          <v:f eqn="sum @10 21600 0" />
        </v:formulas>
        <v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect" />
        <o:lock v:ext="edit" aspectratio="t" />
      </v:shapetype>
      <w:binData w:name="wordml://01000001.gif">R0lGODlhEAAQAPIGAAAAAAAAsACwALAAALD/sP+wsP
   ///////yH5BAEAAAcALAAAAAAQABAAAAOW
eHd3h3d3d3h3d4d3cHd4d3eHd3cHWHAXgXF3d3gHVYNwZxZ4d3eAVTUDeHdhh3d3UFgDdocRcXd4
d1CAdncXaHZ3h3dgd3h3Z4d3d3d4d3eHB3d3eHd3h3d3QAh3d4d3d3d4QCSAd3d3eHcHhEQicHh3
d4d3B0QoYHeHd3d3eAcEhnd3d3h3d4cHdnd4d3eHd3d3eHeXADu=
</w:binData>
      <v:shape id="_x0000_i1025" type="#_x0000_t75" style="width:12pt;height:12pt">
        <v:imagedata src="wordml://01000001.gif" o:title="convert" />
      </v:shape>
    </w:pict>
  </w:r>
  <w:p>
    <w:r>
      <w:t>
        <xsl:value-of select="." />
      </w:t>
    </w:r>
  </w:p>
</ns0:SomeImage>

Obviously, the image is Base64 encoded into the XML file between the <w:binData> tags. After that, we have the <v:shape> tag which defines the placing of the image and references the encoded binary data by using <v:imagedata>. All this is preceded by <v:shapetype>, which is (luckily) optional and can be removed. Now, when we have some understanding of the format, we can perform a little clean up and properly place xsl:value-of select, so that binary data comes from our XML file:

<ns0:SomeImage>
  <xsl:for-each select="@ns0:*|@*[namespace-uri()='']">
    <xsl:attribute name="{name()}" namespace="{namespace-uri()}">
      <xsl:value-of select="." />
    </xsl:attribute>
  </xsl:for-each>
  <w:r>
    <w:pict>
      <w:binData w:name="wordml://01000001.gif"><xsl:value-of select="." /></w:binData>
      <v:shape id="_x0000_i1025" type="#_x0000_t75" style="width:12pt;height:12pt">
        <v:imagedata src="wordml://01000001.gif" o:title="convert" />
      </v:shape>
    </w:pict>
  </w:r>
</ns0:SomeImage>

It looks better, doesn’t it? All that is left is to supply the XML data in the proper format:

="1.0"="utf-8"
<Something xmlns="http://schemas.microsoft.com/GeneratingWordDocuments/ImageExample.xsd">
    <SomeText>Small image below</SomeText>
    <SomeImage>R0lGODlhE[-- binary data truncated --]3d3eHeXADu=</SomeImage>
</Something>

and we’ll have the document from Figure 9 in no time. One final word of warning — if your images aren’t always the same size, you’ll want to check the style attribute of the <v:shape> tag. And, after checking, you’ll probably want to move it out of the transformation into XML ;). Here is how to do that:

<w:pict>
  <w:binData w:name="wordml://01000001.gif">
      <xsl:value-of select="." />
  </w:binData>
    <v:shape id="_x0000_i1025" type="#_x0000_t75">
        <xsl:attribute name="style">
            <xsl:value-of select="@style"/>
        </xsl:attribute>
        <v:imagedata src="wordml://01000001.gif" o:title="convert" />
    </v:shape>
</w:pict>
 
="1.0"="utf-8"
<Something xmlns="http://schemas.microsoft.com/GeneratingWordDocuments/ImageExample.xsd">
    <SomeText>Small image below</SomeText>
    <SomeImage style="width:24pt;height:24pt">R0lGOD[-- binary data truncated --]3d3eADu=
    </SomeImage>
</Something>

Opening the document in read-only mode

To force opening the report in read-only mode when the report is displayed to the user, it’s needed to use the Tools -> Options -> Security -> Protect Document option during the document creation. Under Editing Restrictions, ‘No changes (Read only)’ should be chosen… after that, the only thing left to do is click onto ‘Yes, Start Enforcing Protection’ and enter the password for protection. Of course, further steps remain the same — the document is saved as WordML, processed through the WML2XSLT tool…

Figure 9 – Settings for read-only mode

Figure 10 – Settings for the read-only mode

Do not expect too much from this «protection». In WordML format, it’s enforced by one line in the DocumentProperties element:

<w:docPr>
  <w:view w:val="print" />
  <w:zoom w:percent="85" />
  <w:doNotEmbedSystemFonts />
  <w:proofState w:spelling="clean" w:grammar="clean" />
  <w:attachedTemplate w:val="" />
  <u><w:documentProtection w:edit="read-only" w:enforcement="on"
                           w:unprotectPassword="4560CA9C" /></u>
  <w:defaultTabStop w:val="720" />
  <w:punctuationKerning />
  <w:characterSpacingControl w:val="DontCompress" />
  <w:optimizeForBrowser />
  <w:validateAgainstSchema />
  <w:saveInvalidXML />
  <w:ignoreMixedContent />
  <w:alwaysShowPlaceholderText w:val="off" />
  <w:compat>
    <w:breakWrappedTables />
    <w:snapToGridInCell />
    <w:wrapTextWithPunct />
    <w:useAsianBreakRules />
    <w:dontGrowAutofit />
  </w:compat>
  <w:showXMLTags w:val="off" />
</w:docPr>

This means that the read-only mode can be easily incorporated into XSLT for reports you’ve already done… but, it also means that anyone knowing WML format can easily workaround your «protection». So, use it wisely :)

Preparing data and applying the transformation

T-SQL and XML

XML data that satisfies the previously defined schema and which we’ll use in the report can be generated in many ways. The most commonly used is the one that utilizes the SELECT... FOR XML command and data from SQL Server 2005 that directly translates into XML.

SELECT... FOR XML has two parameters:

  1. Work mode, chosen from RAW, AUTO, EXPLICIT, and the PATH array. In general, the AUTO mode will finish the job; when extra formatting is needed, the PATH mode is the choice.
  2. Additional variables like ROOT (add a root tag to XML), ELEMENTS (format output data as elements), TYPE (result is returned as XML type of SQL Server 2005), and XMLSCHEMA (write XML schema before data).

For example, if there is a c_City table with columns CityId and CityName, and XML with element City is needed, the following T-SQL is required:

SELECT CityId, CityName FROM c_City AS City
FOR XML AUTO

<City CityId="43" CityName="100 Mile House" />
<City CityId="53" CityName="Abbotsford" />

If it’s needed to write out data in elements, the ELEMENTS directive is added:

SELECT CityId, CityName FROM c_City AS City
FOR XML AUTO, ELEMENTS

<City>
  <CityId>43</CityId>
  <CityName>100 Mile House</CityName>
</City>
<City>
  <CityId>53</CityId>
  <CityName>Abbotsford</CityName>
</City>

As two elements exist on the first level, Root tag must be added so that the XML is syntactically valid:

SELECT CityId, CityName FROM c_City AS City
FOR XML AUTO, ELEMENTS, ROOT('Root')

<Root>
  <City>
    <CityId>43</CityId>
    <CityName>100 Mile House</CityName>
  </City>
  <City>
    <CityId>53</CityId>
    <CityName>Abbotsford</CityName>
  </City>
</Root>

Let’s assume that there is a c_PostalCode table with postal codes used in cities. If it’s required to make XML where postal codes will be child element of cities, the following SQL is in order:

SELECT CityId, CityName,  
    (SELECT PostalCodeId, PostalCodeName FROM c_PostalCode
     WHERE CityId = City.CityId
     FOR XML AUTO, TYPE)        
FROM c_City AS City
FOR XML AUTO, TYPE

<Root>
  <City CityId="43" CityName="100 Mile House">
    <c_PostalCode PostalCodeId="317701" PostalCodeName="V0K2Z0" />
    <c_PostalCode PostalCodeId="317702" PostalCodeName="V0K2E0" />
  </City>
  <City CityId="53" CityName="Abbotsford">
    <c_PostalCode PostalCodeId="317703" PostalCodeName="V3G2J3" />
  </City>
</Root>

If more output flexibility is required, it’s possible to format the XML in more detail using the PATH mode. For example, if it’s needed to hold CityId as an attribute, CityName as an element, and information about postal codes as child elements which PostalCodeId places in the NotNeeded sub element, use this T-SQL:

SELECT CityId AS '@CityId', CityName,  
    (SELECT PostalCodeId AS 'NotNeeded/PostalCodeId', PostalCodeName 
     FROM c_PostalCode
     WHERE CityId = City.CityId
     FOR XML path('PostalCode'), TYPE)        
FROM c_City AS City
FOR XML PATH('CityRow'), type, root('Data')

<Data>
  <CityRow CityId="43">
    <CityName>100 Mile House</CityName>
    <PostalCode PostalCodeName="V0K2Z0">
      <NotNeeded>
        <PostalCodeId>317701</PostalCodeId>
      </NotNeeded>
    </PostalCode>
    <PostalCode PostalCodeName="V0K2E0">
      <NotNeeded>
        <PostalCodeId>317702</PostalCodeId>
      </NotNeeded>
    </PostalCode>
  </CityRow>
  <CityRow CityId="53">
    <CityName>Abbotsford</CityName>
    <PostalCode PostalCodeName="V3G2J3">
      <NotNeeded>
        <PostalCodeId>317703</PostalCodeId>
      </NotNeeded>
    </PostalCode>
  </CityRow>
</Data>

Binding XML to schema

For the XML data to be shown in Word, it’s necessary that the xmlns attribute of the root tag points to the appropriate schema. To be precise – in our example, to show the XML data in the generated Word document, it’s not enough to provide just the following output from SQL:

SELECT Buyer, InvoiceDate, ...
FROM Invoice
FOR XML PATH('Invoice'), ELEMENTS

<Invoice>
    <Buyer>John Doe</Buyer>
    <InvoiceDate>2008-01-01</InvoiceDate>
    ...
</Invoice>

It’s needed to set the xmlns attribute in such a manner to point to the targetNamespace of the WordGeneratedInvoice.xsd schema:

WITH XMLNAMESPACES(DEFAULT 
   'http://schemas.microsoft.com/GeneratingWordDocuments/WordGeneratedInvoice.xsd')
SELECT Buyer, InvoiceDate, ...
FROM Invoice 
FOR XML PATH('Invoice'), ELEMENTS

<Data xmlns="http://schemas.microsoft.com/GeneratingWordDocuments/WordGeneratedInvoice.xsd">
    <Buyer>John Doe</Buyer>
    <InvoiceDate>2008-01-01</InvoiceDate>
    ...
</Invoice>

A blank Word document is the most common result if the XML data is not bound to the schema over an xmlns attribute.

Applying the transformation on XML data

public static byte[] GetWord(XmlReader xmlData, XmlReader xslt)
{
    XslCompiledTransform xslt = new XslCompiledTransform();
    XsltArgumentList args = new XsltArgumentList();

    using (MemoryStream swResult = new MemoryStream())
    {
        xslt.Load(xslt);
        xslt.Transform(xmlData, args, swResult);

        return swResult.ToArray();
    }
}

It’s mentioned earlier that this step is trivial. The example justifies that, doesn’t it?

After the XML data and the XSL transformation are passed as XmlReader objects, an XslCompiledTransform is initialized through the Load method. All that is left is to call Transform to finish the job.

XML->XSLT->HTML->Word, the easy way out

In case you don’t need advanced capabilities that Word provides (page numbering, margins, and similar), you have a pretty handy option of hand-writing XSLT that transforms XML data to HTML and then just opens HTML in Word.

To illustrate the idea with an example – here is an XSLT that I use for a list report that just shows the contents of a CD DataTable with two columns, Title and Price:

='1.0'='UTF-8'
<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version='1.0' 
xmlns:fo='http://www.w3.org/1999/XSL/Format' 
xmlns:fn='http://www.w3.org/2003/11/xpath-functions' 
xmlns:xf='http://www.w3.org/2002/08/xquery-functions'>
    <xsl:template match='/'>
        <html>
            <body>
                <h2>Report Header</h2>
                <table border='0' width='100%'>
                    <tr bgcolor='Gray'>
                        <th align='left'>Title</th>
                        <th align='left'>Price</th>
                    </tr>
                    <xsl:for-each select='DocumentElement/Cd'>
                        <tr>
                            <td>
                                <xsl:value-of select='Title'/>
                            </td>
                            <td>
                                <xsl:value-of select='Price'/>
                            </td>
                        </tr>
                    </xsl:for-each>
                </table>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>

The XML data which is transformed:

='1.0'='UTF-8'
<DocumentElement>
    <Cd>
        <Title>Mike</Title>
        <Price>20$</Price>
    </Cd>
    <Cd>
        <Title>Nike</Title>
        <Price>30$</Price>
    </Cd>
    <Cd>
        <Title>Reebok</Title>
        <Price>40$</Price>
    </Cd>
</DocumentElement>

When the xsl:template tag is matched (and it’ll be matched always because it points to root), its InnerText is evaluated. The xsl:for-each tag processes each of the DocumentElement/Cd nodes, and xsl:value-of gets the InnerText of the XPath selected element. In case you’re not too good with XSLT, I recommend this webpage: W3Schools. W3Schools, you rock! :)

Resulting HTML:

<html xmlns:fo="http://www.w3.org/1999/XSL/Format" 
xmlns:fn="http://www.w3.org/2003/11/xpath-functions" 
xmlns:xf="http://www.w3.org/2002/08/xquery-functions">
    <body>
        <h2>Something</h2>
        <table border="0" width="100%">
            <tr bgcolor="Gray">
                <th align="left">Title</th>
                <th align="left">Price</th>
            </tr>
            <tr>
                <td>Mike</td>
                <td>20$</td>
            </tr>
            <tr>
                <td>Nike</td>
                <td>30$</td>
            </tr>
            <tr>
                <td>Reebok</td>
                <td>40$</td>
            </tr>
        </table>
    </body>
</html>

Word, even in versions earlier than 2003, had no any problems with opening HTML; so, just save the result as .doc (instead of .HTML) and you’ll be done. In case you are sending the response over the Web, you can specify the type with:

Response.AddHeader("content-type", "application/msword");
Response.AddHeader("Content-Disposition", "attachment; filename=report.doc");

The true value of this option comes into light when you start thinking about generic reports. In the source code that accompanies this article, you’ll find a generic version of this example, the one that works with any DataTable. Be sure to check it.

Organization of resources used for the generation in the Visual Studio project

The source code I have attached to this article demonstrates one possible way of organizing the needed resources for the Word reports generation. Here is the project structure:

Figure 11 - XSL transform as part of VS.NET project for generating Word reports

Figure 11 — XSL transform as part of the VS.NET project for generating Word reports

It is of utmost importance that Embedded Resource is set on the Build Action for all the resources that are used in the generation of the Word document (XML, XSD, XSLT). This enables their later fetching from the resource collection of the compiled DLL.

Reports are generated through a static Report class which represents the facade to embedded resources and the logic exploiting them:

public class Report
{
                    public static byte[] WordGeneratedInvoice()
    {
        

        

        

        string xmlData = Getters.GetTestXml("WordGeneratedInvoice");
        return Getters.GetWord(xmlData, "WordGeneratedInvoice");
    }

    


    

}

Adding new reports in this structure is easy:

  • The new report for generation is added in the Doc directory.
  • The XML schema which is created based on the report is added in the Xsd directory.
  • After the schema is applied on the document, the saved WordML is used as the input in the WML2XSLT tool; the resulting XSLT is placed in the Xslt directory.
  • A method is added in the Report class which is responsible for fetching XML data, invoking the transformation, and returning the resulting Word document.

FAQ

Can I convert the generated WordML to PDF? How do I do it?

Check out my article Generate PDF using C#.

I applied the schema to the Word document and ended my work on it. After some time, I reopened the document, but in the XML structure dialog, the list of elements available for applying onto the document (the lower listbox) is empty.

This occurred because the path to the XSD file is changed. The location of the schema can be refreshed by using XML Options -> Schema Library -> choose the schema used in the document -> Schema Settings -> Browse…

Figure 12 – Dialogs (from left to right) that visualy show path to Browse... option

Figure 12 – Dialogs (ordered from left to right) that visually show the path to the Browse… option

I’ve changed the XML schema (XSD) after the changed request for the new report fields arrived. However, Word 2003 does not show new fields in the XML structure dialog, so I can’t bind them to the data in the new version of the report. Must I build the report from scratch?

This problem can be solved by installing the Office 2003 Service Pack 2. When SP2 is installed, Word 2003 will refresh the attached schema if the following steps are satisfied:

  • Schema is changed, XSD file is saved
  • All instances of Word 2003 are closed (not only the document which uses the mentioned schema!)
  • Reopen the Word document that uses the schema

In some situations, the better way to solve this problem is to install the XML Toolbox for Microsoft Office Word 2003 – it adds the command Refresh Schema. The solution isn’t universal because the XML Toolbox doesn’t install properly always (the most common problems are security polices, the existence of .NET Framework 1.1…). So, my suggestion is to close all Office applications, download the .msi from the link, run it – if everything goes smoothly, you’ll see the Word XML toolbar (View -> Toolbars -> Word XML Toolbar); if not, you always have the first suggestion for schema refreshing.

Figure 13 - XML Toolbox in Word 2003, with Reload Schema option

Figure 13 — XML Toolbox in Word 2003, with the Reload Schema option

I made the XSD, bound it to the Word document, made the XSLT, prepared the XML data, performed the transformation, and got – empty document

The most common cause of this problem is that XML doesn’t contain the schema binding (as a value of the xmlns attribute of the root tag). Read the Binding XML to schema chapter.

The easiest way to see the type of XML you should prepare is to get the properly schema and fields bounded Word document to be saved on the some temporary location as the XML (File -> Save as, Save as type: XML document), by checking the option Save data only. You can view the saved XML by opening it in Visual Studio .NET or Notepad…

Figure 14 – Saving XML data only from properly mapped Word document

Figure 14 – Saving the XML data only from properly mapped Word document

Where are the XML options located in Office Word 2007? How different is report making between Word 2003 and 2007?

Honestly, I haven’t worked much in the 2007 version of Word, but still — I couldn’t find big differences. The only problem I’ve had is in finding the XML Structure dialog, as it was not accessible with the Task Pane. It seems that the XML Toolbox is installed by default with Office 2007, so you can solve this by its adding by using the toolbar’s (Ribbon’s) option, Customize…

Figure 15 – Dialog shown after choosing option Customize... in Word 2007

Figure 15 – Dialog shown after choosing the option Customize… in Word 2007

Figure 16 - XML Toolbox in Word 2007

Figure 16 — XML Toolbox in Word 2007

Conclusion

It is worthy to note that the solution I recommended doesn’t use Visual Studio Tools for Office. I tried them out for document generation, and was very disappointed as they required a nasty deal of configuring both to develop and run.

Also, using XSLT to produce Word documents is far easier than juggling with the Microsoft Word Object Library COM DLL and its Word.Application class; not to mention that it is way faster and memory leak free. If you are using a COM DLL for generating Word files, I would advise you to start rewriting that part of your system right now, especially if you are generating documents on the server and then sending them to clients. Simply, Word was developed to be an interactive user application and not a «visible = false» puppet of another process.

Well, that’s it folks. You know the drill — please take your time to rate this article, and if you are (un)happy with it or just need some aid, post comments and I’ll be glad to respond/help in no time :).

References

In no particular order…

Books:

History

  • February 17, 2008 — Added the multiple images example (this comment initiated it).
  • November 4, 2007 — Added the image example (this comment initiated it).
  • October 17, 2007 – Added the grouping example (this comment initiated it).
  • September 13, 2007 – Added the read-only section, added one more example (this comment initiated it).
  • August 31, 2007 – Initial version of the article.

If you liked this article, consider reading other articles by me. For republishing article on other websites, please contact me by leaving a comment.

Сотрудники большой организации часто добавляют схему к документу, который является частью информационной системы, например, к заказу товара для отдела закупок. Схемы обычно создаются и распространяются специалистами, задачей которых является развитие бизнес-процессов.

Выполните следующие действия, чтобы добавить схему к документу:

1. Выберите в меню

Сервис пункты Шаблоны и надстройки (AddTns).

2. На вкладке XML-схема (XML Schema) выберите схему (рис. 10.21);

Щелкните по кнопке Библиотека схем (Schema Library), чтобы отобразить список схем и сделать в нем выбор (рис. 10.22).

3. Щелкните по кнопке ОК.

После добавления схемы вы можете задать ярлыки из схемы для текста в вашем документе. Для этого выберите текст, а затем ярлык в Области задач Структура XML (XML Structure). Разработчик схемы должен предоставить вам информацию о правильном использовании ярлыков.

Создание и использование схем — сложная тема, изучение которой выходит за рамки данной книги. За дополнительной информацией о схемах, а также о связанной с ними функции трансформации обращайтесь к книге «Истинный мир формата XML-Стива Хользнера (Steve Holzner) издательства Peachpit Press.


Newer news items:

Older news items:


  •  
  • xsd

  • ms-word

  • openxml

  • openxml-sdk

  •  11-12-2019
  •  | 

  •  

Question

Hello there I wish to create an XML Schema for word 2010 and specify that to a word document so that the word doc is now based on my own Custom XML schema and so that I can apply my own XML elements to that word file? There’s an option in the developer tab in MS word 2010 to apply your XML elements but for that you have to specify a XML schema. I have googled on creating custom xml schema for word 2010 it but no luck! Any thoughts are sample code would do a great favour Thanks in advance!

Kind Regards!

No correct solution

OTHER TIPS

Понравилась статья? Поделить с друзьями:
  • Xml schema from excel
  • Xml schema for excel
  • Xml parsing error word как исправить
  • Xlfn excel что это такое
  • Xlfn concat в excel