Page 1 of 1

Filling out a template with Strings of data

PostPosted: Wed Sep 08, 2010 7:05 am
by dcole
Hello,

I have a template that contains both freeform text areas, drop down boxes, and date drop down boxes. Can I use docx4j to fill this template out with this mixed content? What are the examples on the site I need to be following? I obviously want to keep my style parameters in the template, but for some of the places we expect bulleted lists to come in, and there can be any number of them. Do I have to construct each of these paragraph XML lines in the code, insert the text, and loop over all the entries for that section?

Most of the fields int he template are simply denoted by something like <Employee_Name>, do you just search for that string, and replace that text?

Thanks for any insight. This is my first attempt at messing around with any kind of xml documents

Re: Filling out a template with Strings of data

PostPosted: Wed Sep 08, 2010 9:16 am
by dcole
So, I have been doing some reading on the internet, and on this site, and I have come up with this basic idea, Perhaps you can tell me if it is close to what I need to do..thanks !

I read on some blog that you can make a custom binding XML document for a template. I am not exactly sure what this means. Does it mean that it is bound to the main document, and so if I change values in the custom XML document, those values will change in the real document?

If so - I should figure out how to create this custom binding XML document. Then substitute in my values to that custom document. Then in my main document, substitute in my new CustomBindingXML document, and then the new values will show up in the real document, correct?

Perhaps you can break this down for me more, pointing to the appropriate articles to read on how to do each step. Thanks!

Re: Filling out a template with Strings of data

PostPosted: Wed Sep 08, 2010 9:34 am
by jason
Hi, yes, a custom XML binding is the modern way to do this. It is based on "content controls" (w:sdt).

Have you seen our Getting Started guide? (see link at top of forum). That describes how to do it on about p20. There is a sample in org.docx4j.samples called CustomXmlBinding.

(Alternatively, the Getting Started guide also describes how to replace ${key1} in a string of wml using unmarshallFromTemplate)

Your existing document with the freeform text areas, drop down boxes, and date drop down boxes - is this an old-school Word form? These would need to be converted to content controls in order to use the custom XML binding approach.

If your document contains legacy mail merge fields, simple VBA for migrating a document is available at http://blogs.msdn.com/b/microsoft_offic ... trols.aspx

Re: Filling out a template with Strings of data

PostPosted: Wed Sep 08, 2010 11:06 am
by dcole
Since I am completely new to this - I found a documentation online that lets you use Visual Studio to create the custom content controls - is this the typical way of doing this?

I kind of want to stay away from the string replacement method if at all possible. Some people may fill this template out by hand, and so it'd be better to have a controlled input method.

I couldnt find the MedicalSample chart - can you provide a direct link? Is the itemID in the sample program some ID that a customXML document gets to store data portions in kind of like the MainDocumentPart of the word doc? How did you determine the path in the value-setting function setNodeValueAtXPath()?

Maybe some of these questions will be obvious once I can find the sample document - thanks for the help though!

Re: Filling out a template with Strings of data

PostPosted: Wed Sep 08, 2010 1:39 pm
by jason
dcole wrote:Since I am completely new to this - I found a documentation online that lets you use Visual Studio to create the custom content controls - is this the typical way of doing this?


Use the Content Control Toolkit:- http://dbe.codeplex.com/

(If you build it, you'd do so using Visual Studio. I suspect it is also available as a VS extension, and this may be what you are referring to. But you can download a standalone version, and that is what i have used in the past)

dcole wrote:I couldnt find the MedicalSample chart - can you provide a direct link? Is the itemID in the sample program some ID that a customXML document gets to store data portions in kind of like the MainDocumentPart of the word doc?


There is a link to the MedicalSample somewere at dbe.codeplex.com

The itemID specifies the custom XML part (in case there is more than one in the document).

dcole wrote:How did you determine the path in the value-setting function setNodeValueAtXPath()?


The content control toolkit will define the XPaths, and put them in the content controls.

If you are injecting an entire custom XML part into your docx (there are earlier forum posts on this), you shouldn't need to setNodeValueAtXPath. If you instead choose to update individual values in your custom XML, then it is up to you to work out what XPath to use (although it would typically be the same as the XPath the content control toolkit injects into your content controls.

Hope this helps..

Re: Filling out a template with Strings of data

PostPosted: Thu Sep 09, 2010 3:08 am
by dcole
I think I understand what you mean, but I just want to make sure.

If I have already mapped a custom XML to my document, then each of the content controls has a tag, Xpath, itemID and all that associated with it. I got all this by going through my template, giving the fields tags, and doing the mapping myself. Since this is already done, I could now use the setNodeValueAtXPath() function to change the value of any and all fields in the document, provided I somehow supply those itemID's and Xpath values, etc. This is a viable solution if my itemID's never change, right? In other words, I always know that the field Name for the CustomXML is going to map to itemID={FF1A9384-B406-488E-8E72-B61DABF0AA39} and the associated Xpath and Prefix mapping. Is there a way to only use the field's Tag info, so that if the Template changes, but the tags all stay the same, the injection of the custom data still works? As I just described seems like it would really only be best if the template was always going to be the same, right?


That all being said - is that what you meant by the second part of your comments - about injecting an entire customXML into my document? If I have written some Java to marshal objects to XML so that I get something like this for the employee object, lets say:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employee>
<code>CA</code>
<name>Cath</name>
<salary>300</salary>
</employee>

Then what's enclosed by the salary tags there maps to the field called "salary" in my document, right? The customXML knows nothing of the namespace, XPath, or ID. Would that work? I suspect not, right, because I would still have to go into the Content Control toolkit and make the mapping from "salary" to the salary content control box int he document, right? I am basing this off of the info I got here: http://blogs.msdn.com/b/modonovan/archi ... 04704.aspx

One final question, lets pretend this template is for Employees at a company. I want each employee to tell me their previous employers. For some this will be none, and for some this will be up to 10, lets say. Each previous employer has a set of similar fields - name, addresss, dates served, position title.

What is the best way to inject this into the template for each employee when I dont know ahead of time how many of these there will be in the document? Would it be best to not even use a content control here, and just generate the XML to output the text strings I have holding this info, in the style I want it, directly into the document? This way I would have a loop over the previous employers, and just output all of the data as I want it - kind of a "manual content control" or is there a way to inject the same fields over and over again with different data each time?

Re: Filling out a template with Strings of data

PostPosted: Thu Sep 09, 2010 7:33 am
by dcole
While I am at it - I attempted to run the MedicalChart sample. I was able to get this running, however, I wanted to save my output. I tried to do a wordMLPackage.save() and the output file will not open in Word.

I just added this to the end:

wordMLPackage.save(new java.io.File(System.getProperty("user.dir") + "/ad.docx") );

Is this something you have seen? Word spits back an "Unspecified error"

Re: Filling out a template with Strings of data

PostPosted: Thu Sep 09, 2010 10:13 am
by jason
dcole wrote:If I have already mapped a custom XML to my document, then each of the content controls has a tag, Xpath, itemID and all that associated with it. I got all this by going through my template, giving the fields tags, and doing the mapping myself.


It is worth checking you have done this correctly, by opening the docx in Word, and confirming that the values in the custom XML part appear in the relevant locations in the document.

dcole wrote:Since this is already done, I could now use the setNodeValueAtXPath() function to change the value of any and all fields in the document, provided I somehow supply those itemID's and Xpath values, etc. This is a viable solution if my itemID's never change, right?


Correct. From the sample:
Code: Select all
      CustomXmlDataStoragePart customXmlDataStoragePart = wordMLPackage.getCustomXmlDataStorageParts().get(itemId);
      
      // Get the contents      
      CustomXmlDataStorage customXmlDataStorage = customXmlDataStoragePart.getData();

      // Change its contents      ((CustomXmlDataStorageImpl)customXmlDataStorage).setNodeValueAtXPath("/ns0:chart[1]/ns0:personal[1]/ns0:name[1]", example_value_to_inject,
            "xmlns:ns0='http://schemas.medchart'");


You need to get the correct CustomXmlDataStoragePart (and its CustomXmlDataStorage) in order to setNodeValueAtXPath.

As per the sample, getting it via itemId is one way of doing this.

dcole wrote:In other words, I always know that the field Name for the CustomXML is going to map to itemID={FF1A9384-B406-488E-8E72-B61DABF0AA39} and the associated Xpath and Prefix mapping. Is there a way to only use the field's Tag info, so that if the Template changes, but the tags all stay the same, the injection of the custom data still works? As I just described seems like it would really only be best if the template was always going to be the same, right?


The binding (XPath) info is in the binding element, not the tag element. So its the binding element in the content control which must be preserved.

dcole wrote:That all being said - is that what you meant by the second part of your comments - about injecting an entire customXML into my document? If I have written some Java to marshal objects to XML so that I get something like this for the employee object, lets say:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employee>
<code>CA</code>
<name>Cath</name>
<salary>300</salary>
</employee>

Then what's enclosed by the salary tags there maps to the field called "salary" in my document, right? The customXML knows nothing of the namespace, XPath, or ID. Would that work? I suspect not, right, because I would still have to go into the Content Control toolkit and make the mapping from "salary" to the salary content control box int he document, right? I am basing this off of the info I got here: http://blogs.msdn.com/b/modonovan/archi ... 04704.aspx


It should work. The mapping stuff you do in the content control toolkit sets the binding in the content controls. It doesn't need to write any kind of mapping into the XML part.

See further viewtopic.php?f=6&t=381

Of course, if you have namespaces specified in your bindings, these must match.

dcole wrote:One final question, lets pretend this template is for Employees at a company. I want each employee to tell me their previous employers. For some this will be none, and for some this will be up to 10, lets say. Each previous employer has a set of similar fields - name, addresss, dates served, position title.

What is the best way to inject this into the template for each employee when I dont know ahead of time how many of these there will be in the document? Would it be best to not even use a content control here, and just generate the XML to output the text strings I have holding this info, in the style I want it, directly into the document? This way I would have a loop over the previous employers, and just output all of the data as I want it - kind of a "manual content control" or is there a way to inject the same fields over and over again with different data each time?


The content control binding extensions - implemented in docx4j - are designed specifically to handle this :-) See "Binding extensions for repeats and conditionals" in the Getting Started guide.

Re: Filling out a template with Strings of data

PostPosted: Thu Sep 09, 2010 11:13 am
by jason
dcole wrote:While I am at it - I attempted to run the MedicalChart sample. I was able to get this running, however, I wanted to save my output. I tried to do a wordMLPackage.save() and the output file will not open in Word.

I just added this to the end:

wordMLPackage.save(new java.io.File(System.getProperty("user.dir") + "/ad.docx") );

Is this something you have seen? Word spits back an "Unspecified error"


In the sample, itemId needs .toLowerCase() applied to it. http://dev.plutext.org/trac/docx4j/changeset/1211

Without this, a NPE was being thrown.

Once I fixed that, the result opens fine in Word 2007 for me.

Check your output file contains content? Try to unzip it?

Re: Filling out a template with Strings of data

PostPosted: Fri Sep 10, 2010 12:36 am
by dcole
I actually only get the NPE when I change that itemID to lowercase. Leaving it as is -the sample run completes sucessfully, but the file is still giving an error. I checked and it does indeed have all of the files in it, including my injected value in item1.xml, but I am still getting the "Unspecified error" from word. When I click on details it says it is in /word/document.xml, line:1 column: 3540

Also - thanks for the help and explanations. I think I am about to get it, just a few minor snags left to overcome!

Re: Filling out a template with Strings of data

PostPosted: Fri Sep 10, 2010 12:55 am
by dcole
I just downloaded your updated source and re-downloaded teh medical sample chart. It gives me an NPE running it as-is

Re: Filling out a template with Strings of data

PostPosted: Fri Sep 10, 2010 1:38 am
by dcole
Upon inspecting the /word/documentl.xml file - the word "Flynnie" is found twice in the modfied one. Should this be the case? I did a little googling on the error, and it seems like that it sometimes comes up if there is a content control imbedded in another content control or some such thing like that..and i saw some people say they had to modify the XML to fix it, but I dont know enough(anything) about XML to fix it probably.

Edit: This was apparently because the DOB and Name fields were both bound to the same thing in the MedicalSample chart coming from the site. I fixed that, and that got rid of the duplicate entry, but it still doesnt open.

Re: Filling out a template with Strings of data

PostPosted: Fri Sep 10, 2010 3:02 am
by dcole
When I commented out this line:

customXmlDataStoragePart.applyBindings(wordMLPackage.getMainDocumentPart());

The newly created file opens correctly

Re: Filling out a template with Strings of data

PostPosted: Fri Sep 10, 2010 8:22 am
by jason
I can't see why you'd get a different result from me if we are using the same source code, unless we are using different versions of Word and something has changed.

So, are you building from svn trunk, or using a binary docx4j jar? if so, which one?
if not http://dev.plutext.org/docx4j/docx4j-ni ... 100907.jar could you please try that (in conjunction with toLowerCase in the sample).

Re: Filling out a template with Strings of data

PostPosted: Fri Sep 10, 2010 10:47 am
by jason
by the way, did you solve your stackoverflow grails controller issue?

Re: Filling out a template with Strings of data

PostPosted: Sat Sep 11, 2010 12:27 am
by dcole
I will see if I can rebuild from a later version of source today. I was just using the 2.5 binary.

I haven't quite solved the grails controller issue, but I think I know what the problem is. I think that if any of your java source has an error in it, it cancels building ALL of the classes. I had some temporary stuff in there that was leftover from the previous developer that was erroring, so grails was just stopping the build and that would explain why I'm getting no classdef. The weird part is that grails was not reporting the Java errors except for the first time you do the build. So unless it was a clean build, you wouldnt notice the failures.