All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.docx4j.openpackaging.parts.relationships.AlteredParts Maven / Gradle / Ivy

Go to download

docx4j is a library which helps you to work with the Office Open XML file format as used in docx documents, pptx presentations, and xlsx spreadsheets.

There is a newer version: 11.4.11
Show newest version
/*
 *  Copyright 2011, Plutext Pty Ltd.
 *   
 *  This file is part of docx4j.

    docx4j is licensed under the Apache License, Version 2.0 (the "License"); 
    you may not use this file except in compliance with the License. 

    You may obtain a copy of the License at 

        http://www.apache.org/licenses/LICENSE-2.0 

    Unless required by applicable law or agreed to in writing, software 
    distributed under the License is distributed on an "AS IS" BASIS, 
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
    See the License for the specific language governing permissions and 
    limitations under the License.

 */

package org.docx4j.openpackaging.parts.relationships;


import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.JAXBException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.docx4j.convert.out.flatOpcXml.FlatOpcXmlCreator;
import org.docx4j.openpackaging.exceptions.Docx4JException;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.Part;
import org.docx4j.openpackaging.parts.PartName;
import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPart;
import org.docx4j.relationships.Relationship;

/**
 * Output is Flat OPC XML format:
 * 
 * 
        
            

 */
public class AlteredParts {
	
	private static Logger log = LoggerFactory.getLogger(AlteredParts.class);
		
	public static Alterations start(
									WordprocessingMLPackage thisPackage, 
									WordprocessingMLPackage otherPackage)
			throws Docx4JException {

		Alterations alterations = new Alterations();
		
		// First, handle [Content_Types].xml
		if (!thisPackage.getContentTypeManager().isContentEqual(otherPackage.getContentTypeManager())) {
	    	ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
	    	try {
				thisPackage.getContentTypeManager().marshal(baos);
			} catch (JAXBException e) {
				// Shouldn't happen
				throw new Docx4JException("Can't marshall content type", e);
			}
		}
		
		// Second, handle parts
		RelationshipsPart packageRels = thisPackage.getRelationshipsPart();
		RelationshipsPart otherPackageRels = otherPackage.getRelationshipsPart();
		recurse(alterations, packageRels, otherPackageRels);

		return alterations;
	}	

	public static void recurse(Alterations alterations,
			RelationshipsPart thisRP, RelationshipsPart otherRP)
			throws Docx4JException {
		
		log.info("######### @" + thisRP.getPartName().getName() + "#########");

		log.info("uniques -------");
		List uniques = thisRP.uniqueToThis(otherRP);
		addPartsForRels(alterations.getPartsAdded(), uniques, thisRP  );		

		List 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 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());
						}
						
					}
					
				}
			}
		}
	}

	private static void addPartsForRels(List list, List 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 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 );
				}
			}
		}		
		
	}
	
	private static org.docx4j.xmlPackage.Part toStorageFormat(Part part)  throws Docx4JException { 
		
		if (part instanceof BinaryPart ) {
			log.info(".. saving binary stuff" );
			return FlatOpcXmlCreator.createRawBinaryPart( part );
			
		} else {
			return FlatOpcXmlCreator.createRawXmlPart(part );
		}
	}
	
	
	public static class Alterations {
		
		// There is no Flat OPC part for [Content_Types].xml
		// so its up to us to choose a representation
		private byte[] contentTypes;
		public void setContentTypes(ByteArrayOutputStream baos) {
			contentTypes = baos.toByteArray();
		}
		public byte[] getContentTypes() {
			return contentTypes;
		}

		private List partsAdded = new ArrayList();
		private List partsDeleted = new ArrayList();
		private List partsModified = new ArrayList();

		public List getPartsAdded() {
			return partsAdded;
		}
		public List getPartsDeleted() {
			return partsDeleted;
		}
		public List getPartsModified() {
			return partsModified;
		}
		
		public void debug() {
			System.out.println("- Additions -------");
			for (Alteration a : partsAdded) {
				System.out.println(a.getPart().getName() + " @ " + a.getSourcePartName().getName() );
			}

			System.out.println("- Modifications -------");
			for (Alteration a : partsModified) {
				System.out.println(a.getPart().getName() + " @ " + a.getSourcePartName().getName() );
			}
			
			System.out.println("- Deletions -------");
			for (Alteration a : partsDeleted) {
				System.out.println(a.getPart().getName() + " @ " + a.getSourcePartName().getName() );
			}
		}
		
		public boolean isEmpty() {
			
			return partsAdded.isEmpty() && partsDeleted.isEmpty() && partsModified.isEmpty();
		}
	}

	public static class Alteration {
		
		// Required in order to apply patch
		private PartName sourcePartName;
		public PartName getSourcePartName() {
			return sourcePartName;
		}

		private org.docx4j.xmlPackage.Part part;
		public org.docx4j.xmlPackage.Part getPart() {
			return part;
		}

		
//		public Alteration(String point, org.docx4j.xmlPackage.Part part) {
//			this.point = point;
//			this.part = part;
//		}
		
		public Alteration(RelationshipsPart rp, org.docx4j.xmlPackage.Part part) {
			this.sourcePartName = rp.getSourceP().getPartName();
			this.part = part;
		}
		public Alteration(PartName sourcePartName, org.docx4j.xmlPackage.Part part) {
			this.sourcePartName = sourcePartName;
			this.part = part;
		}
		
	}
	
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy