Page 1 of 1

Inject converted html to custom xml

PostPosted: Thu Feb 07, 2013 10:10 pm
by kevins
Hi everybody!

I'm trying to inject some converted html to a custom field (define with xpath). Since it's not working, it seems that I did something wrong. :o

Here is the content of the customXml/item1.xml, where I injected the converted html into the <data> tag.

Thanks in adavnce for your help!

Kevin

Code: Select all
<?xml version="1.0" encoding="UTF-8"?>
<htmlProperty>
<data>
<w:p xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:c="http://schemas.openxmlformats.org/drawingml/2006/chart" xmlns:dgm="http://schemas.openxmlformats.org/drawingml/2006/diagram" xmlns:dsp="http://schemas.microsoft.com/office/drawing/2008/diagram" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:ns11="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing" xmlns:ns13="urn:schemas-microsoft-com:office:excel" xmlns:ns17="urn:schemas-microsoft-com:office:powerpoint" xmlns:ns24="http://schemas.openxmlformats.org/officeDocument/2006/bibliography" xmlns:ns25="http://schemas.openxmlformats.org/drawingml/2006/compatibility" xmlns:ns26="http://schemas.openxmlformats.org/drawingml/2006/lockedCanvas" xmlns:ns6="http://schemas.openxmlformats.org/schemaLibrary/2006/main" xmlns:ns8="http://schemas.openxmlformats.org/drawingml/2006/chartDrawing" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:odc="http://opendope.org/conditions" xmlns:odgm="http://opendope.org/SmartArt/DataHierarchy" xmlns:odi="http://opendope.org/components" xmlns:odq="http://opendope.org/questions" xmlns:odx="http://opendope.org/xpaths" xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing">
    <w:pPr>
        <w:numPr>
            <w:ilvl w:val="0"/>
            <w:numId w:val="1"/>
        </w:numPr>
        <w:jc w:val="left"/>
        <w:textAlignment w:val="auto"/>
    </w:pPr>
    <w:r>
        <w:rPr>
            <w:b/>
            <w:color w:val="000000"/>
            <w:sz w:val="22"/>
        </w:rPr>
        <w:t>Hello World!</w:t>
    </w:r>
</w:p>
</data>
</htmlProperty>

Re: Inject converted html to custom xml

PostPosted: Fri Feb 08, 2013 3:23 pm
by jason
You'll need to explain in more detail what you are trying to do, please.

What is your "custom field (define with xpath)"?

If it is anything like content control data binding, well, plain vanilla content control data binding binds text strings, not WordML structures. (The OpenDoPE extensions do allow you to bind escaped XHTML - docx4j converts this to WordML)

Re: Inject converted html to custom xml

PostPosted: Fri Feb 08, 2013 9:24 pm
by kevins
Hi Jason, thanks for your answer.

I finally discovered that the docx4j 2.8.1 version integrates xhtml conversion natively. :P

So the just thing to do (where I was wrong) is to put the xhtml into the CustomXml document in order to put it in word.

But I tried with an li tag, which is well converted to word but the li tag is still always present. (see the generated.docx)

Here is the part of my java code that generated the custom xml document that docx4j will use when applying binding.

Code: Select all
           
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document customXmlDocument = documentBuilder.newDocument();
Element element = customXmlDocument.createElement("htmlProperty");
Element dataElement = customXmlDocument.createElement("data");
dataElement.setTextContent("<li>test</li>");
element.appendChild(dataElement);
customXmlDocument.appendChild(element);


template.docx
Template
(25.7 KiB) Downloaded 478 times

generated.docx
Generated file
(24.85 KiB) Downloaded 484 times

Re: Inject converted html to custom xml

PostPosted: Sat Feb 09, 2013 12:40 am
by jason
Your content control must have a w:tag similar to the following:

Syntax: [ Download ] [ Hide ]
Using xml Syntax Highlighting
      <w:sdt>
        <w:sdtPr>
          <w:tag w:val="od:xpath=ML4nr&amp;od:ContentType=application/xhtml+xml"/>
 
Parsed in 0.000 seconds, using GeSHi 1.0.8.4


and it needs to be processed using OpenDoPEHandler.

The Word Add-In referenced in recent posts in the subforum will create an appropriate w:tag value.

Please note the following:

1. your HTML needs to be well formed XML, so:

(a) close all tags properly

(b) it must have a single root element

2. your HTML then needs to be escaped, for example:

<yourxml>&lt;div&gt; &lt;img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" /&gt; &lt;/div&gt; </yourxml>

3. the input XHTML must be suitable for the context ie you can't insert block level stuff (eg p) into a run level sdt, so for content like list items, use a block level content control.

Re: Inject converted html to custom xml

PostPosted: Sat Feb 09, 2013 2:18 am
by kevins
All the requirements you listed above are validated in my not working example :

The content control in document.xml :

Code: Select all
<w:sdt>
            <w:sdtPr>
                <w:tag w:val="od:xpath=xHtmlPropertyData&amp;od:ContentType=application/xhtml+xml"/>
                <w:id w:val="-1852166050"/>
                <w:dataBinding w:xpath="/htmlProperty/data" w:storeItemID="{E033670F-9199-483B-A728-17BEE7BB02AF}"/>
                <w:text/>
            </w:sdtPr>
            <w:sdtContent>
                <w:p>
                    <w:pPr>
                        <w:ind w:left="0"/>
                        <w:jc w:val="left"/>
                        <w:textAlignment w:val="auto"/>
                    </w:pPr>
                    <w:r>
                        <w:rPr>
                            <w:b/>
                            <w:color w:val="000000"/>
                        </w:rPr>
                        <w:t>test</w:t>
                    </w:r>
                </w:p>
            </w:sdtContent>
        </w:sdt>


1. The html is well formed and has a single root element :
Code: Select all
<h1>test</h1>


2. The custom xml content (it's well escaped):
Code: Select all
<?xml version="1.0" encoding="UTF-8"?><htmlProperty><data>&lt;li&gt;test&lt;/li&gt;</data></htmlProperty>


3. In this case (h1), it's suitable for the context.

I really don't know where the problem come from...?!

Thanks in advance for your help

Re: Inject converted html to custom xml

PostPosted: Sat Feb 09, 2013 2:45 am
by kevins
Here is the java code :

Code: Select all
try {
                    inputStream = getClass().getResourceAsStream("/template.docx");
                    WordprocessingMLPackage wordprocessingMLPackage = (WordprocessingMLPackage) loadFromZipNG.get(inputStream);
                   
                    // Creating custom data
                    DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
                    DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
                    Document customXmlDocument = documentBuilder.newDocument();
                    Element element = customXmlDocument.createElement("htmlProperty");
                    Element dataElement = customXmlDocument.createElement("data");
                    dataElement.setTextContent("<h1>test</h1>");
                    element.appendChild(dataElement);
                    customXmlDocument.appendChild(element);
                   
                    // Set the custom data to the custom part
                    CustomXmlDataStoragePart customXmlDataStoragePart = wordprocessingMLPackage
                            .getCustomXmlDataStorageParts().get
                                    ("{E033670F-9199-483B-A728-17BEE7BB02AF}".toLowerCase());
                   
                    CustomXmlDataStorage data = new CustomXmlDataStorageImpl();
                    data.setDocument(customXmlDocument);
                    customXmlDataStoragePart.setData(data);
                   
                    // OpenDoPEHandler processing
                    wordprocessingMLPackage = new OpenDoPEHandler(wordprocessingMLPackage).preprocess();
                   
                    // Applying bindings
                    BindingHandler.applyBindings(wordprocessingMLPackage.getMainDocumentPart());
                    wordprocessingMLPackage.save(new File("generated.docx"));
                } catch (Docx4JException e) {
                    logger.warn(e.getMessage(), e);
                } catch (ParserConfigurationException e) {
                    logger.warn(e.getMessage(), e);
                }

Re: Inject converted html to custom xml

PostPosted: Sun Feb 10, 2013 7:04 pm
by jason
Worked for me when I ran it through sample ContentControlBindingExtensions, after I removed the following from your content control:

Syntax: [ Download ] [ Hide ]
Using xml Syntax Highlighting
        <w:dataBinding w:xpath="/htmlProperty/data" w:storeItemID="{E033670F-9199-483B-A728-17BEE7BB02AF}"/>
        <w:text/>
 
Parsed in 0.000 seconds, using GeSHi 1.0.8.4

Re: Inject converted html to custom xml

PostPosted: Tue Feb 12, 2013 10:22 am
by kvmc09302012
Hi,
I did follow the above steps (as said by Jason and removed the <w:dataBinding w:xpath="/htmlProperty/data" w:storeItemID="{E033670F-9199-483B-A728-17BEE7BB02AF}"/><w:text/> tag) from the document template and was able to replace with HTML content in the generated document. I've a few queries:

1) How did you add the custom xml tag or <w:tag into the word template. Can you give me the steps. How did the your code knew it has to replace the test place holder in template with the html value?

2) I have a requirement where the user is allowed to create/design a template on his own and use the predefined place holders to substitute values from the database at run-time. The place holder values can be simple string or may contain HTML content.

3) Can the above approach be used to replace multiple string and html place holders ?

Thanks.

Re: Inject converted html to custom xml

PostPosted: Tue Feb 12, 2013 10:36 am
by jason
kvmc09302012 wrote:1) How did you add the custom xml tag or <w:tag into the word template. Can you give me the steps.


I use an OpenDoPE Word Add-In; there is an older one and a newer one; the newer one is the one you want.

kvmc09302012 wrote:How did the your code knew it has to replace the test place holder in template with the html value?


Because of the od:ContentType=application/xhtml+xml in the w:tag, and the XPath expression in the XPaths part which is pointed to by od:xpath

kvmc09302012 wrote:2) I have a requirement where the user is allowed to create/design a template on his own and use the predefined place holders to substitute values from the database at run-time. The place holder values can be simple string or may contain HTML content.


You'll need to map the database content to an XML structure. Then the author can use the OpenDoPE authoring tool with an example of the XML structure, to create/design their template.

kvmc09302012 wrote:3) Can the above approach be used to replace multiple string and html place holders ?


Yes.

Re: Inject converted html to custom xml

PostPosted: Wed Feb 13, 2013 9:18 am
by kvmc09302012
Thanks for your reply and I installed the openDoPE tool and was able to add a custom xml tag and run a simple program to replace the content on run time. I have some more queries on this:

1) I added a simple traditional bind and gave it an xpath id. Now how do you map this tag to a value at run time. I see in your code that you do something like this:
Code: Select all
CustomXmlDataStoragePart customXmlDataStoragePart = wordMLPackage
                    .getCustomXmlDataStorageParts().get("{E033670F-9199-483B-A728-17BEE7BB02AF}".toLowerCase());

            CustomXmlDataStorage data = new CustomXmlDataStorageImpl();
            data.setDocument(customXmlDocument);
            customXmlDataStoragePart.setData(data);

The Id {E033670F-9199-483B-A728-17BEE7BB02AF} is used to refer to custom xml node and replace it with the new value at run-time. This id value is obtained only if we open the document.xml and look for <w:dataBinding element for the specified xpath.
Code: Select all
<w:dataBinding w:xpath="/yourxml" w:storeItemID="{DC5868F8-7363-412F-A580-0E8370C8EF27}"/>

Looks like this w:storeItemID is system generated. So every time I create a template and add custom tag, then I have to open the document.xml manually and read the ID and update my java code with this id and recompile and rerun. Is there and alternative where I dont have to recompile the code.

2) While creating a custom xml tag, I gave an xpath Id (myxpathid1111 in the below xml fragment) which appears in the xml document. Is there a way I can use this to replace the value at runtime without using the w:storeItemId.
Code: Select all
<w:body><w:p w:rsidR="009C57F0" w:rsidRDefault="009C57F0"><w:r><w:t>This is a sample template.</w:t></w:r></w:p><w:sdt><w:sdtPr><w:tag w:val="od:condition=mycondid1"/><w:id w:val="-801685726"/><w:placeholder><w:docPart w:val="DefaultPlaceholder_1082065158"/></w:placeholder></w:sdtPr><w:sdtEndPr/><w:sdtContent><w:sdt><w:sdtPr><w:tag w:val="od:xpath=myxpathid1111"/><w:id w:val="1837268323"/><w:placeholder><w:docPart w:val="DefaultPlaceholder_1082065158"/></w:placeholder><w:dataBinding w:xpath="/yourxml" w:storeItemID="{DC5868F8-7363-412F-A580-0E8370C8EF27}"/><w:text w:multiLine="1"/></w:sdtPr><w:sdtEndPr/>



3) In your sample template I see the below lines:
Code: Select all
<w:tag w:val="od:xpath=xHtmlPropertyData&amp;od:ContentType=application/xhtml+xml"/>


How did you set the od:ContentType=application/xhtml+xml and od:xpath attributes. Do we have to manipulate the document.xml manually or can this be done using the openDoPE tool ?

4) In your template's xml fragement, you have something like this
Code: Select all
<w:tag w:val="od:xpath=xHtmlPropertyData&amp;od:ContentType=application/xhtml+xml"/>


is the xHtmlPropertyData represents any keyword or does it represent your xml's data's structure?
Code: Select all
<htmlProperty><data>some date</data></htmlProperty>


I presume, it represents the keyword.

6) Actually my requirement is, the user creates a templates on the fly ( ofcourse the name of the place holders are predefined), adds the predefined place holders on the document at required spots in the document, saves them and clicks a generate button in the application. The output of this operation is the application should open the template automatically and do the transformation with place holders texts being replaced with value at the run time and return the generated document to user.

thanks.

Thanks.

Re: Inject converted html to custom xml

PostPosted: Wed Feb 13, 2013 10:08 am
by jason
kvmc09302012 wrote:The Id {E033670F-9199-483B-A728-17BEE7BB02AF} is used to refer to custom xml node and replace it with the new value at run-time. This id value is obtained only if we open the document.xml and look for <w:dataBinding element for the specified xpath.
Looks like this w:storeItemID is system generated. So every time I create a template and add custom tag, then I have to open the document.xml manually and read the ID and update my java code with this id and recompile and rerun. Is there and alternative where I dont have to recompile the code.


Do those steps programmatically, or:

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
        /**
         * We need the item id of the custom xml part.  
         *
         * There are several strategies we could use to find it,
         * including searching the docx for a bind element, but
         * here, we simply look in the xpaths part.
         *
         * @param wordMLPackage
         * @return
         */

        public static String getCustomXmlItemId(WordprocessingMLPackage wordMLPackage) throws Docx4JException {
               
                MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart();                   
                if (wordMLPackage.getMainDocumentPart().getXPathsPart()==null) {
                        throw new Docx4JException("OpenDoPE XPaths part missing");
                }
       
                org.opendope.xpaths.Xpaths xPaths = wordMLPackage.getMainDocumentPart().getXPathsPart().getJaxbElement();
               
                return xPaths.getXpath().get(0).getDataBinding().getStoreItemID();
               
        }
 
Parsed in 0.015 seconds, using GeSHi 1.0.8.4


kvmc09302012 wrote:2) While creating a custom xml tag, I gave an xpath Id (myxpathid1111 in the below xml fragment) which appears in the xml document. Is there a way I can use this to replace the value at runtime without using the w:storeItemId.


With both plain vanilla data binding and the OpenDoPE extensions, in principle individual XPaths could be references into different XML stores. The w:storeItemId is used to specify which one, so you need it.

kvmc09302012 wrote:How did you set the od:ContentType=application/xhtml+xml and od:xpath attributes. Do we have to manipulate the document.xml manually or can this be done using the openDoPE tool ?


The tool should do this automatically, if it detects the element you are binding contains XHTML.

kvmc09302012 wrote:4) In your template's xml fragement, you have something like this
<w:tag w:val="od:xpath=xHtmlPropertyData&amp;od:ContentType=application/xhtml+xml"/>

is the xHtmlPropertyData represents any keyword or does it represent your xml's data's structure?


The value of od:xpath is essentially an IDREF into the XPaths part. In there, you'll find an entry with that ID, containing an XPath and storeItemID

Re: Inject converted html to custom xml

PostPosted: Thu Feb 14, 2013 5:58 am
by kvmc09302012
Thanks for the reply and I tried your steps and it worked. I was able to get the store item id programmatically.
However, I couldn't get html part to work. I could't set the content type to xhtml
Code: Select all
<w:tag w:val="od:xpath=xHtmlPropertyData&amp;od:ContentType=application/xhtml+xml"/>


The tool should do this automatically, if it detects the element you are binding contains XHTML.

I added a new binding variable and binded the <address> node's xpath to it. The content of the address node is html value. But when the conversion happened, it showed the node as is and didn't transform the html. Also, the document.xml didn't have od:path as od:xpath=xHtmlPropertyData&amp;od:ContentType=application/xhtml+xml.

My xml node is
Code: Select all
<person>
   <lastname>my last name</lastname>
   <firstname>my First name</firstname>
   <age>30</age>
   <address>
      &lt;h1&gt;my address, city, state. &lt;/h1&gt;
   </address>
</person>


I am listing the steps I followed to add a html custom node using opendope add in.

1) Opened the word document.
2) clicked on OpenDope ribbon
3) Clicked on Bind this text.
4) Entered a text and clicked on Bind This button in the task pane.
5) Pasted my custom xml. Clicked on the Address node.
6) Gave an xpath id and clicked on Use this xPath button.
7) Saved the document.
8)Opened the document.xml to see if the contentType is set to xhtml, but didn't find it.

Please let me know if I am doing something wrong.

Thanks.

Re: Inject converted html to custom xml

PostPosted: Sat Feb 23, 2013 5:05 am
by kvmc09302012
Any inputs will be of great help. Hope my question is clear.

Re: Inject converted html to custom xml

PostPosted: Sun Feb 24, 2013 12:45 pm
by jason
I've just responded to your other post (which is the one in the right place). Sorry for the delay.

Please don't post in more than one place. This just creates more work for me, since its undesirable to leave any of them looking as if the question went unanswered.