{"id":62,"date":"2011-10-11T10:34:38","date_gmt":"2011-10-11T15:34:38","guid":{"rendered":"http:\/\/www.teamdesk.net\/blog\/2011\/10\/docx-generation-improvements\/"},"modified":"2011-10-11T10:34:38","modified_gmt":"2011-10-11T15:34:38","slug":"docx-generation-improvements","status":"publish","type":"post","link":"https:\/\/www.teamdesk.net\/blog\/whats-new\/docx-generation-improvements\/","title":{"rendered":"DOCX generation improvements"},"content":{"rendered":"<p><em>Recently we encountered some issues with DOCX templates created in Word 2010. <\/em><em>Unlike its predecessor Word 2010 uses more complicated constructs for merge fields we use for placeholders and we did not recognize such definitions properly. We revised merge fields identification algorithm, fixed few other issues by the way and step by step ended up with completely new document generation algorithm.<\/em><\/p>\n<p>Our old client-side .DOC generation module used Word Automation to expand the template. When we started working on server-side code, we simply replicated old algorithm with all the quirks \u2013 this helped us to ensure that movement from old to new technology will produce (nearly) identical results.<\/p>\n<p>Yet, one part definitely needed improvement: the detail records generation. Due to lack of suitable methods in the automation our code had somehow sophisticated algorithm that tracked row and column index of each placeholder in the detail table and performed replacement of whole cells, not just the placeholders. This caused some formatting and layout restrictions, for example, the font and color should be defined for the cell as whole, not for the content of the cell; nested tables were not allowed.<\/p>\n<p>Now, generator works more straightforward from user&#8217;s perspective. First we replace all master-level placeholder in the document wherever they are placed. Next, we generate detail tables one by one. Here we have to repeat some part of template for each detail record. Due to lack of non-visual markers in a Word documents and for backward compatibility we define repeatable item the table row. We find and locate all the placeholder for detail table and find innermost table row they have in common. This row will be repeatable block. For each record we clone the row with all placeholders, replace the placeholders and insert now-expanded content back into the table. Here are illustrations:<\/p>\n<table border=\"1\" cellspacing=\"1\" cellpadding=\"2\" width=\"500\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"120\"><strong>Column 1<\/strong><\/td>\n<td valign=\"top\" width=\"212\"><strong>Column 2 * Column 3<\/strong><\/td>\n<\/tr>\n<tr bgcolor=\"#cccccc\">\n<td valign=\"top\" width=\"120\">\u00abDetail\/Column 1\u00bb<\/td>\n<td valign=\"top\" width=\"212\">\u00abDetail\/Column 2\u00bb <strong>some text <\/strong>\u00abDetail\/Column 3\u00bb<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The row marked gray will be repeatable block since it&#8217;s a common row for all detail placeholders. Since we now operate on a field level, single table cell can contain several placeholders and\/or text around the placeholders.<\/p>\n<p>Now, more complicated layout:<\/p>\n<table border=\"1\" cellspacing=\"1\" cellpadding=\"2\" width=\"499\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"120\"><strong>Master Info<\/strong><\/td>\n<td valign=\"top\" width=\"374\"><strong>Detail<\/strong><\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"120\">\u00abMaster Info\u00bb<\/td>\n<td valign=\"top\" width=\"374\">\n<table border=\"1\" cellspacing=\"1\" cellpadding=\"2\" width=\"373\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"166\"><strong>Column 1<\/strong><\/td>\n<td valign=\"top\" width=\"202\"><strong>Column 2<\/strong><\/td>\n<\/tr>\n<tr bgcolor=\"#cccccc\">\n<td valign=\"top\" width=\"166\">\u00abDetail\/Column 1\u00bb<\/td>\n<td valign=\"top\" width=\"202\">\u00abDetail\/Column 2\u00bb<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Here we nest detail table into another table. The repeatable block is the row in the inner table since this one is <strong>innermost<\/strong> common to both detail placeholders. And now even more complicated:<\/p>\n<table border=\"1\" cellspacing=\"1\" cellpadding=\"2\" width=\"500\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"136\"><strong>Column 1<\/strong><\/td>\n<td valign=\"top\" width=\"364\"><strong>Mixed Content<\/strong><\/td>\n<\/tr>\n<tr bgcolor=\"#cccccc\">\n<td valign=\"top\" width=\"136\">\u00abDetail\/Column 1\u00bb<\/td>\n<td valign=\"top\" width=\"364\">\n<table border=\"1\" cellspacing=\"1\" cellpadding=\"2\" width=\"359\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"176\"><strong>Master Info<\/strong><\/td>\n<td valign=\"top\" width=\"178\"><strong>Column 2<\/strong><\/td>\n<\/tr>\n<tr>\n<td valign=\"top\" width=\"176\">\u00abMaster Info\u00bb<\/td>\n<td valign=\"top\" width=\"178\">\u00abDetail\/Column 2\u00bb<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Here, the row in outer table will be repeated since it&#8217;s common for both detail placeholders. There is no problem for inner table to contain master information \u2013 it will be simply repeated for each row in the detail table.<\/p>\n<p>We are trying to preserve the text formatting wherever possible, but formatting should be applied to placeholder as a whole. Many Word&#8217;s formatting commands apply to a word the cursor placed on. As we replace the placeholder completely, we do not preserve the styling defined within the placeholder. Moreover, if multiple styles are defined for placeholder content, it&#8217;s not clear what style to use for content. For example, what font, size, style and color we should use when replacing this?<\/p>\n<p>\u00ab<font size=\"5\" face=\"Times New Roman\"><em><strong>Master<\/strong><\/em><\/font> <font style=\"background-color: #ffff00\" size=\"4\"><strong>Info<\/strong><\/font>\u00bb<\/p>\n<p>As a bonus, we&#8217;ve added column usage information for the documents. Make any change in your app, save and columns will start to report their usage in the DOCX documents.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Recently we encountered some issues with DOCX templates created in Word 2010. Unlike its predecessor Word 2010 uses more complicated constructs for merge fields we use for placeholders and we did not recognize such definitions properly. We revised merge fields identification algorithm, fixed few other issues by the way and step by step ended up [&hellip;]<\/p>\n","protected":false},"author":4,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"class_list":["post-62","post","type-post","status-publish","format-standard","hentry","category-whats-new"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>DOCX generation improvements - TeamDesk Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.teamdesk.net\/blog\/whats-new\/docx-generation-improvements\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"DOCX generation improvements - TeamDesk Blog\" \/>\n<meta property=\"og:description\" content=\"Recently we encountered some issues with DOCX templates created in Word 2010. Unlike its predecessor Word 2010 uses more complicated constructs for merge fields we use for placeholders and we did not recognize such definitions properly. We revised merge fields identification algorithm, fixed few other issues by the way and step by step ended up [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.teamdesk.net\/blog\/whats-new\/docx-generation-improvements\/\" \/>\n<meta property=\"og:site_name\" content=\"TeamDesk Blog\" \/>\n<meta property=\"article:published_time\" content=\"2011-10-11T15:34:38+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2024\/01\/logo_og.png\" \/>\n\t<meta property=\"og:image:width\" content=\"600\" \/>\n\t<meta property=\"og:image:height\" content=\"315\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Kirill Bondar\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Kirill Bondar\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"3 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/whats-new\\\/docx-generation-improvements\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/whats-new\\\/docx-generation-improvements\\\/\"},\"author\":{\"name\":\"Kirill Bondar\",\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/#\\\/schema\\\/person\\\/22c4c05bd657513c8b00122fa364c8d2\"},\"headline\":\"DOCX generation improvements\",\"datePublished\":\"2011-10-11T15:34:38+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/whats-new\\\/docx-generation-improvements\\\/\"},\"wordCount\":561,\"commentCount\":2,\"articleSection\":[\"What's New\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/whats-new\\\/docx-generation-improvements\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/whats-new\\\/docx-generation-improvements\\\/\",\"url\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/whats-new\\\/docx-generation-improvements\\\/\",\"name\":\"DOCX generation improvements - TeamDesk Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/#website\"},\"datePublished\":\"2011-10-11T15:34:38+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/#\\\/schema\\\/person\\\/22c4c05bd657513c8b00122fa364c8d2\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/whats-new\\\/docx-generation-improvements\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/whats-new\\\/docx-generation-improvements\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/whats-new\\\/docx-generation-improvements\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"DOCX generation improvements\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/\",\"name\":\"TeamDesk Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/#\\\/schema\\\/person\\\/22c4c05bd657513c8b00122fa364c8d2\",\"name\":\"Kirill Bondar\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/dc5bc844095b5753ccc73c589c028bf16615674f289668146bbd59205a08a52d?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/dc5bc844095b5753ccc73c589c028bf16615674f289668146bbd59205a08a52d?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/dc5bc844095b5753ccc73c589c028bf16615674f289668146bbd59205a08a52d?s=96&d=mm&r=g\",\"caption\":\"Kirill Bondar\"},\"url\":\"https:\\\/\\\/www.teamdesk.net\\\/blog\\\/author\\\/kirill-bondar\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"DOCX generation improvements - TeamDesk Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.teamdesk.net\/blog\/whats-new\/docx-generation-improvements\/","og_locale":"en_US","og_type":"article","og_title":"DOCX generation improvements - TeamDesk Blog","og_description":"Recently we encountered some issues with DOCX templates created in Word 2010. Unlike its predecessor Word 2010 uses more complicated constructs for merge fields we use for placeholders and we did not recognize such definitions properly. We revised merge fields identification algorithm, fixed few other issues by the way and step by step ended up [&hellip;]","og_url":"https:\/\/www.teamdesk.net\/blog\/whats-new\/docx-generation-improvements\/","og_site_name":"TeamDesk Blog","article_published_time":"2011-10-11T15:34:38+00:00","og_image":[{"width":600,"height":315,"url":"https:\/\/www.teamdesk.net\/blog\/wp-content\/uploads\/2024\/01\/logo_og.png","type":"image\/png"}],"author":"Kirill Bondar","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Kirill Bondar","Est. reading time":"3 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.teamdesk.net\/blog\/whats-new\/docx-generation-improvements\/#article","isPartOf":{"@id":"https:\/\/www.teamdesk.net\/blog\/whats-new\/docx-generation-improvements\/"},"author":{"name":"Kirill Bondar","@id":"https:\/\/www.teamdesk.net\/blog\/#\/schema\/person\/22c4c05bd657513c8b00122fa364c8d2"},"headline":"DOCX generation improvements","datePublished":"2011-10-11T15:34:38+00:00","mainEntityOfPage":{"@id":"https:\/\/www.teamdesk.net\/blog\/whats-new\/docx-generation-improvements\/"},"wordCount":561,"commentCount":2,"articleSection":["What's New"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.teamdesk.net\/blog\/whats-new\/docx-generation-improvements\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.teamdesk.net\/blog\/whats-new\/docx-generation-improvements\/","url":"https:\/\/www.teamdesk.net\/blog\/whats-new\/docx-generation-improvements\/","name":"DOCX generation improvements - TeamDesk Blog","isPartOf":{"@id":"https:\/\/www.teamdesk.net\/blog\/#website"},"datePublished":"2011-10-11T15:34:38+00:00","author":{"@id":"https:\/\/www.teamdesk.net\/blog\/#\/schema\/person\/22c4c05bd657513c8b00122fa364c8d2"},"breadcrumb":{"@id":"https:\/\/www.teamdesk.net\/blog\/whats-new\/docx-generation-improvements\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.teamdesk.net\/blog\/whats-new\/docx-generation-improvements\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.teamdesk.net\/blog\/whats-new\/docx-generation-improvements\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.teamdesk.net\/blog\/"},{"@type":"ListItem","position":2,"name":"DOCX generation improvements"}]},{"@type":"WebSite","@id":"https:\/\/www.teamdesk.net\/blog\/#website","url":"https:\/\/www.teamdesk.net\/blog\/","name":"TeamDesk Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.teamdesk.net\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.teamdesk.net\/blog\/#\/schema\/person\/22c4c05bd657513c8b00122fa364c8d2","name":"Kirill Bondar","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/dc5bc844095b5753ccc73c589c028bf16615674f289668146bbd59205a08a52d?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/dc5bc844095b5753ccc73c589c028bf16615674f289668146bbd59205a08a52d?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/dc5bc844095b5753ccc73c589c028bf16615674f289668146bbd59205a08a52d?s=96&d=mm&r=g","caption":"Kirill Bondar"},"url":"https:\/\/www.teamdesk.net\/blog\/author\/kirill-bondar\/"}]}},"_links":{"self":[{"href":"https:\/\/www.teamdesk.net\/blog\/wp-json\/wp\/v2\/posts\/62","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.teamdesk.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.teamdesk.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.teamdesk.net\/blog\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/www.teamdesk.net\/blog\/wp-json\/wp\/v2\/comments?post=62"}],"version-history":[{"count":0,"href":"https:\/\/www.teamdesk.net\/blog\/wp-json\/wp\/v2\/posts\/62\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.teamdesk.net\/blog\/wp-json\/wp\/v2\/media?parent=62"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.teamdesk.net\/blog\/wp-json\/wp\/v2\/categories?post=62"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.teamdesk.net\/blog\/wp-json\/wp\/v2\/tags?post=62"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}