private static void addPartsForRels( List<Alteration> list, List<Relationship> rels, RelationshipsPart rp) throws Docx4JException { for (Relationship r : rels) { if (r.getTargetMode() != null && r.getTargetMode().equals("External")) { log.debug(r.getTarget() + " is external"); // Have everything we need info wise in transmitting the rels part } else { list.add(new Alteration(rp, toStorageFormat(rp.getPart(r)))); log.debug("added part: " + r.getTarget()); } } }
/** * @param alteredParts * @param theseRels * @throws Docx4JException */ private static void addTree(List<Alteration> list, RelationshipsPart rp) throws Docx4JException { if (rp == null) return; for (Relationship r : rp.getJaxbElement().getRelationship()) { if (r.getTargetMode() != null && r.getTargetMode().equals("External")) { log.debug(r.getTarget() + " is external"); // Have everything we need info wise in transmitting the rels part } else { list.add(new Alteration(rp, toStorageFormat(rp.getPart(r)))); log.debug("add tree: " + r.getTarget()); // recurse Part nextSourcePart = rp.getPart(r); RelationshipsPart nextRP = nextSourcePart.getRelationshipsPart(); if (nextRP != null) { list.add(new Alteration(nextSourcePart.getPartName(), toStorageFormat(nextRP))); addTree(list, nextRP); } } } }
/** * Get a Part (except a relationships part), and all its related parts. 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. * * @param zf * @param source * @param unusedZipEntries * @param pkg * @param r * @param resolvedPartUri * @throws Docx4JException * @throws InvalidFormatException */ private void getPart(OpcPackage pkg, RelationshipsPart rp, Relationship r, ContentTypeManager ctm) throws Docx4JException, InvalidFormatException, URISyntaxException { Base source = null; String resolvedPartUri = null; if (r.getType().equals(Namespaces.HYPERLINK)) { // Could be Internal or External // Example of Internal is w:drawing/wp:inline/wp:docPr/a:hlinkClick log.info("Encountered (but not loading) hyperlink " + r.getTarget()); return; } else if (r.getTargetMode() == null || !r.getTargetMode().equals("External")) { // Usual case source = rp.getSourceP(); resolvedPartUri = URIHelper.resolvePartUri(rp.getSourceURI(), new URI(r.getTarget())).toString(); // Now drop leading "/' resolvedPartUri = resolvedPartUri.substring(1); // Now normalise it .. ie abc/def/../ghi // becomes abc/ghi // Maybe this isn't necessary with a zip file, // - ZipFile class may be smart enough to do it. // But it is certainly necessary in the JCR case. // resolvedPartUri = (new java.net.URI(resolvedPartUri)).normalize().toString(); // log.info("Normalised, it is " + resolvedPartUri ); } else { // EXTERNAL if (loadExternalTargets && r.getType().equals(Namespaces.IMAGE)) { // It could instead be, for example, of type hyperlink, // and we don't want to try to fetch that log.info("Loading external resource " + r.getTarget() + " of type " + r.getType()); BinaryPart bp = ExternalResourceUtils.getExternalResource(r.getTarget()); pkg.getExternalResources().put(bp.getExternalTarget(), bp); } else { log.info( "Encountered (but not loading) external resource " + r.getTarget() + " of type " + r.getType()); } return; } String relationshipType = r.getType(); Part part; if (pkg.handled.get(resolvedPartUri) != null) { // The source Part (or Package) might have a convenience // method for this part = pkg.getParts().getParts().get(new PartName("/" + resolvedPartUri)); if (source.setPartShortcut(part, relationshipType)) { log.debug( "Convenience method established from " + source.getPartName() + " to " + part.getPartName()); } return; } part = getRawPart(ctm, resolvedPartUri, r); // will throw exception if null // The source Part (or Package) might have a convenience // method for this if (source.setPartShortcut(part, relationshipType)) { log.debug( "Convenience method established from " + source.getPartName() + " to " + part.getPartName()); } if (part instanceof BinaryPart || part instanceof DefaultXmlPart) { // The constructors of other parts should take care of this... part.setRelationshipType(relationshipType); } rp.loadPart(part, r); pkg.handled.put(resolvedPartUri, resolvedPartUri); // unusedZipEntries.put(resolvedPartUri, new Boolean(false)); RelationshipsPart rrp = getRelationshipsPart(part); if (rrp != null) { // recurse via this parts relationships, if it has any addPartsFromRelationships(part, rrp, ctm); String relPart = PartName.getRelationshipsPartName(part.getPartName().getName().substring(1)); // unusedZipEntries.put(relPart, new Boolean(false)); } }
public static void recurse( Alterations alterations, RelationshipsPart thisRP, RelationshipsPart otherRP) throws Docx4JException { log.info("######### @" + thisRP.partName.getName() + "#########"); log.info("uniques -------"); List<Relationship> uniques = thisRP.uniqueToThis(otherRP); addPartsForRels(alterations.getPartsAdded(), uniques, thisRP); List<Relationship> missings = thisRP.uniqueToOther(otherRP); addPartsForRels(alterations.getPartsDeleted(), missings, otherRP); // is this rels part itself altered? if (!thisRP.isContentEqual(otherRP)) { alterations.getPartsModified().add(new Alteration(thisRP, toStorageFormat(thisRP))); } log.info("content -------"); List<Relationship> altered = thisRP.differingContent(otherRP); addPartsForRels(alterations.getPartsModified(), altered, thisRP); // Now recurse all rels log.info("recurse ------- "); for (Relationship r : thisRP.getJaxbElement().getRelationship()) { if (r.getTargetMode() != null && r.getTargetMode().equals("External")) { // do nothing } else { if (uniques.contains(r)) { // add tree, including any external parts // (we already have the part itself) addTree(alterations.getPartsAdded(), thisRP.getPart(r).getRelationshipsPart()); } else if (missings.contains(r)) { addTree(alterations.getPartsDeleted(), thisRP.getPart(r).getRelationshipsPart()); } else { // its present in both trees. // irrespective of whether content of part is the same, content of a rel could still have // changed Part thisPart = thisRP.getPart(r); Part otherPart = otherRP.getPart(RelationshipsPart.getRelationshipByTarget(otherRP, r.getTarget())); if (thisPart.getRelationshipsPart() == null) { if (otherPart.getRelationshipsPart() != null) { // add tree, including any external parts alterations .getPartsDeleted() .add( new Alteration( thisPart.getPartName(), toStorageFormat(thisPart.getRelationshipsPart()))); addTree(alterations.getPartsDeleted(), thisPart.getRelationshipsPart()); } } else { if (otherPart.getRelationshipsPart() == null) { // add tree, including any external parts alterations .getPartsAdded() .add( new Alteration( thisPart.getPartName(), toStorageFormat(thisPart.getRelationshipsPart()))); addTree(alterations.getPartsAdded(), thisPart.getRelationshipsPart()); } else { recurse( alterations, thisPart.getRelationshipsPart(), otherPart.getRelationshipsPart()); } } } } } }
/* recursively (i) get each Part listed in the relationships (ii) add the Part to the zip file (iii) traverse its relationship */ public void addPartsFromRelationships(ZipOutputStream out, RelationshipsPart rp) throws Docx4JException { // for (Iterator it = rp.iterator(); it.hasNext(); ) { // Relationship r = (Relationship)it.next(); // log.info("For Relationship Id=" + r.getId() + " Source is " + r.getSource().getPartName() + // ", Target is " + r.getTargetURI() ); for (Relationship r : rp.getRelationships().getRelationship()) { log.debug( "For Relationship Id=" + r.getId() + " Source is " + rp.getSourceP().getPartName() + ", Target is " + r.getTarget()); if (r.getType().equals(Namespaces.HYPERLINK)) { continue; // whether internal or external } if (r.getTargetMode() != null && r.getTargetMode().equals("External")) { // ie its EXTERNAL // As at 1 May 2008, we don't have a Part for these; // there is just the relationship. log.warn("Encountered external resource " + r.getTarget() + " of type " + r.getType()); // So continue; } try { // String resolvedPartUri = URIHelper.resolvePartUri(r.getSourceURI(), r.getTargetURI() // ).toString(); String resolvedPartUri = URIHelper.resolvePartUri(rp.getSourceURI(), new URI(r.getTarget())).toString(); // Now drop leading "/' resolvedPartUri = resolvedPartUri.substring(1); // Now normalise it .. ie abc/def/../ghi // becomes abc/ghi // Maybe this isn't necessary with a zip file, // - ZipFile class may be smart enough to do it. // But it is certainly necessary in the JCR case. // target = (new java.net.URI(target)).normalize().toString(); // log.info("Normalised, it is " + target ); // Document contents = getDocumentFromZippedPart( zf, target); if (!false) { log.debug("Getting part /" + resolvedPartUri); // Part part = p.getParts().get(new PartName("/" + resolvedPartUri)); Part part = rp.getPart(r); // 2012 09 26: If the part is actually attached to // a different package, using this you can still get it. // Use this 'feature' at your own risk! if (part == null) { log.error("Part " + resolvedPartUri + " not found!"); } else { log.debug(part.getClass().getName()); } if (!part.getPackage().equals(p)) { log.warn("Part " + resolvedPartUri + " is attached to some other package"); } savePart(out, part); } } catch (Exception e) { throw new Docx4JException( "Failed to add parts from relationships of " + rp.getSourceP().getPartName(), e); } } }