org.docx4j.utils.XPathAwareCloner Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of docx4j Show documentation
Show all versions of docx4j Show documentation
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.
package org.docx4j.utils;
import java.util.List;
import javax.xml.bind.Binder;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import org.docx4j.XmlUtils;
import org.docx4j.jaxb.Context;
import org.docx4j.jaxb.JaxbValidationEventHandler;
import org.docx4j.jaxb.XPathBinderAssociationIsPartialException;
import org.docx4j.wml.P;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;
/**
* Some users wish to be able to use an XPath on the result
* of cloning a JAXB object. This variant on XmlUtils.deepCopy
* allows that.
*
* Note that if you use this object's deepCopy method more
* than once, the results returned by getJAXBNodesViaXPath
* will only be on your last deepCopy.
*/
public class XPathAwareCloner {
private static Logger log = LoggerFactory.getLogger(XPathAwareCloner.class);
/** Clone this JAXB object, using default JAXBContext. */
public Object deepCopy(Object o) {
return deepCopy(o, Context.jc);
}
Object jaxbElement;
/** Clone this JAXB object
* @param value
* @param jc
* @return
*/
public Object deepCopy(Object o, JAXBContext jc) {
if (o==null) {
throw new IllegalArgumentException("Can't clone a null argument");
}
try {
// To be XPath aware, we need a binder.
// But to unmarshall using a binder, we need to unmarshal a node.
// So, our marshall should be to a W3C document
org.w3c.dom.Document doc = XmlUtils.marshaltoW3CDomDocument(o, jc);
// OK, unmarshall to binder
binder = jc.createBinder();
JaxbValidationEventHandler eventHandler = new JaxbValidationEventHandler();
eventHandler.setContinue(false);
binder.setEventHandler(eventHandler);
jaxbElement = binder.unmarshal( doc);
//log.debug("Clone: " + XmlUtils.marshaltoString(jaxbElement, true, true));
return jaxbElement;
} catch (JAXBException ex) {
throw new IllegalArgumentException(ex);
}
}
private Binder binder;
/**
* Enables synchronization between XML infoset nodes and JAXB objects
* representing same XML document.
*
* An instance of this class maintains the association between XML nodes
* of an infoset preserving view and a JAXB representation of an XML document.
* Navigation between the two views is provided by the methods
* getXMLNode(Object) and getJAXBNode(Object) .
*
* In theory, modifications can be made to either the infoset preserving view or
* the JAXB representation of the document while the other view remains
* unmodified. The binder ought to be able to synchronize the changes made in
* the modified view back into the other view using the appropriate
* Binder update methods, #updateXML(Object, Object) or #updateJAXB(Object).
*
* But JAXB doesn't currently work as advertised .. access to this
* object is offered for advanced users on an experimental basis only.
*/
public Binder getBinder() {
return binder;
}
/**
* Fetch JAXB Nodes matching an XPath (for example "//w:p").
*
* If you have modified your JAXB objects (eg added or changed a
* w:p paragraph), you need to update the association. The problem
* is that this can only be done ONCE, owing to a bug in JAXB:
* see https://jaxb.dev.java.net/issues/show_bug.cgi?id=459
*
* So this is left for you to choose to do via the refreshXmlFirst parameter.
*
* @param xpathExpr
* @param refreshXmlFirst
* @return
* @throws JAXBException
* @throws XPathBinderAssociationIsPartialException
*/
public List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy