package org.cagrid.core.xml; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.StringReader; import java.io.StringWriter; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import javax.xml.bind.util.JAXBSource; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.sax.SAXTransformerFactory; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.xml.sax.InputSource; public class XMLUtils { public final static String DEFAULT_ENCODING = "ISO-8859-1"; /* * Strings (and Nodes) don't care about encoding but the marshaller will use * it to determine if characters should be hex-escaped -- UTF-8 results in * no escaping. */ public final static String ALL_ENCODING = "UTF-8"; private static Logger logger = LoggerFactory.getLogger(XMLUtils.class); public static <T> T copy(T obj) { return fromXMLObject(null, obj); } public static <T> T fromXMLObject(JAXBContext jaxbContext, T xml) { @SuppressWarnings("unchecked") Class<T> klass = (Class<T>) xml.getClass(); if (jaxbContext == null) { try { jaxbContext = JAXBContext.newInstance(klass); } catch (JAXBException jaxbe) { logger.error("Could not create JAXB context for " + klass.getName()); return null; } } Source source = null; try { source = new JAXBSource(jaxbContext, xml); } catch (JAXBException jaxbe) { logger.error("Could not create JAXBSource for " + klass.getName()); return null; } return fromXML(jaxbContext, klass, source); } public static <T> T fromXMLString(Class<T> c, String xml) { return fromXMLString(null, c, xml); } public static <T> T fromXMLString(JAXBContext jaxbContext, Class<T> klass, String xml) { return fromXML(jaxbContext, klass, new StreamSource(new StringReader(xml))); } public static <T> T fromXMLFile(Class<T> c, File f) { return fromXMLFile(null, c, f); } public static <T> T fromXMLFile(JAXBContext jaxbContext, Class<T> klass, File file) { return fromXML(jaxbContext, klass, new StreamSource(file)); } public static <T> T fromXMLDOM(Class<T> c, Node n) { return fromXMLDOM(null, c, n); } public static <T> T fromXMLDOM(JAXBContext jaxbContext, Class<T> klass, Node node) { return fromXML(jaxbContext, klass, new DOMSource(node)); } /* * All unmarshalling goes through here. */ public static <T> T fromXML(JAXBContext jaxbContext, Class<T> klass, Source source) { if (jaxbContext == null) { try { jaxbContext = JAXBContext.newInstance(klass); } catch (JAXBException jaxbe) { logger.error("Could not create JAXB context for " + klass.getName()); return null; } } T t = null; try { Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); JAXBElement<T> element = unmarshaller.unmarshal(source, klass); t = element.getValue(); } catch (JAXBException jaxbe) { logger.error("Could not unmarshal " + klass.getName(), jaxbe); } return t; } public static String toXMLString(Object object) { return toXMLString(null, object, false, ALL_ENCODING); } /** * This method is used to return an XML document with or without the XML * declaration. * * @param object * - Object to be marshalled into XML * @param excludeXMLDeclaration * - Boolean indicating whether to exclude the xml declaration * @param encoding * the JAXB_ENCODING value to use * * @return */ public static String toXMLString(Object object, boolean excludeXMLDeclaration, String encoding) { return toXMLString(null, object, excludeXMLDeclaration, encoding); } /** * This method is used to return an XML document with or without the XML * declaration. * * @param object * - Object to be marshalled into XML * @param excludeXMLDeclaration * - Boolean indicating whether to exclude the xml declaration * @return */ public static String toXMLString(Object object, boolean excludeXMLDeclaration) { return toXMLString(null, object, excludeXMLDeclaration, ALL_ENCODING); } public static String toXMLString(JAXBContext jaxbContext, Object object, boolean excludeXMLDeclaration) { return toXMLString(jaxbContext, object, excludeXMLDeclaration, ALL_ENCODING); } public static String toXMLString(JAXBContext jaxbContext, Object object, boolean excludeXMLDeclaration, String encoding) { StringWriter sw = new StringWriter(); toXML(jaxbContext, object, excludeXMLDeclaration, encoding, new StreamResult(sw)); return sw.toString(); } public static boolean toXMLFile(Object object, File file) throws Exception { return toXMLFile(null, object, DEFAULT_ENCODING, file); } /* * All toFile should go through here. */ public static boolean toXMLFile(JAXBContext jaxbContext, Object object, String encoding, File file) throws IOException { FileOutputStream fos = new FileOutputStream(file); try { Result result = new StreamResult(fos); toXML(jaxbContext, object, false, encoding, result); } finally { try { fos.close(); } catch (IOException ignored) { } } return true; } public static Node toXMLDOM(Object object) { return toXMLDOM(null, object); } public static Node toXMLDOM(JAXBContext jaxbContext, Object object) { DOMResult result = new DOMResult(); toXML(jaxbContext, object, false, ALL_ENCODING, result); return result.getNode(); } /* * All marshalling goes through here. */ public static void toXML(JAXBContext jaxbContext, Object object, boolean excludeXMLDeclaration, String encoding, Result result) { if (object == null) return; Class<?> klass = object.getClass(); if (jaxbContext == null) { try { jaxbContext = JAXBContext.newInstance(klass); } catch (JAXBException jaxbe) { logger.error("Could not create JAXB context for " + klass.getName()); return; } } try { Marshaller marshaller = jaxbContext.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.setProperty(Marshaller.JAXB_FRAGMENT, excludeXMLDeclaration); marshaller.setProperty(Marshaller.JAXB_ENCODING, encoding); marshaller.marshal(object, result); } catch (JAXBException jaxbe) { logger.error("Could not marshal " + klass.getName(), jaxbe); } } public static Document createDocumentFromFile(File file) throws Exception { DocumentBuilderFactory factory = getDocumentBuilderFactory(); DocumentBuilder builder; try { builder = factory.newDocumentBuilder(); } catch (ParserConfigurationException e) { throw new Exception(e); } return builder.parse(file); } public static Document createDocumentFromStream(InputStream is) throws Exception { DocumentBuilderFactory factory = getDocumentBuilderFactory(); DocumentBuilder builder; try { builder = factory.newDocumentBuilder(); } catch (ParserConfigurationException e) { throw new Exception(e); } return builder.parse(is); } private static DocumentBuilderFactory getDocumentBuilderFactory() { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); factory.setXIncludeAware(true); return factory; } public static void writeDocumentToFile(Document d, File f) throws TransformerException, FileNotFoundException { TransformerFactory tFactory = TransformerFactory.newInstance(); Transformer transformer = tFactory.newTransformer(); DOMSource source = new DOMSource(d); StreamResult result = new StreamResult(new FileOutputStream(f)); transformer.transform(source, result); } public static String formatXML(String xml) { try { Transformer serializer = SAXTransformerFactory.newInstance().newTransformer(); serializer.setOutputProperty(OutputKeys.INDENT, "yes"); serializer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); Source xmlSource = new SAXSource(new InputSource(new ByteArrayInputStream(xml.getBytes()))); StreamResult res = new StreamResult(new ByteArrayOutputStream()); serializer.transform(xmlSource, res); return new String(((ByteArrayOutputStream) res.getOutputStream()).toByteArray()); } catch (Exception e) { return xml; } } }