CustomXmlParts.cs
 // // This code is part of Document Solutions for Word demos. // Copyright (c) MESCIUS inc. All rights reserved. // using System; using System.IO; using System.Drawing; using System.Collections.Generic; using System.Linq; using System.Xml; using GrapeCity.Documents.Word; namespace DsWordWeb.Demos { // This example demonstrates how to create a document with multiple ContentControls, // whose values are mapped to user-created CustomXmlPart file, standard XML file // which defines various elements and attributes. // This document also contain a header and a footer with elements that are also mapped to // proper xml elements. public class CustomXmlParts { public GcWordDocument CreateDocx() { var doc = new GcWordDocument(); // Create custom xml part and keep it in the document: CreateOrderCustomXmlFromString(doc); // Set custom xml document element value: SetDeliveryOption(doc, true); // Compose document with Case properties bound to proper CustomControls: // Create and map To text field: CreateOficialBody(doc); // Create and map Appeal checkbox and AppealDeadline Text control: CreateDeliveryCheckbox(doc); // Create Header and map Department xml element: CreateHeaderWithMappedDepartment(doc); // Create Header and map document built-in Author xml element: CreateFooterWithMappedAuthor(doc); // Done: return doc; } // Retrieve a CustomXmlPart from a document by name: private static CustomXmlPart GetCustomXmlPartByName(GcWordDocument doc, string name) { foreach (var xmlPart in doc.CustomXmlParts) { if (string.Compare(xmlPart.XmlDocument.DocumentElement.Name, name, true) == 0) return xmlPart; } throw new ArgumentException(string.Format("Could not find custom xml part {0}", name)); } // Find 'Order' CustomXmlPart and set its DeliveryAppeal xml element to value provided by method parameter: private static void SetDeliveryOption(GcWordDocument doc, bool deliveryRequired) { var xmlPart = GetCustomXmlPartByName(doc, "Order"); var node = xmlPart.XmlDocument.SelectSingleNode(@"//*[local-name()='Delivery']"); node.InnerText = deliveryRequired ? "true" : "false"; } // Compose half of document body, map "To" text custom control to proper CustomXml field: private static void CreateOficialBody(GcWordDocument doc) { var p = doc.Body.Paragraphs.Add("Dear "); var to = p.GetRange().ContentControls.Add(ContentControlType.Text, false); to.XmlMapping.SetMapping(@"//mescius:To", @"xmlns:mescius='http://developer.mescius.com'"); p.GetRange().Runs.First.Font.Size = 10; to.Font.Size = 10; p.GetRange().Runs.Add(","); doc.Body.Paragraphs.Add(); p = doc.Body.Paragraphs.Add( "The first shipment of equipment from AMA Ltd has arrived. " + "We are delighted with every piece. Therefore, we decided to make " + "our initial purchase larger than anticipated. I am attaching our " + "purchase order No. 8393 for additional goods. Since you already have " + "a copy of our Procurement Guidelines, I shall not attach them to " + "this order. Current Shipping date is "); // Add shipping Date control, bound to proper section of Order CustomXmlPart: var dateControl = p.GetRange().ContentControls.Add(ContentControlType.Date, false); dateControl.DateFormat = "dd.MM.yyyy"; //here we demonstrate how to map CustomControl with namespaces usage, it allows us write //clean and straight XmlPath. Its the right way of XMlMapping dateControl.XmlMapping.SetMapping(@"//mescius:Delivery/@DeliveryDate", @"xmlns:mescius='http://developer.mescius.com'"); p.GetRange().Paragraphs.Add( "If you want to change it, select checkbox below and change Date, " + "then send this letter back to me"); dateControl.Font.Italic = true; p.GetRange().Runs.First.Font.Size = 12; p.GetRange().Runs.First.Font.Italic = true; } // Create footer and map Author built-in property to Text content control: private static void CreateFooterWithMappedAuthor(GcWordDocument doc) { var footer = doc.Body.Sections.First.Footers[HeaderFooterType.Primary]; var p = footer.Body.Paragraphs.Add("Sincerely yours, "); if (p.Document.Settings.BuiltinProperties.Author == null) p.Document.Settings.BuiltinProperties.Author = "Nancy Davolio"; // Create Text ContentControl and bind its value to builtin Author property: var authorTextControl = p.GetRange().ContentControls.Add(ContentControlType.Text, false); // Use specialized SetMapping overload for document BuiltInProperties. // here we bind (map) ContentControl to builtin Author property: authorTextControl.XmlMapping.SetMapping(() => p.Document.Settings.BuiltinProperties.Author); } // Create header with Text ContentControl mapped to 'Department' node of 'Order' CustomXml: private static void CreateHeaderWithMappedDepartment(GcWordDocument doc) { // Create Header and fill it with data: var header = doc.Body.Sections.First.Headers[HeaderFooterType.Primary]; var p = header.Body.Paragraphs.Add(); var departmentTextControl = p.GetRange().ContentControls.Add(ContentControlType.Text, false); // Get our Case CustomXmlPart: var xmlPart = GetCustomXmlPartByName(doc, "Order"); var departmentNode = xmlPart.XmlDocument.SelectSingleNode(@"//*[local-name()='Department']"); // Mapping directly to XmlNode: departmentTextControl.XmlMapping.SetMapping(departmentNode); } // Create Delivery part, Checkbox custom control bound to Delivery node and Date custom control // bound to details of (possible) Delivery date.: private static void CreateDeliveryCheckbox(GcWordDocument doc) { var p = doc.Body.Paragraphs.Add(); // Create checkbox and map it to Shipping node of 'Case' CustomXmlPart: var checkBox = p.GetRange().ContentControls.Add(ContentControlType.CheckBox, false); // Here we demonstrate how to map CustomControl ignoring namespaces used in the xml. // This way should be avoided as much as possible as pretty inefficient: checkBox.XmlMapping.SetMapping(@"//*[local-name()='Delivery']"); p.GetRange().Runs.Add("Delivery should be done before "); // Add shipping Date control, bound to proper section of Order CustomXmlPart: var dateControl = p.GetRange().ContentControls.Add(ContentControlType.Date, false); dateControl.DateFormat = "dd.MM.yyyy"; // Here we demonstrate how to map CustomControl with namespaces usage, it allows us write // clean and straight XmlPath. Its the right way of XMlMapping: dateControl.XmlMapping.SetMapping(@"//mescius:Delivery/@DeliveryDate", @"xmlns:mescius='http://developer.mescius.com'"); } // Create XML from a string (see alternative method below): private static void CreateOrderCustomXmlFromString(GcWordDocument doc) { var sb = new System.Text.StringBuilder(201); const string ns = "'http://developer.mescius.com'"; sb.AppendLine(@"<Order xmlns=" + ns + ">"); sb.AppendLine(@" <To>Mark Donahue</To>"); sb.AppendLine(@" <Department>Shipping department</Department>"); sb.AppendLine(@" <Delivery DeliveryDate=""12.04.2019"">true</Delivery>"); sb.AppendLine(@"</Order>"); XmlDocument xml = new XmlDocument(); xml.LoadXml(sb.ToString()); CustomXmlPart xmlPart = doc.CustomXmlParts.Add(xml, Guid.NewGuid().ToString(), new string[] { ns }, "application/xml"); } // Create XML by adding individual nodes one by one // (this method is not used in this sample, the previous // alternative is used instead): private static void CreateOrderCustomXml(GcWordDocument doc) { // add a custom xml part with custom settings const string ns = "http://developer.mescius.com"; XmlDocument xml = new XmlDocument(); xml.AppendChild(xml.CreateXmlDeclaration("1.0", "utf-8", null)); XmlElement root = xml.CreateElement("Order", ns); xml.AppendChild(root); var to = root.AppendChild(xml.CreateElement("To", ns)); to.InnerText = "Mark Donahue"; var dep = root.AppendChild(xml.CreateElement("Department", ns)); dep.InnerText = "Shipping department"; XmlElement child = xml.CreateElement("Delivery", ns); child.InnerText = "true"; child.SetAttribute("DeliveryDate", "12.04.2019"); root.AppendChild(child); CustomXmlPart xmlPart = doc.CustomXmlParts.Add(xml, Guid.NewGuid().ToString(), new string[] { ns }, "application/xml"); // Sad story: we cannot apply schemas to our custom xml parts. // Unlike in Office excel (where a schema can be serialized inside a document), // it seems that Word can work with schema URIs only so we cannot place an xsd inside the document. // This means that we cannot implement native xml-mapping restrictiong and verifying like // xmlPart.Schemas.Add(CreateCelebrationScheme()); } } }