package org.docx4j.openpackaging.parts.WordprocessingML; import static org.junit.Assert.assertTrue; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.util.List; import javax.xml.bind.Binder; import org.apache.commons.io.IOUtils; import org.docx4j.XmlUtils; import org.docx4j.jaxb.Context; import org.docx4j.jaxb.JaxbValidationEventHandler; import org.docx4j.model.structure.HeaderFooterPolicy; import org.docx4j.model.structure.SectionWrapper; import org.docx4j.openpackaging.packages.WordprocessingMLPackage; import org.docx4j.wml.Comments; import org.docx4j.wml.Document; import org.docx4j.wml.Hdr; import org.docx4j.wml.P; import org.docx4j.wml.R; import org.junit.Assert; import org.junit.Test; import org.w3c.dom.Node; public class AlternateContentPreprocessorTest { /** * This tests that an oval wrapped in AlternateContent * is resolved to the Fallback; it tests the usual unmarshal * method in JaxbXmlPart ie unmarshal( java.io.InputStream is ) * since CommentsPart uses that. */ @Test public void testAlternateContent() throws Exception { String inputfilepath = System.getProperty("user.dir") + "/sample-docs/word/2010/2010-mcAlternateContent.docx"; WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(new java.io.File(inputfilepath)); // 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().getCommentsPart().getJaxbElement()); Binder<Node> binder = Context.jc.createBinder(); Object jaxbElement = (Comments) binder.unmarshal(xmlNode); List<Object> list = XmlUtils.getJAXBNodesViaXPath(binder, jaxbElement, "//w:pict/v:oval", false ); int count = list.size(); assertTrue("expected oval but got " + count, count==1 ); } /** * This tests that an oval wrapped in AlternateContent * is resolved to the Fallback; it tests the unmarshal * method in MainDocumentPart */ @Test public void testAlternateContentMDP() throws Exception { String inputfilepath = System.getProperty("user.dir") + "/sample-docs/word/2010/2010-mcAlternateContent-MDP.docx"; WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(new java.io.File(inputfilepath)); // 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); List<Object> list = XmlUtils.getJAXBNodesViaXPath(binder, jaxbElement, "//w:pict/v:oval", false ); int count = list.size(); assertTrue("expected oval but got " + count, count==1 ); } /** * This tests that an oval wrapped in AlternateContent * is resolved to the Fallback, even in the presence * of other unrecognised content (eg glow); it uses the unmarshal * method in MainDocumentPart */ @Test public void testGlowAndAlternateContent() throws Exception { String inputfilepath = System.getProperty("user.dir") + "/sample-docs/word/2010/2010-glow-then-AlternateContent.docx"; WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(new java.io.File(inputfilepath)); // 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); List<Object> list = XmlUtils.getJAXBNodesViaXPath(binder, jaxbElement, "//w:pict/v:oval", false ); int count = list.size(); assertTrue("expected oval but got " + count, count==1 ); } /** * This tests that an oval wrapped in AlternateContent * is resolved to the Fallback; it tests * unmarshal( java.io.InputStream is ) * in HeaderPart */ @Test public void testHeaderDocx() throws Exception { String inputfilepath = System.getProperty("user.dir") + "/sample-docs/word/2010/2010-mcAlternateContent-in-header.docx"; WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage .load(new java.io.File(inputfilepath)); List<SectionWrapper> sectionWrappers = wordMLPackage.getDocumentModel() .getSections(); HeaderPart header = null; for (SectionWrapper sw : sectionWrappers) { HeaderFooterPolicy hfp = sw.getHeaderFooterPolicy(); if (hfp.getDefaultHeader() != null) { header = hfp.getDefaultHeader(); } } // 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( header.getJaxbElement()); Binder<Node> binder = Context.jc.createBinder(); Object jaxbElement = (Hdr) binder.unmarshal(xmlNode); List<Object> list = XmlUtils.getJAXBNodesViaXPath(binder, jaxbElement, "//w:pict/v:oval", false ); int count = list.size(); assertTrue("expected oval but got " + count, count==1 ); } // There is currently no test for unmarshal(org.w3c.dom.Element el) // method in JaxbXmlPart, but I did test that by commenting out // the override in HeaderPart, and running the below test. /** * This tests that an oval wrapped in AlternateContent * is resolved to the Fallback; it tests unmarshal(org.w3c.dom.Element el) * in HeaderPart. */ @Test public void testHeaderFlatOPC() throws Exception { String inputfilepath = System.getProperty("user.dir") + "/sample-docs/word/2010/2010-mcAlternateContent-in-header.xml"; WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(new java.io.File(inputfilepath)); /* * That unmarshalled via binder * * DEBUG org.docx4j.openpackaging.parts.JaxbXmlPartXPathAware .unmarshal line 559 - * For org.docx4j.openpackaging.parts.WordprocessingML.HeaderPart, unmarshall via binder * * but MOXy 2.5.2 and 2.6.3 seems to ignore event handler for that? * * http://stackoverflow.com/questions/37225221/moxy-validationevents-triggered-by-unmarshaller-but-not-binder * * docx4j 3.3.1 has a workaround for this in JaxbXmlPartXPathAware */ List<SectionWrapper> sectionWrappers = wordMLPackage.getDocumentModel() .getSections(); HeaderPart header = null; for (SectionWrapper sw : sectionWrappers) { HeaderFooterPolicy hfp = sw.getHeaderFooterPolicy(); if (hfp.getDefaultHeader() != null) { header = hfp.getDefaultHeader(); } } String headerXML = header.getXML(); System.out.println(headerXML); assertTrue(headerXML.contains("v:oval")); // 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(header .getJaxbElement()); Binder<Node> binder = Context.jc.createBinder(); JaxbValidationEventHandler eventHandler = new JaxbValidationEventHandler(); binder.setEventHandler(eventHandler); Object jaxbElement = (Hdr) binder.unmarshal(xmlNode); List<Object> list = XmlUtils.getJAXBNodesViaXPath(binder, jaxbElement, "//w:pict/v:oval", false ); int count = list.size(); assertTrue("expected oval but got " + count, count==1 ); } @Test public void testAltContentMarkSupported() throws Exception { String inputfilepath = System.getProperty("user.dir") + "/src/test/resources/parts/document_altContent.xml"; // mark supported byte[] bytes = IOUtils.toByteArray(new FileInputStream(new File(inputfilepath))); Document doc = (Document)XmlUtils.unmarshal(new ByteArrayInputStream(bytes)); //System.out.println(XmlUtils.marshaltoString(doc)); P p = (P)doc.getBody().getContent().get(0); R r = (R)p.getContent().get(0); Assert.assertTrue( XmlUtils.unwrap(r.getContent().get(0)) instanceof org.docx4j.wml.Pict); } @Test public void testAltContentMarkNotSupported() throws Exception { String inputfilepath = System.getProperty("user.dir") + "/src/test/resources/parts/document_altContent.xml"; // mark not supported try { Object o = XmlUtils.unmarshal(new FileInputStream(new File(inputfilepath))); System.out.println(XmlUtils.marshaltoString(o)); Assert.fail("Expect an exception, since mark not supported"); } catch (javax.xml.bind.UnmarshalException e){ System.out.println("OK " + e.getMessage() + " OK"); } } }