/* * Copyright 2000-2013 Enonic AS * http://www.enonic.com/license */ package com.enonic.cms.framework.util; import java.io.IOException; import java.io.InputStream; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import org.jdom.Attribute; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.jdom.input.DOMBuilder; import org.jdom.input.SAXBuilder; import org.jdom.output.DOMOutputter; import org.jdom.output.Format; import org.jdom.output.XMLOutputter; import org.jdom.transform.JDOMSource; import com.google.common.base.Strings; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.sxpath.XPathEvaluator; import net.sf.saxon.sxpath.XPathExpression; /** * This implements common JDOM utility methods. */ public final class JDOMUtil { private final static ThreadLocal<SAXBuilder> threadLocalSAXBuilder = new ThreadLocal<SAXBuilder>() { @Override protected SAXBuilder initialValue() { SAXBuilder builder = new SAXBuilder(); builder.setFastReconfigure( true ); return builder; } }; /** * Parse document. */ public static Document parseDocument( InputStream in ) throws IOException, JDOMException { SAXBuilder builder = getSAXBuilder(); return builder.build( in ); } /** * Parse document. */ public static Document parseDocument( String xml ) throws IOException, JDOMException { SAXBuilder builder = getSAXBuilder(); return builder.build( new StringReader( xml ) ); } /** * Convert org.w3c.dom.Document to JDOM document. */ public static Document toDocument( org.w3c.dom.Node node ) { if ( node instanceof org.w3c.dom.Document ) { return toDocument( (org.w3c.dom.Document) node ); } else if ( node instanceof org.w3c.dom.Element ) { return toDocument( (org.w3c.dom.Element) node ); } else { return toDocument( node.getOwnerDocument() ); } } /** * Convert org.w3c.dom.Document to JDOM document. */ private static Document toDocument( org.w3c.dom.Document doc ) { DOMBuilder builder = new DOMBuilder(); return builder.build( doc ); } /** * Convert org.w3c.dom.Element to JDOM document. */ private static Document toDocument( org.w3c.dom.Element element ) { DOMBuilder builder = new DOMBuilder(); return new Document( (Element) builder.build( element ).detach() ); } /** * Convert to w3c dom. */ public static org.w3c.dom.Document toW3CDocument( Document doc ) throws JDOMException { DOMOutputter builder = new DOMOutputter(); return builder.output( doc ); } /** * Return first child element. */ public static Element getFirstElement( Element root ) { if ( root != null ) { List list = root.getChildren(); if ( !list.isEmpty() ) { return (Element) list.get( 0 ); } } return null; } /** * Return named sub element. */ public static Element getElement( Element root, String name ) { if ( root != null ) { List list = root.getChildren( name ); if ( !list.isEmpty() ) { return (Element) list.get( 0 ); } } return null; } /** * Return the child elements of an element. */ public static Element[] getElements( Element root ) { if ( root != null ) { List list = root.getChildren(); return (Element[]) list.toArray( new Element[list.size()] ); } else { return new Element[0]; } } @SuppressWarnings({"unchecked"}) public static List<Element> getChildren( final Element parentEl, final String name ) { final List list = parentEl.getChildren( name ); if ( list == null ) { return new ArrayList<Element>(); } return list; } /** * Return the element text. */ public static String getElementText( Element root ) { if ( root != null ) { String text = root.getText(); if ( "".equals( text ) ) { return null; } else { return root.getText(); } } else { return null; } } /** * Create element and adds it to parent. */ private static Element createElement( Element parent, String name ) { Element elem = new Element( name ); parent.addContent( elem ); return elem; } /** * Create element and adds it to parent. */ public static Element createElement( Element parent, String name, String text ) { Element elem = createElement( parent, name ); elem.setText( text ); return elem; } public static String printDocument( Document doc ) { StringWriter sw = new StringWriter(); XMLOutputter outputter = new XMLOutputter(); try { outputter.output( doc, sw ); return sw.getBuffer().toString(); } catch ( IOException e ) { throw new RuntimeException( "Failed to print document", e ); } } public static String printElement( Element element ) { StringWriter sw = new StringWriter(); XMLOutputter outputter = new XMLOutputter(); try { outputter.output( element, sw ); return sw.getBuffer().toString(); } catch ( IOException e ) { throw new RuntimeException( "Failed to print element", e ); } } public static String prettyPrintDocument( Document doc, String indent ) { return prettyPrintDocument( doc, indent, false ); } public static String prettyPrintDocument( Document doc ) { return prettyPrintDocument( doc, " ", false ); } public static String serialize( Document doc, int indent, boolean omitDecl ) { return serialize( doc, indent, omitDecl, true ); } public static String serializeChildren( Document doc, int indent ) { return serialize( doc, indent, true, false ); } private static String serialize( Document doc, int indent, boolean omitDecl, boolean includeSelf ) { Format format; if ( indent != -1 ) { format = Format.getPrettyFormat().setIndent( Strings.repeat( " ", indent ) ).setOmitDeclaration( omitDecl ).setTextMode( Format.TextMode.TRIM ); } else { format = Format.getRawFormat().setOmitDeclaration( omitDecl ).setTextMode( Format.TextMode.PRESERVE ); } return doSerialize( doc, format, includeSelf ); } private static String doSerialize( Document doc, Format format, boolean includeSelf ) { final XMLOutputter out = new XMLOutputter( format ); if ( includeSelf ) { return out.outputString( doc ); } else { return out.outputString( doc.getRootElement().getChildren() ); } } public static String prettyPrintDocument( Document doc, String indent, boolean sortAttributes ) { StringWriter sw = new StringWriter(); Format format = Format.getPrettyFormat(); format.setIndent( indent ); format.setOmitDeclaration( false ); ExtXMLOutputter outputter = new ExtXMLOutputter( format, sortAttributes ); try { outputter.output( doc, sw ); return sw.getBuffer().toString(); } catch ( IOException e ) { throw new RuntimeException( "Failed to print document", e ); } } public static String evaluateSingleXPathValueAsString( String xpath, Document doc ) { try { XPathEvaluator xpathEvaluator = new XPathEvaluator(); XPathExpression expr = xpathEvaluator.createExpression( xpath ); final JDOMSource docAsDomSource = new JDOMSource( doc ); List nodes = expr.evaluate( docAsDomSource ); if ( nodes.size() > 1 ) { throw new IllegalArgumentException( "Did not expected more than one value at xpath" ); } Object valueAsObject = expr.evaluateSingle( docAsDomSource ); String valueAsString; if ( valueAsObject == null ) { return null; } else if ( valueAsObject instanceof NodeInfo ) { NodeInfo valueAsNodeInfo = (NodeInfo) valueAsObject; valueAsString = valueAsNodeInfo.getStringValue(); } else { valueAsString = String.valueOf( valueAsObject ); } return valueAsString; } catch ( Exception e ) { throw new RuntimeException( e ); } } private static SAXBuilder getSAXBuilder() { return threadLocalSAXBuilder.get(); } /** * Extended xml outputter. */ private final static class ExtXMLOutputter extends XMLOutputter { /** * Sort attributes. */ private final boolean sortAttributes; /** * Construct the outputter. */ public ExtXMLOutputter( Format format, boolean sortAttributes ) { super( format ); this.sortAttributes = sortAttributes; } /** * Process the attributes. */ private List<Attribute> processAttributes( List<Attribute> attributes ) { if ( this.sortAttributes ) { ArrayList<Attribute> tmpList = new ArrayList<Attribute>( attributes ); Collections.sort( tmpList, new Comparator<Attribute>() { public int compare( Attribute a1, Attribute a2 ) { return a1.getName().compareTo( a2.getName() ); } } ); return tmpList; } return attributes; } /** * Print the attributes. */ protected void printAttributes( Writer out, List attributes, Element parent, XMLOutputter.NamespaceStack namespaces ) throws IOException { super.printAttributes( out, processAttributes( attributes ), parent, namespaces ); } } }