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

com.soulgalore.velocity.MergeXMLWithVelocity Maven / Gradle / Ivy

/******************************************************
 * Merge XML with a Velocity template
 * 
 * 
 * Copyright (C) 2012 by Peter Hedenskog (http://peterhedenskog.com)
 * 
 ****************************************************** 
 * 
 * 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 com.soulgalore.velocity;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FilePermission;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.FileResourceLoader;
import org.jdom2.Document;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.jdom2.input.sax.XMLReaderSAX2Factory;


/**
 * Merge a XML file with a Velocity template. 
 *  java -jar xml-velocity-1.0-full.jar test.xml test.vm test.properties newfile.xml
 * 	
 * 
 * 

* The parameters: *

    *
  1. the xml file
  2. *
  3. the Velocity template file
  4. *
  5. the properties file, key/vale will be added to the Velocity context, used when merged
  6. *
  7. the output file name
  8. *
  9. Optional second XML file (sitespeed.io uses this when parsing the BrowserTime XML)
  10. *
*

*

* The document is added to the context with {@link #CONTEXT_DOCUMENT} as key. *

*

* You can also add objects to the velocity context by configuration, in the properties file, add: * *

velocity.context.object.1=CLASSNAME:KEYNAME
* And make sure the class exists in the classpath and have a constructor without arguments. See * this example: * *
 * velocity.context.object.1=org.apache.velocity.tools.generic.MathTool:math
 * velocity.context.object.2=org.apache.velocity.tools.generic.EscapeTool:esc
 * velocity.context.object.3=org.apache.commons.math3.stat.descriptive.DescriptiveStatistics:stats
 * velocity.context.object.4=com.soulgalore.velocity.HostTool:host
 * 
*

*

* You can also supply System properties that will be merged, the property needs to start with * {@link #SYSTEM_PROPERTY_START}. It works like this: Set a key * *

com.soulgalore.velocity.key.header
* and in the Velocity file you get the value by $header *

*/ public class MergeXMLWithVelocity { /** * The name of the xml document, added to the context. */ public static final String CONTEXT_DOCUMENT = "document"; public static final String CONTEXT_PROPERTY_OBJECT = "velocity.context.object"; public static final String SYSTEM_PROPERTY_START = "com.soulgalore.velocity.key."; private final VelocityContext context = new VelocityContext(); private final VelocityEngine ve; MergeXMLWithVelocity(Properties properties) { ve = new VelocityEngine(properties); ve.setProperty("resource.loader", "plainfile"); ve.setProperty("plainfile.resource.loader.instance", new PlainFileResourceLoader()); ve.init(); Map keyAndClasses = getClasses(properties); for (Entry value : keyAndClasses.entrySet()) { try { Class clazz = Class.forName(value.getValue()); context.put(value.getKey(), clazz.newInstance()); } catch (Exception e) { System.err.println("Couldn't instantiate class:" + value.getValue() + " with key:" + value.getKey() + " and put it in Velocity context:" + e.toString()); } } final Enumeration e = properties.propertyNames(); while (e.hasMoreElements()) { final String key = (String) e.nextElement(); context.put(key, properties.getProperty(key)); } // Add all system properties starting with specific key Enumeration keys = System.getProperties().keys(); while (keys.hasMoreElements()) { String key = (String) keys.nextElement(); if (key.startsWith(SYSTEM_PROPERTY_START)) { context.put(key.replace(SYSTEM_PROPERTY_START, ""), System.getProperties().get(key)); } } } /** * Merge a xml file with Velocity template. The third parameter is the properties file, where the * key/value is added to the velocity context. The fourth parameter is the output file. If not * included, the result is printed to system.out. * * @param args are file.xml template.vm properties.prop [output.file] * @throws JDOMException if the xml file couldn't be parsed * @throws IOException couldn't find one of the files */ public static void main(String[] args) throws JDOMException, IOException { if (args.length < 3) { System.out .println("Missing input files. XMLToVelocity file.xml template.vm prop.properties [output.file]"); return; } final Properties properties = new Properties(); final File prop = new File(args[2]); if (prop.exists()) properties.load(new FileReader(prop)); else throw new IOException("Couldn't find the property file:" + prop.getAbsolutePath()); final MergeXMLWithVelocity xtv = new MergeXMLWithVelocity(properties); xtv.create(args); } void create(String[] args) throws JDOMException, IOException { Set xmls = new HashSet(); if (args.length > 4) { for (int i = 4; i < args.length; i++) { xmls.add(args[i]); } } String result = (args.length > 4) ? merge(args[0], args[1], xmls.toArray(new String[0])) : merge(args[0], args[1]); final PrintWriter out = new PrintWriter(new FileOutputStream(args[3])); out.write(result); out.close(); } String merge(String xml, String template) throws JDOMException, IOException { return merge(xml, template, new String[] {}); } String merge(String xml, String template, String[] extraXMLs) throws JDOMException, IOException { final File xmlFile = new File(xml); final SAXBuilder b = new SAXBuilder(new XMLReaderSAX2Factory(false)); final Document doc = b.build(xmlFile); context.put(CONTEXT_DOCUMENT, doc); // TODO Old legacy naming, make this cleaner in the future int name = 2; for (String extraXML : extraXMLs) { final File xmlFileExtra = new File(extraXML); final Document doc2 = b.build(xmlFileExtra); context.put(CONTEXT_DOCUMENT + name, doc2); name++; } final StringWriter writer = new StringWriter(); final Template fromTemplate = ve.getTemplate(template); fromTemplate.merge(context, writer); return writer.toString(); } private Map getClasses(Properties properties) { Map keyAndClass = new HashMap(); Set keys = properties.stringPropertyNames(); for (String key : keys) { if (key.startsWith(CONTEXT_PROPERTY_OBJECT)) { String value = properties.getProperty(key); String className = value.substring(0, value.indexOf(":")); String contextKey = value.substring(value.indexOf(":") + 1, value.length()); keyAndClass.put(contextKey, className); } } return keyAndClass; } }