Package org.docx4j.utils

Source Code of org.docx4j.utils.XPathAwareCloner

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<Node> 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<Node> 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<Object> getJAXBNodesViaXPath(String xpathExpr, boolean refreshXmlFirst)
      throws JAXBException, XPathBinderAssociationIsPartialException {
   
    return XmlUtils.getJAXBNodesViaXPath(binder, jaxbElement, xpathExpr, refreshXmlFirst);
 
 
  /**
   * @param args
   * @throws JAXBException
   * @throws XPathBinderAssociationIsPartialException
   */
  public static void main(String[] args) throws JAXBException, XPathBinderAssociationIsPartialException {
   
      String pString = "<w:p xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\">"
              +"<w:r>"
                +"<w:t xml:space=\"preserve\">Here is some text.</w:t>"
              +"</w:r>"
              +"<w:r>"
                +"<w:rPr>"
                  +"<w:i/>"
                +"</w:rPr>"
                +"<w:t>An italic run.</w:t>"
              +"</w:r>"
              +"<w:r>"
                +"<w:rPr>"
                  +"<w:i/>"
                +"</w:rPr>"
                +"<w:t xml:space=\"preserve\">"  +"</w:t>"
              +"</w:r>"
              +"<w:r>"
                +"<w:t>More stuff.</w:t>"
              +"</w:r>"
              +"<w:r>"
                +"<w:t xml:space=\"preserve\">"  +"</w:t>"
              +"</w:r>"
              +"<w:r>"
                +"<w:rPr>"
                  +"<w:b/>"
                +"</w:rPr>"
                +"<w:t>More stuff.</w:t>"
              +"</w:r>"
              +"<w:r>"
                +"<w:t xml:space=\"preserve\">" +"</w:t>"
              +"</w:r>"
              +"<w:r>"
                +"<w:t xml:space=\"preserve\">The run we are seeking.</w:t>"
              +"</w:r>"
              +"<w:r>"
                +"<w:rPr>"
                  +"<w:b/>"
                +"</w:rPr>"
                +"<w:t>More stuff.</w:t>"
              +"</w:r>"
              +"<w:r>"
                +"<w:t xml:space=\"preserve\">" +"</w:t>"
              +"</w:r>"
              +"<w:r>"
                +"<w:t>More stuff.</w:t>"
              +"</w:r>"
            +"</w:p>";
     
      P pIn = (P)XmlUtils.unmarshalString(pString);
     
      XPathAwareCloner cloner = new XPathAwareCloner();
      P clonedP = (P)cloner.deepCopy(pIn);
     
      List<Object> results = cloner.getJAXBNodesViaXPath("//w:r[contains( w:t, 'seeking')]", false);
      //List<Object> results = cloner.getJAXBNodesViaXPath("//w:r", false);
     
      int i=1;
      for (Object result: results) {
        System.out.println("\n\r" + i + ": " + XmlUtils.marshaltoString(result, true, true));
        i++;
      }
   

  }

}
TOP

Related Classes of org.docx4j.utils.XPathAwareCloner

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.