/** * Get a Part (except a relationships part), but not its relationships part or related parts. * Useful if you need quick access to just this part. This can be called directly from outside the * library, in which case the Part will not be owned by a Package until the calling code makes it * so. * * @see To get a Part and all its related parts, and add all to a package, use getPart. * @param partByteArrays * @param ctm * @param resolvedPartUri * @param rel * @return * @throws Docx4JException including if result is null */ public Part getRawPart(ContentTypeManager ctm, String resolvedPartUri, Relationship rel) throws Docx4JException { Part part = null; InputStream is = null; try { try { log.debug("resolved uri: " + resolvedPartUri); // Get a subclass of Part appropriate for this content type // This will throw UnrecognisedPartException in the absence of // specific knowledge. Hence it is important to get the is // first, as we do above. part = ctm.getPart("/" + resolvedPartUri, rel); log.info("ctm returned " + part.getClass().getName()); if (part instanceof org.docx4j.openpackaging.parts.ThemePart || part instanceof org.docx4j.openpackaging.parts.DocPropsCorePart || part instanceof org.docx4j.openpackaging.parts.DocPropsCustomPart || part instanceof org.docx4j.openpackaging.parts.DocPropsExtendedPart || part instanceof org.docx4j.openpackaging.parts.CustomXmlDataStoragePropertiesPart || part instanceof org.docx4j.openpackaging.parts.digitalsignature.XmlSignaturePart || part instanceof org.docx4j.openpackaging.parts.JaxbXmlPart) { // Nothing to do here } else if (part instanceof org.docx4j.openpackaging.parts.WordprocessingML.BinaryPart) { log.debug("Detected BinaryPart " + part.getClass().getName()); // is = partStore.loadPart( resolvedPartUri); // ((BinaryPart)part).setBinaryData(is); } else if (part instanceof org.docx4j.openpackaging.parts.CustomXmlDataStoragePart) { // ContentTypeManager initially detects them as CustomXmlDataStoragePart; // the below changes as necessary // Is it a part we know? is = partStore.loadPart(resolvedPartUri); try { Unmarshaller u = Context.jc.createUnmarshaller(); Object o = u.unmarshal(is); log.debug(o.getClass().getName()); PartName name = part.getPartName(); if (o instanceof CoverPageProperties) { part = new DocPropsCoverPagePart(name); ((DocPropsCoverPagePart) part).setJaxbElement((CoverPageProperties) o); } else if (o instanceof org.opendope.conditions.Conditions) { part = new ConditionsPart(name); ((ConditionsPart) part).setJaxbElement((org.opendope.conditions.Conditions) o); } else if (o instanceof org.opendope.xpaths.Xpaths) { part = new XPathsPart(name); ((XPathsPart) part).setJaxbElement((org.opendope.xpaths.Xpaths) o); } else if (o instanceof org.opendope.questions.Questionnaire) { part = new QuestionsPart(name); ((QuestionsPart) part).setJaxbElement((org.opendope.questions.Questionnaire) o); } else if (o instanceof org.opendope.answers.Answers) { part = new StandardisedAnswersPart(name); ((StandardisedAnswersPart) part).setJaxbElement((org.opendope.answers.Answers) o); } else if (o instanceof org.opendope.components.Components) { part = new ComponentsPart(name); ((ComponentsPart) part).setJaxbElement((org.opendope.components.Components) o); } else if (o instanceof JAXBElement<?> && XmlUtils.unwrap(o) instanceof org.docx4j.bibliography.CTSources) { part = new BibliographyPart(name); ((BibliographyPart) part) .setJaxbElement((JAXBElement<org.docx4j.bibliography.CTSources>) o); } else { log.error("TODO: handle known CustomXmlPart part " + o.getClass().getName()); CustomXmlDataStorage data = getCustomXmlDataStorageClass().factory(); is.reset(); data.setDocument(is); // Not necessarily JAXB, that's just our method name ((org.docx4j.openpackaging.parts.CustomXmlDataStoragePart) part).setData(data); } } catch (javax.xml.bind.UnmarshalException ue) { log.warn("No JAXB model for this CustomXmlDataStorage part; " + ue.getMessage()); CustomXmlDataStorage data = getCustomXmlDataStorageClass().factory(); is.reset(); data.setDocument(is); // Not necessarily JAXB, that's just our method name ((org.docx4j.openpackaging.parts.CustomXmlDataStoragePart) part).setData(data); } } else if (part instanceof org.docx4j.openpackaging.parts.XmlPart) { is = partStore.loadPart(resolvedPartUri); // try { ((XmlPart) part).setDocument(is); // Experimental 22/6/2011; don't fall back to binary (which we used to) // } catch (Docx4JException d) { // // This isn't an XML part after all, // // even though ContentTypeManager detected it as such // // So get it as a binary part // part = getBinaryPart(partByteArrays, ctm, resolvedPartUri); // log.warn("Could not parse as XML, so using BinaryPart for " // + resolvedPartUri); // ((BinaryPart)part).setBinaryData(is); // } } else { // Shouldn't happen, since ContentTypeManagerImpl should // return an instance of one of the above, or throw an // Exception. log.error("No suitable part found for: " + resolvedPartUri); part = null; } } catch (PartUnrecognisedException e) { log.error("PartUnrecognisedException shouldn't happen anymore!", e); // Try to get it as a binary part part = getBinaryPart(ctm, resolvedPartUri); log.warn("Using BinaryPart for " + resolvedPartUri); // is = partStore.loadPart( resolvedPartUri); // ((BinaryPart)part).setBinaryData(is); } } catch (Exception ex) { // IOException, URISyntaxException ex.printStackTrace(); throw new Docx4JException("Failed to getPart", ex); } finally { IOUtils.closeQuietly(is); } if (part == null) { throw new Docx4JException( "cannot find part " + resolvedPartUri + " from rel " + rel.getId() + "=" + rel.getTarget()); } return part; }
/** * Get a Part (except a relationships part), but not its relationships part or related parts. * Useful if you need quick access to just this part. This can be called directly from outside the * library, in which case the Part will not be owned by a Package until the calling code makes it * so. * * @see To get a Part and all its related parts, and add all to a package, use getPart. * @param zf * @param resolvedPartUri * @return * @throws URISyntaxException * @throws InvalidFormatException */ public static Part getRawPart( ZipFile zf, ContentTypeManager ctm, String resolvedPartUri, Relationship rel) throws Docx4JException { Part part = null; InputStream is = null; try { try { log.debug("resolved uri: " + resolvedPartUri); is = getInputStreamFromZippedPart(zf, resolvedPartUri); // Get a subclass of Part appropriate for this content type // This will throw UnrecognisedPartException in the absence of // specific knowledge. Hence it is important to get the is // first, as we do above. part = ctm.getPart("/" + resolvedPartUri, rel); if (part instanceof org.docx4j.openpackaging.parts.ThemePart) { ((org.docx4j.openpackaging.parts.JaxbXmlPart) part).setJAXBContext(Context.jcThemePart); ((org.docx4j.openpackaging.parts.JaxbXmlPart) part).unmarshal(is); } else if (part instanceof org.docx4j.openpackaging.parts.DocPropsCorePart) { ((org.docx4j.openpackaging.parts.JaxbXmlPart) part) .setJAXBContext(Context.jcDocPropsCore); ((org.docx4j.openpackaging.parts.JaxbXmlPart) part).unmarshal(is); } else if (part instanceof org.docx4j.openpackaging.parts.DocPropsCustomPart) { ((org.docx4j.openpackaging.parts.JaxbXmlPart) part) .setJAXBContext(Context.jcDocPropsCustom); ((org.docx4j.openpackaging.parts.JaxbXmlPart) part).unmarshal(is); } else if (part instanceof org.docx4j.openpackaging.parts.DocPropsExtendedPart) { ((org.docx4j.openpackaging.parts.JaxbXmlPart) part) .setJAXBContext(Context.jcDocPropsExtended); ((org.docx4j.openpackaging.parts.JaxbXmlPart) part).unmarshal(is); } else if (part instanceof org.docx4j.openpackaging.parts.CustomXmlDataStoragePropertiesPart) { ((org.docx4j.openpackaging.parts.JaxbXmlPart) part) .setJAXBContext(Context.jcCustomXmlProperties); ((org.docx4j.openpackaging.parts.JaxbXmlPart) part).unmarshal(is); } else if (part instanceof org.docx4j.openpackaging.parts.digitalsignature.XmlSignaturePart) { ((org.docx4j.openpackaging.parts.JaxbXmlPart) part).setJAXBContext(Context.jcXmlDSig); ((org.docx4j.openpackaging.parts.JaxbXmlPart) part).unmarshal(is); } else if (part instanceof org.docx4j.openpackaging.parts.JaxbXmlPart) { // MainDocument part, Styles part, Font part etc ((org.docx4j.openpackaging.parts.JaxbXmlPart) part).setJAXBContext(Context.jc); ((org.docx4j.openpackaging.parts.JaxbXmlPart) part).unmarshal(is); } else if (part instanceof org.docx4j.openpackaging.parts.WordprocessingML.BinaryPart) { log.debug("Detected BinaryPart " + part.getClass().getName()); if (conserveMemory) { ((BinaryPart) part).setBinaryDataRef(zf.getName(), resolvedPartUri); } else { ((BinaryPart) part).setBinaryData(is); } } else if (part instanceof org.docx4j.openpackaging.parts.CustomXmlDataStoragePart) { // Is it a part we know? try { Unmarshaller u = Context.jc.createUnmarshaller(); Object o = u.unmarshal(is); log.debug(o.getClass().getName()); PartName name = part.getPartName(); if (o instanceof org.opendope.conditions.Conditions) { part = new ConditionsPart(name); ((ConditionsPart) part).setJaxbElement((org.opendope.conditions.Conditions) o); } else if (o instanceof org.opendope.xpaths.Xpaths) { part = new XPathsPart(name); ((XPathsPart) part).setJaxbElement((org.opendope.xpaths.Xpaths) o); } else if (o instanceof org.opendope.questions.Questionnaire) { part = new QuestionsPart(name); ((QuestionsPart) part).setJaxbElement((org.opendope.questions.Questionnaire) o); } else if (o instanceof org.opendope.answers.Answers) { part = new StandardisedAnswersPart(name); ((StandardisedAnswersPart) part).setJaxbElement((org.opendope.answers.Answers) o); } else if (o instanceof org.opendope.components.Components) { part = new ComponentsPart(name); ((ComponentsPart) part).setJaxbElement((org.opendope.components.Components) o); } else if (o instanceof JAXBElement<?> && XmlUtils.unwrap(o) instanceof org.docx4j.bibliography.CTSources) { part = new BibliographyPart(name); ((BibliographyPart) part) .setJaxbElement((JAXBElement<org.docx4j.bibliography.CTSources>) o); } else { log.warn("No known part after all for CustomXmlPart " + o.getClass().getName()); CustomXmlDataStorage data = getCustomXmlDataStorageClass().factory(); is.reset(); data.setDocument(is); // Not necessarily JAXB, that's just our method name ((org.docx4j.openpackaging.parts.CustomXmlDataStoragePart) part).setData(data); } } catch (javax.xml.bind.UnmarshalException ue) { // No ... CustomXmlDataStorage data = getCustomXmlDataStorageClass().factory(); is.reset(); data.setDocument(is); // Not necessarily JAXB, that's just our method name ((org.docx4j.openpackaging.parts.CustomXmlDataStoragePart) part).setData(data); } } else if (part instanceof org.docx4j.openpackaging.parts.XmlPart) { try { ((XmlPart) part).setDocument(is); } catch (Docx4JException d) { // This isn't an XML part after all, // even though ContentTypeManager detected it as such // So get it as a binary part part = getBinaryPart(zf, ctm, resolvedPartUri); if (conserveMemory) { ((BinaryPart) part).setBinaryDataRef(zf.getName(), resolvedPartUri); } else { ((BinaryPart) part).setBinaryData(is); } } } else { // Shouldn't happen, since ContentTypeManagerImpl should // return an instance of one of the above, or throw an // Exception. log.error("No suitable part found for: " + resolvedPartUri); part = null; } } catch (PartUnrecognisedException e) { log.warn("PartUnrecognisedException shouldn't happen anymore!"); // Try to get it as a binary part part = getBinaryPart(zf, ctm, resolvedPartUri); if (conserveMemory) { ((BinaryPart) part).setBinaryDataRef(zf.getName(), resolvedPartUri); } else { ((BinaryPart) part).setBinaryData(is); } } } catch (Exception ex) { // IOException, URISyntaxException ex.printStackTrace(); throw new Docx4JException("Failed to getPart", ex); } finally { if (is != null) { try { is.close(); } catch (IOException exc) { exc.printStackTrace(); } } } return part; }
private List<Object> processRepeat( Object sdt, Map<String, CustomXmlPart> customXmlDataStorageParts, XPathsPart xPathsPart) { Tag tag = getSdtPr(sdt).getTag(); HashMap<String, String> map = QueryString.parseQueryString(tag.getVal(), true); String repeatId = map.get(BINDING_ROLE_REPEAT); // Check, whether we are in an old repeat case. These can be removed. if (StringUtils.isEmpty(repeatId)) return new ArrayList<Object>(); org.opendope.xpaths.Xpaths.Xpath xpathObj = XPathsPart.getXPathById(xPaths, repeatId); String storeItemId = xpathObj.getDataBinding().getStoreItemID(); String xpath = xpathObj.getDataBinding().getXpath(); String prefixMappings = xpathObj.getDataBinding().getPrefixMappings(); // Get the bound XML String xpathBase; // if (xpath.endsWith("/*")) { // xpathBase = xpath.substring(0, xpath.length()-2); // } else if (xpath.endsWith("/")) { xpathBase = xpath.substring(0, xpath.length() - 1); // Check, whether the xpath ends with a [1]. If so, guess it comes // from a round-tripped path and strip it } else if (xpath.endsWith("[1]")) { xpathBase = xpath.substring(0, xpath.length() - 3); } else { xpathBase = xpath; } // DON'T Drop any trailing position! That breaks nested repeats // if (xpathBase.endsWith("]")) // xpathBase = xpathBase.substring(0, xpathBase.lastIndexOf("[")); log.info("/n/n Repeat: using xpath: " + xpathBase); List<Node> repeatedSiblings = xpathGetNodes(customXmlDataStorageParts, storeItemId, xpathBase, prefixMappings); // storeItemId, xpathBase+"/*", prefixMappings); // Count siblings int numRepeats = repeatedSiblings.size(); log.debug("yields REPEATS: " + numRepeats); if (numRepeats == 0) { // return new ArrayList<Object>(); // effectively, delete // Change tag to od:resultRepeatZero=id return repeatZero(sdt); } // duplicate content here ... List<Object> repeated = cloneRepeatSdt(sdt, xpathBase, numRepeats); // deep traverse to fix binding DeepTraversor dt = new DeepTraversor(); dt.xpathBase = xpathBase; for (int i = 0; i < repeated.size(); i++) { log.info("\n Traversing clone " + i); dt.index = i; new TraversalUtil(repeated.get(i), dt); } log.info(".. deep traversals done "); // make bookmarks (if any) unique for (int i = 0; i < repeated.size(); i++) { try { // Use the sdt id for uniqueness long global = ((SdtElement) repeated.get(i)).getSdtPr().getId().getVal().longValue(); BookmarkRenumber.fixRange( ((SdtElement) repeated.get(i)).getSdtContent().getContent(), "CTBookmark", "CTMarkupRange", null, global, i); } catch (Exception e) { // Shouldn't happen .. TODO remove reflection? log.error(e.getMessage(), e); } } return repeated; }
@Override public void apply(SdtElement element, Object parent, List<Object> siblings) { System.out.println(); SdtPr sdtPr = element.getSdtPr(); if (sdtPr == null) { System.out.println( callback.indent + element.getClass().getSimpleName() + " [no sdtPr!]" + " (having parent " + parent.getClass().getSimpleName() + ")"); } else { System.out.println( callback.indent + element.getClass().getSimpleName() + " (having parent " + parent.getClass().getSimpleName() + ")"); CTDataBinding binding = (CTDataBinding) XmlUtils.unwrap(sdtPr.getDataBinding()); if (binding != null) { System.out.println(callback.indent + " binding: " + binding.getXpath()); } Tag tag = sdtPr.getTag(); if (tag == null) return; System.out.println(callback.indent + " " + tag.getVal()); HashMap<String, String> map = QueryString.parseQueryString(tag.getVal(), true); String conditionId = map.get(OpenDoPEHandler.BINDING_ROLE_CONDITIONAL); String repeatId = map.get(OpenDoPEHandler.BINDING_ROLE_REPEAT); String xp = map.get(OpenDoPEHandler.BINDING_ROLE_XPATH); if (conditionId != null) { Condition c = ConditionsPart.getConditionById(conditions, conditionId); if (c == null) { System.out.println(callback.indent + " " + "Missing condition " + conditionId); } if (c.getParticle() instanceof org.opendope.conditions.Xpathref) { org.opendope.conditions.Xpathref xpathRef = (Xpathref) c.getParticle(); if (xpathRef == null) { System.out.println( callback.indent + " " + "Condition " + c.getId() + " references a missing xpath!"); } org.opendope.xpaths.Xpaths.Xpath xpath = XPathsPart.getXPathById(xPaths, xpathRef.getId()); if (xpath == null) { System.out.println( callback.indent + " " + "XPath specified in condition '" + c.getId() + "' is missing!"); } else { System.out.println( callback.indent + " " + xpath.getId() + ": " + xpath.getDataBinding().getXpath()); } } else { System.out.println("Complex condition: " + XmlUtils.marshaltoString(c, true, true)); } } else if (repeatId != null) { org.opendope.xpaths.Xpaths.Xpath xpath = XPathsPart.getXPathById(xPaths, repeatId); if (xpath == null) { System.out.println( callback.indent + " " + "XPath specified in repeat '" + repeatId + "' is missing!"); } else { System.out.println( callback.indent + " " + xpath.getId() + ": " + xpath.getDataBinding().getXpath()); } } else if (xp != null) { org.opendope.xpaths.Xpaths.Xpath xpath = XPathsPart.getXPathById(xPaths, xp); if (xpath == null) { System.out.println( callback.indent + " " + "XPath specified with id '" + xp + "' is missing!"); } else { System.out.println( callback.indent + " " + xpath.getId() + ": " + xpath.getDataBinding().getXpath()); } } } }
private void processDescendantBindings(Object sdt, String xpathBase, int index) { SdtPr sdtPr = getSdtPr(sdt); // log.debug(XmlUtils.marshaltoString(sdtPr, true, true)); // Give it a unique ID (supersedes above?) sdtPr.setId(); // log.debug(XmlUtils.marshaltoString(sdtPr, true, true)); CTDataBinding binding = (CTDataBinding) XmlUtils.unwrap(sdtPr.getDataBinding()); String thisXPath = null; // It'll have one of these three... String conditionId = null; String repeatId = null; String bindingId = null; org.opendope.xpaths.Xpaths.Xpath xpathObj = null; Tag tag = sdtPr.getTag(); if (tag == null) return; HashMap<String, String> map = QueryString.parseQueryString(tag.getVal(), true); if (binding == null) { conditionId = map.get(BINDING_ROLE_CONDITIONAL); repeatId = map.get(BINDING_ROLE_REPEAT); if (conditionId != null) { // c = ConditionsPart.getConditionById(conditions, conditionId); // if (c == null) { // log.error("Missing condition " + conditionId); // throw new InputIntegrityException("Required condition '" + conditionId + "' is // missing"); // } // // // TODO: this code assumes the condition contains // // a simple xpath // log.debug("Using condition" // + XmlUtils.marshaltoString(c, true, true)); // xpathObj = getXPathFromCondition(c); // thisXPath = xpathObj.getDataBinding().getXpath(); processDescendantCondition(sdt, xpathBase, index, tag); return; } else if (repeatId != null) { xpathObj = XPathsPart.getXPathById(xPaths, repeatId); thisXPath = xpathObj.getDataBinding().getXpath(); } else if (map.containsKey(BINDING_CONTENTTYPE) || map.containsKey(BINDING_HANDLER) || map.containsKey(BINDING_PROGID)) { xpathObj = XPathsPart.getXPathById(xPaths, map.get(BINDING_ROLE_XPATH)); thisXPath = xpathObj.getDataBinding().getXpath(); } else { log.warn("couldn't find binding or bindingrole!"); // not all sdt's need have a binding; // they could be present in the docx for other purposes return; // NB an OpenDoPE xpath tag (with no w:binding element) // eg as created by authoring tool for a "count(" XPath // ends up here. } } else { thisXPath = binding.getXpath(); // Set this stuff up now bindingId = map.get(BINDING_ROLE_XPATH); xpathObj = XPathsPart.getXPathById(xPaths, bindingId); // Sanity test if (!thisXPath.equals(xpathObj.getDataBinding().getXpath())) { log.error( "XPaths didn't match for id " + bindingId + ": \n\r " + thisXPath + "\n\rcf. " + xpathObj.getDataBinding().getXpath()); } // 2012 09 20 - when did this break? // thisXPath = xpathObj.getDataBinding().getXpath(); } // System.out.println("xpathBase: " + xpathBase); // System.out.println("index: " + index); // System.out.println("thisXPath: " + thisXPath); final String newPath = enhanceXPath(xpathBase, index + 1, thisXPath); // System.out.println("newPath: " + newPath); if (log.isDebugEnabled() && !thisXPath.equals(newPath)) { log.debug("xpath prefix enhanced " + thisXPath + " to " + newPath); } if (binding == null) { if (repeatId != null) { // Create the new xpath object org.opendope.xpaths.Xpaths.Xpath newXPathObj = createNewXPathObject(newPath, xpathObj, index); // set sdt to use it map.put(BINDING_ROLE_REPEAT, newXPathObj.getId()); tag.setVal(QueryString.create(map)); } else if (map.containsKey(BINDING_CONTENTTYPE) || map.containsKey(BINDING_HANDLER) || map.containsKey(BINDING_PROGID)) { // Also need to create new xpath id, and add that org.opendope.xpaths.Xpaths.Xpath newXPathObj = createNewXPathObject(newPath, xpathObj, index); // set sdt to use it map.put(BINDING_ROLE_XPATH, newXPathObj.getId()); tag.setVal(QueryString.create(map)); } } else { binding.setXpath(newPath); // Also need to create new xpath id, and add that org.opendope.xpaths.Xpaths.Xpath newXPathObj = createNewXPathObject(newPath, xpathObj, index); // set sdt to use it map.put(BINDING_ROLE_XPATH, newXPathObj.getId()); tag.setVal(QueryString.create(map)); } }