/*
* Copyright (c) 2003-2012 Fred Hutchinson Cancer Research Center
*
* 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 org.fhcrc.cpl.toolbox.filehandler;
import org.apache.log4j.Logger;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.GregorianCalendar;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
/**
* Helper class to pull events and rewrite them with modification or with new
* elements interspersed. Override handleStartElement, handleEndElement, etc.,
* instantiate, and call rewrite(). See the Q3.java code for an example of
* rewriting a pepXML file.
*/
public class SimpleXMLEventRewriter
{
private static Logger _log = Logger.getLogger(SimpleXMLEventRewriter.class);
private static XMLEventFactory eventFactory = XMLEventFactory.newInstance();
private static DatatypeFactory typeFactory = null;
static
{
// Rethrow any DatatypeFactory setup errors
try
{
typeFactory = DatatypeFactory.newInstance();
}
catch (DatatypeConfigurationException e)
{
throw new ExceptionInInitializerError(e);
}
}
private InputStream in = null;
private PrintStream out = null;
private String inFileName = null;
private String outFileName = null;
private XMLEventReader parser = null;
private XMLEventWriter writer = null;
public SimpleXMLEventRewriter(String inFileName, String outFileName)
{
this.inFileName = inFileName;
this.outFileName = outFileName;
}
/**
*
*/
private static XMLEventReader createParser(InputStream in)
throws XMLStreamException
{
XMLInputFactory inFactory = XMLInputFactory.newInstance();
inFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
return inFactory.createXMLEventReader(in);
}
/**
*
*/
private static XMLEventWriter createWriter(OutputStream out)
throws XMLStreamException
{
XMLOutputFactory outFactory = XMLOutputFactory.newInstance();
return outFactory.createXMLEventWriter(out);
}
protected void emit(String content)
throws XMLStreamException
{
writer.flush();
out.println(content);
}
public void add(SimpleElement element)
throws XMLStreamException
{
writer.add(element.getEvent());
}
public void add(XMLEvent event)
throws XMLStreamException
{
writer.add(event);
}
public void addNewline()
throws XMLStreamException
{
// TODO: Should really make line end style consistent for entire file
writer.add(eventFactory.createSpace("\n"));
}
public void handleDefault(XMLEvent event)
throws XMLStreamException
{
add(event);
}
public void handleDiscard(XMLEvent event)
throws XMLStreamException
{
// Discard; take no action
}
public void handleStartDocument(XMLEvent event)
throws XMLStreamException
{
add(event);
}
public void handleEndDocument(XMLEvent event)
throws XMLStreamException
{
add(event);
}
public void handleStartElement(StartElement event)
throws XMLStreamException
{
add(event);
}
public void handleEndElement(EndElement event)
throws XMLStreamException
{
add(event);
}
/**
*
*/
public void rewrite()
throws IOException, XMLStreamException
{
try
{
in = new FileInputStream(inFileName);
out = new PrintStream(outFileName);
parser = createParser(in);
writer = createWriter(out);
while (parser.hasNext())
{
XMLEvent event = parser.nextEvent();
switch (event.getEventType())
{
case XMLStreamConstants.ATTRIBUTE:
case XMLStreamConstants.CDATA:
case XMLStreamConstants.CHARACTERS:
case XMLStreamConstants.COMMENT:
case XMLStreamConstants.DTD:
case XMLStreamConstants.ENTITY_DECLARATION:
case XMLStreamConstants.ENTITY_REFERENCE:
case XMLStreamConstants.NAMESPACE:
case XMLStreamConstants.NOTATION_DECLARATION:
case XMLStreamConstants.PROCESSING_INSTRUCTION:
case XMLStreamConstants.SPACE:
handleDefault(event);
break;
case XMLStreamConstants.START_DOCUMENT:
handleStartDocument(event);
break;
case XMLStreamConstants.END_DOCUMENT:
handleEndDocument(event);
break;
case XMLStreamConstants.START_ELEMENT:
handleStartElement(event.asStartElement());
break;
case XMLStreamConstants.END_ELEMENT:
handleEndElement(event.asEndElement());
break;
default:
_log.error("Unrecognized event type " + event.getEventType());
throw new XMLStreamException("Unrecognized event type " + event.getEventType());
}
}
}
finally
{
close();
}
}
/**
*
*/
public void close()
{
try {
if (null != parser) parser.close();
} catch (Exception e) {
} finally {
parser = null;
}
try {
if (null != in) in.close();
} catch (Exception e) {
} finally {
in = null;
}
try {
if (null != writer) writer.close();
} catch (Exception e) {
} finally {
writer = null;
}
try {
if (null != out) out.close();
} catch (Exception e) {
} finally {
out = null;
}
}
/**
*
*/
protected static interface SimpleElement
{
XMLEvent getEvent();
}
/**
* Helpers for consing up StartElements
*/
public static class SimpleStartElement implements SimpleElement
{
private String name = null;
private ArrayList<Attribute> attrs = null;
/**
* Create a start tag with the given name
*/
public SimpleStartElement(String name)
{
this.name = name;
}
/**
* Add an array of attributes to this start tag
*/
public SimpleStartElement(String name, Attribute[] attrs)
{
this.name = name;
this.attrs = new ArrayList<Attribute>(Arrays.asList(attrs));
}
/**
* Add a string valued attribute
*/
public void addAttribute(String name, String value)
throws XMLStreamException
{
if (null == attrs)
attrs = new ArrayList<Attribute>();
attrs.add(eventFactory.createAttribute(name, value));
}
/**
* Add a char valued attribute
*/
public void addAttribute(String name, char value)
throws XMLStreamException
{
addAttribute(name, "" + value);
}
/**
* Add a int valued attribute
*/
public void addAttribute(String name, int value)
throws XMLStreamException
{
addAttribute(name, "" + value);
}
/**
* Add a floatvalued attribute
*/
public void addAttribute(String name, float value)
throws XMLStreamException
{
addAttribute(name, String.format("%f", value));
}
/**
* Add a double valued attribute
*/
public void addAttribute(String name, double value)
throws XMLStreamException
{
addAttribute(name, String.format("%f", value));
}
/**
* Add a timestamp attribute
* @throws NullPointerException if <code>value</code> is <code>null</code>.
*/
public void addAttribute(String name, GregorianCalendar value)
throws XMLStreamException
{
addAttribute(name, "" + typeFactory.newXMLGregorianCalendar(value).toXMLFormat());
}
/**
* Create an event for this element
* @return XMLEvent for this StartElement
*/
public XMLEvent getEvent()
{
return eventFactory.createStartElement("", "", name, attrs.iterator(), null);
}
}
/**
* Helpers for creating end elements
*/
public static class SimpleEndElement implements SimpleElement
{
private String name = null;
/**
* Create an end element with the given name
*/
public SimpleEndElement(String name)
{
this.name = name;
}
/**
* Create an event for this element
* @return XMLEvent for this StartElement
*/
public XMLEvent getEvent()
{
return eventFactory.createEndElement("", "", name);
}
}
/**
* Create a space element
*/
public static class SimpleSpaceElement implements SimpleElement
{
private String content = null;
public SimpleSpaceElement(String content)
{
this.content = content;
}
public XMLEvent getEvent()
{
return eventFactory.createSpace(content);
}
}
/**
* Convert an XML time element to a Date
*/
public static Date convertXMLTimeToDate(String lexTime)
{
XMLGregorianCalendar xgc = typeFactory.newXMLGregorianCalendar(lexTime);
return xgc.toGregorianCalendar().getTime();
}
/**
*
*/
public static void main(String[] av)
{
try
{
SimpleXMLEventRewriter s = new SimpleXMLEventRewriter("/home/mfitzgib/AcrylForMarc/data/L_04_IPAS0012_AX01_RP_SG04to10.pep.xml", "foo.pep.xml");
s.rewrite();
s.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}