package org.docx4j.model.datastorage; import static org.junit.Assert.assertTrue; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import javax.xml.bind.Binder; import org.docx4j.XmlUtils; import org.docx4j.jaxb.Context; import org.docx4j.openpackaging.packages.WordprocessingMLPackage; import org.junit.Test; import org.w3c.dom.Node; public class EndToEndTest { /** * This tests: * - repeat of a table row * - conditions: simple conditional inclusion/exclusion of a paragraph */ @Test public void testInvoice() throws Exception { String inputfilepath = System.getProperty("user.dir") + "/sample-docs/word/databinding/invoice.docx"; /* * <invoice> <customer> <name>Joe Bloggs</name> </customer> <items> <item> <name>apples</name> <price>$20</price> </item> <item> <name>bananas</name> <price>$30</price> </item> <item> <name>cherries</name> <price>$40</price> </item> </items> <misc> <includeBankDetails>true</includeBankDetails> <wantspam>false</wantspam> </misc> </invoice> */ WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(new java.io.File(inputfilepath)); // System.out.println( // XmlUtils.marshaltoString( // wordMLPackage.getMainDocumentPart().getJaxbElement(), true) ); // Process conditionals and repeats OpenDoPEHandler odh = new OpenDoPEHandler(wordMLPackage); odh.preprocess(); // Since the JAXB binding stuff seems to remember // old artifacts, we'll first create a 'clean' object here // from something we've marshalled to. org.w3c.dom.Document xmlNode = XmlUtils.marshaltoW3CDomDocument( wordMLPackage.getMainDocumentPart().getJaxbElement()); Binder<Node> binder = Context.jc.createBinder(); Object jaxbElement = (org.docx4j.wml.Document) binder.unmarshal(xmlNode); // Test (1) // Before processing, the table contains 2 rows // (a header row, and 1 for content). // Now it should contain 4 rows. List<Object> list = XmlUtils.getJAXBNodesViaXPath(binder, jaxbElement, "//w:tr", false ); int count = list.size(); assertTrue("expected 4 rows but got " + count, count==4 ); // 3 cells should contain 'apples', but I don't test that // Test (2) // Conditions // <includeBankDetails>true</includeBankDetails> list = XmlUtils.getJAXBNodesViaXPath(binder, jaxbElement, "//w:r[w:t[contains(text(),'Bank')]]", false ); count = list.size(); assertTrue("expected 1 run but got " + count, count==1 ); // <wantspam>false</wantspam> list = XmlUtils.getJAXBNodesViaXPath(binder, jaxbElement, "//w:r[w:t[contains(text(),'left out')]]", false ); count = list.size(); assertTrue("expected 0 runs but got " + count, count==0 ); // Apply the bindings AtomicInteger bookmarkId = odh.getNextBookmarkId(); BindingHandler bh = new BindingHandler(wordMLPackage); bh.setStartingIdForNewBookmarks(bookmarkId); bh.applyBindings(wordMLPackage.getMainDocumentPart()); // create a 'clean' object again .. xmlNode = XmlUtils.marshaltoW3CDomDocument( wordMLPackage.getMainDocumentPart().getJaxbElement()); binder = Context.jc.createBinder(); jaxbElement = (org.docx4j.wml.Document) binder.unmarshal(xmlNode); // Test (3) list = XmlUtils.getJAXBNodesViaXPath(binder, jaxbElement, "//w:r[w:t[contains(text(),'cherries')]]", false ); count = list.size(); assertTrue("expected 1 runs but got " + count, count==1 ); } /** * This tests nested repeats. * * The outer repeat is of a table. */ @Test public void testNestedRepeats() throws Exception { String inputfilepath = System.getProperty("user.dir") + "/sample-docs/word/databinding/CountryRegions.xml"; /* <root xmlns=""> <countries> <country name="c1"> <region name="c1 r1"> <area>A c1 r1</area> <population>P c1 r1 </population> </region> </country> <country name="c2"> <region name="c2 r1"> <area>A c2 r1 </area> <population> P c2 r1</population> </region> <region name="c2 r2"> <area>A c2 r2 </area> <population>P c2 r2 </population> </region> </country> <country name="c3"> <region name="c3 r1"> <area>A c3 r1 </area> <population> P c3 r1</population> </region> <region name="c3 r2"> <area> A c3 r2</area> <population>P c3 r2 </population> </region> <region name="c3 r3"> <area> A c3 r2</area> <population>P c3 r2 </population> </region> </country> </countries> </root> */ WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(new java.io.File(inputfilepath)); // System.out.println( // XmlUtils.marshaltoString( // wordMLPackage.getMainDocumentPart().getJaxbElement(), true) ); // Process conditionals and repeats OpenDoPEHandler odh = new OpenDoPEHandler(wordMLPackage); odh.preprocess(); // Since the JAXB binding stuff seems to remember // old artifacts, we'll first create a 'clean' object here // from something we've marshalled to. org.w3c.dom.Document xmlNode = XmlUtils.marshaltoW3CDomDocument( wordMLPackage.getMainDocumentPart().getJaxbElement()); Binder<Node> binder = Context.jc.createBinder(); Object jaxbElement = (org.docx4j.wml.Document) binder.unmarshal(xmlNode); // Test (1) // After processing, we should have 3 tables List<Object> list = XmlUtils.getJAXBNodesViaXPath(binder, jaxbElement, "//w:tbl", false ); int count = list.size(); assertTrue("expected 3 tables but got " + count, count==3 ); // First table has 2 rows list = XmlUtils.getJAXBNodesViaXPath(binder, jaxbElement, "/descendant::w:tbl[1]/*[local-name()='sdt' or local-name()='tr']" , false ); // for (Object o : list){ // System.out.println(XmlUtils.marshaltoString(o, true)); // } count = list.size(); assertTrue("expected 2 rows but got " + count, count==2 ); // Second table has 3 rows list = XmlUtils.getJAXBNodesViaXPath(binder, jaxbElement, "/descendant::w:tbl[2]/*[local-name()='sdt' or local-name()='tr']" , false ); count = list.size(); assertTrue("expected 3 rows but got " + count, count==3 ); // Third table has 4 rows list = XmlUtils.getJAXBNodesViaXPath(binder, jaxbElement, "/descendant::w:tbl[3]/*[local-name()='sdt' or local-name()='tr']" , false ); count = list.size(); assertTrue("expected 4 rows but got " + count, count==4 ); // Apply the bindings AtomicInteger bookmarkId = odh.getNextBookmarkId(); BindingHandler bh = new BindingHandler(wordMLPackage); bh.setStartingIdForNewBookmarks(bookmarkId); bh.applyBindings(wordMLPackage.getMainDocumentPart()); // create a 'clean' object again .. xmlNode = XmlUtils.marshaltoW3CDomDocument( wordMLPackage.getMainDocumentPart().getJaxbElement()); binder = Context.jc.createBinder(); jaxbElement = (org.docx4j.wml.Document) binder.unmarshal(xmlNode); // Test (3) // Test that the last w:tc in the last table contains 'P c3 r3' /* <w:tc> <w:tcPr> <w:tcW w:type="dxa" w:w="2660"/> </w:tcPr> <w:sdt> <w:sdtPr> <w:dataBinding w:storeItemID="{D42EB9BD-AFC8-4100-9E42-B62BFF6817F8}" w:xpath="/root/countries/country[3]/region[3]/population"/> <w:showingPlcHdr/> <w:tag w:val="od:xpath=x6_2_2"/> <w:id w:val="1472231447"/> </w:sdtPr> <w:sdtContent> <w:p> <w:r> <w:t xml:space="preserve">P c3 r3 </w:t> </w:r> </w:p> </w:sdtContent> </w:sdt> </w:tc> </w:tr> </w:sdtContent> </w:sdt> </w:tbl> <w:p/> </w:sdtContent> </w:sdt> */ list = XmlUtils.getJAXBNodesViaXPath(binder, jaxbElement, "/descendant::w:tbl[3]/w:sdt[last()]/w:sdtContent/w:tr/w:tc[last()]" , false ); String content = XmlUtils.marshaltoString(list.get(0), true); assertTrue("expected content to contain 'P c3 r3' but got " + content, content.contains("P c3 r3") ); } }