{"id":296,"date":"2014-09-08T12:23:59","date_gmt":"2014-09-08T02:23:59","guid":{"rendered":"http:\/\/www.docx4java.org\/blog\/?p=296"},"modified":"2014-09-08T12:23:59","modified_gmt":"2014-09-08T02:23:59","slug":"xhtml-docx-roundtrip-content-tracking","status":"publish","type":"post","link":"https:\/\/www.docx4java.org\/blog\/2014\/09\/xhtml-docx-roundtrip-content-tracking\/","title":{"rendered":"XHTML-docx roundtrip: content tracking"},"content":{"rendered":"<p>There are a couple of common use cases for docx4j&#8217;s XHTML import capability:<\/p>\n<p><span style=\"font-size: 13px;\">The first is <strong>enabling a webapp with HTML reporting <\/strong>to output\/export reports in Word&#8217;s docx format. \u00a0With docx4j, you can get really nice results doing this, especially if your XHTML has @class which map to Word styles.<\/span><\/p>\n<p><span style=\"font-size: 13px;\">The second &#8211; to <strong>support web based editing<\/strong> &#8211; is the subject of this post. \u00a0In a full incarnation, the vision is:<\/span><\/p>\n<ul>\n<li><span style=\"font-size: 13px;\">be able to edit the content in Word or in the web browser (using an XHTML editor such as CKEditor)<\/span><\/li>\n<li><span style=\"font-size: 13px;\">track chunks of content, perhaps for workflow\/approval processes, version control, or re-use<\/span><\/li>\n<\/ul>\n<p>docx4j can help you with this vision in a Java or .NET (eg C#) environment.<\/p>\n<p>Web based XHTML editing is well understood, so here I&#8217;ll focus on tracking chunks of content.<\/p>\n<p>In XHTML, its straightforward. \u00a0You can add div elements (eg &lt;div id=&#8221;contentXYZ&#8221;&gt;) to your heart&#8217;s content. \u00a0And you can nest them (think book, chapter, section, sub-section).<\/p>\n<p>How to track that ID to or from docx format?<\/p>\n<p>The answer: content controls.<\/p>\n<p>Bookmarks are another possibility, but I wouldn&#8217;t recommend them for this purpose, because it is easy for a user to delete them, or inadvertently insert extra bookmarks. \u00a0They lack the rich features of content controls (eg locking), and aren&#8217;t very &#8220;XMLy&#8221; (they are pairs of start and end point tags which create additional challenges).<\/p>\n<p>So, back to content controls.<\/p>\n<p>Content controls are analogous to divs. \u00a0They have IDs; you can nest them; etc.<\/p>\n<p>Content controls aside, the docx file format is flat. \u00a0Its a sequence of paragraphs and tables. \u00a0Its only inside tables that paragraphs also appear (and nested tables).<\/p>\n<p>So, all we need to do convert divs to content controls, and vice versa.<\/p>\n<p>This post tells you how to do that with docx4j.<\/p>\n<p><strong>XHTML to docx (div to content control)<\/strong><\/p>\n<p>For XHTML to docx, you use docx4j-ImportXHTML<\/p>\n<p>div to content control support was added after 3.2.0&#8217;s release, in <a href=\"https:\/\/github.com\/plutext\/docx4j-ImportXHTML\/commit\/38da87ed1f6cf198eab656e0abbc40e7e2f41749\">this commit<\/a>. \u00a0So for now, you need to build from source, or use a <a href=\"http:\/\/www.docx4java.org\/docx4j\/docx4j-ImportXHTML-nightly-20140907.jar\">nightly build<\/a>.<\/p>\n<p>Once you have that, t<span style=\"font-size: 13px;\">o use it, do something like:<\/span><\/p>\n<p>XHTMLImporterImpl XHTMLImporter = new XHTMLImporterImpl(wordMLPackage);<br \/>\nXHTMLImporter.<strong>setDivHandler(new DivToSdt());<\/strong><\/p>\n<p>That implementation will convert div elements to content controls, and place @id and @class values into the content control&#8217;s <a href=\"http:\/\/webapp.docx4java.org\/OnlineDemo\/ecma376\/WordML\/tag.html\">w:tag<\/a>, for example &#8220;class=class1&amp;id=myid&#8221;<\/p>\n<p>You can extend DivToSdt with any extra functionality\/logic you might require, such as <a href=\"http:\/\/webapp.docx4java.org\/OnlineDemo\/ecma376\/WordML\/lock.html\">locking<\/a> the content control for <a href=\"http:\/\/webapp.docx4java.org\/OnlineDemo\/ecma376\/WordML\/ST_Lock.html\">editing\/deletion<\/a>.<\/p>\n<p><strong>docx to XHTML (content control to div)<\/strong><\/p>\n<p>The content control to div functionality has been present for a lot longer.<\/p>\n<p>For that, you use docx4j to generate XHTML output in the usual way, but first you invoke <strong>SdtWriter.registerTagHandler<\/strong><\/p>\n<p>See the sample <a href=\"https:\/\/github.com\/plutext\/docx4j-ImportXHTML\/blob\/master\/src\/samples\/java\/org\/docx4j\/samples\/DivRoundtrip.java\">DivRoundtrip.java<\/a> for a fully worked example of divs to content controls, then back to divs again.<\/p>\n<p>The tag handler concept is to treat the content of the w:tag like an HTTP query string (key value pairs).<\/p>\n<p>A tag handler is registered for a specific key (eg &#8216;id&#8217;, &#8216;class&#8217;) or the wildcards (&#8216;*&#8217;, &#8216;**&#8217;), and will only execute if the key is found in the w:tag.<\/p>\n<p>For this example, we want our tag handler to insert a div depending on both class and id keys, so we register it as &#8216;*&#8217; (we don&#8217;t want 2 handlers, which might result in 2 divs).<\/p>\n<p>A tag handler with double asterisk &#8216;**&#8217; will always be applied if you need that. \u00a0See the SdtWriter source code for definitive behaviour.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>There are a couple of common use cases for docx4j&#8217;s XHTML import capability: The first is enabling a webapp with HTML reporting to output\/export reports in Word&#8217;s docx format. \u00a0With docx4j, you can get really nice results doing this, especially if your XHTML has @class which map to Word styles. The second &#8211; to support [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-296","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.docx4java.org\/blog\/wp-json\/wp\/v2\/posts\/296","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.docx4java.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.docx4java.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.docx4java.org\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.docx4java.org\/blog\/wp-json\/wp\/v2\/comments?post=296"}],"version-history":[{"count":2,"href":"https:\/\/www.docx4java.org\/blog\/wp-json\/wp\/v2\/posts\/296\/revisions"}],"predecessor-version":[{"id":298,"href":"https:\/\/www.docx4java.org\/blog\/wp-json\/wp\/v2\/posts\/296\/revisions\/298"}],"wp:attachment":[{"href":"https:\/\/www.docx4java.org\/blog\/wp-json\/wp\/v2\/media?parent=296"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.docx4java.org\/blog\/wp-json\/wp\/v2\/categories?post=296"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.docx4java.org\/blog\/wp-json\/wp\/v2\/tags?post=296"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}