/*******************************************************************************
* Copyright 2016
* Ubiquitous Knowledge Processing (UKP) Lab
* Technische Universität Darmstadt
*
* 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 de.tudarmstadt.ukp.lmf.transform;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
import de.tudarmstadt.ukp.lmf.model.interfaces.IHasID;
import de.tudarmstadt.ukp.lmf.model.miscellaneous.AccessType;
import de.tudarmstadt.ukp.lmf.model.miscellaneous.EVarType;
import de.tudarmstadt.ukp.lmf.transform.UBYLMFClassMetadata.UBYLMFFieldMetadata;
/**
* Abstract base class for all resource transformations involving the
* generation of UBY-XML. The class allows for creating XML tags from
* UBY-LMF model objects.
* @author Christian M. Meyer
*/
public abstract class UBYXMLTransformer extends UBYTransformer {
protected TransformerHandler th;
/** Creates XML TransformerHandler. */
protected void writeStartDocument(final OutputStream outputStream,
final String dtdPath) throws SAXException {
try {
SAXTransformerFactory tf = (SAXTransformerFactory) TransformerFactory.newInstance();
th = tf.newTransformerHandler();
Transformer serializer = th.getTransformer();
serializer.setOutputProperty(OutputKeys.METHOD, "xml");
serializer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
serializer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
if (dtdPath != null)
serializer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, dtdPath);
serializer.setOutputProperty(OutputKeys.INDENT, "yes");
serializer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
th.setResult(new StreamResult(outputStream));
} catch (TransformerConfigurationException e) {
throw new SAXException(e);
}
}
/** Writes lmfObject to XML without writing closing Tag for this Element.
* @throws SAXException in case of any errors. */
protected void writeStartElement(final Object lmfObject) throws SAXException {
doWriteElement(lmfObject, false);
}
/** Writes lmfObject to XML with closing tags.
* @throws SAXException in case of any errors. */
protected void writeElement(Object lmfObject) throws SAXException {
doWriteElement(lmfObject, true);
}
/** Appends an end tag for the given object.
* @throws SAXException in case of any errors. */
protected void writeEndElement(Object lmfObject) throws SAXException {
String elementName = lmfObject.getClass().getSimpleName();
th.endElement("", "", elementName);
}
/**
* This method consumes a LMF Object and transforms it to XML. The method
* iterates over all fields of a class and searches for the {@link AccessType} annotations.
* Depending on the value of the annotation, the method reads the values of the objects
* fields by invoking a getter or by directly accessing the field.
*
* @param lmfObject An LMF Object for which an Element should be created
* @param closeTag If TRUE the closing Tag for the XML-Element will be created
*
* @throws SAXException if writing to XML-file is for some reason not possible
*/
@SuppressWarnings("unchecked")
protected void doWriteElement(Object lmfObject, boolean closeTag)
throws SAXException {
Class<?> lmfClass = lmfObject.getClass();
String elementName = lmfClass.getSimpleName();
int hibernateSuffixIdx = elementName.indexOf("_$$");
if (hibernateSuffixIdx > 0)
elementName = elementName.substring(0, hibernateSuffixIdx);
AttributesImpl atts = new AttributesImpl();
List<Object> children = new ArrayList<Object>();
UBYLMFClassMetadata classMeta = getClassMetadata(lmfClass);
for (UBYLMFFieldMetadata fieldMeta : classMeta.getFields()) {
EVarType varType = fieldMeta.getVarType();
if (varType == EVarType.NONE)
continue;
String xmlFieldName = fieldMeta.getName().replace("_", "");
Method getter = fieldMeta.getGetter();
Object retObj;
try {
retObj = getter.invoke(lmfObject);
} catch (IllegalAccessException e) {
throw new SAXException(e);
} catch (InvocationTargetException e) {
throw new SAXException(e);
}
if (retObj != null) {
switch (fieldMeta.getVarType()) {
case ATTRIBUTE:
case ATTRIBUTE_OPTIONAL:
atts.addAttribute("", "", xmlFieldName, "CDATA", retObj.toString());
break;
case CHILD:
// Transform children of the new element to XML
children.add(retObj);
break;
case CHILDREN:
if (closeTag)
for (Object obj : (Iterable<Object>) retObj)
children.add(obj);
break;
case IDREF:
// Save IDREFs as attribute of the new element
atts.addAttribute("", "", xmlFieldName, "CDATA", ((IHasID) retObj).getId());
break;
case IDREFS:
StringBuilder attrValue = new StringBuilder();
for (Object obj : (Iterable<Object>) retObj)
attrValue.append(attrValue.length() > 0 ? " " : "")
.append(((IHasID) obj).getId());
if (attrValue.length() > 0)
atts.addAttribute("", "", xmlFieldName, "CDATA", attrValue.toString());
break;
case NONE:
break;
}
}
}
// Save the current element and its children
th.startElement("", "", elementName, atts);
for (Object child : children)
doWriteElement(child, true);
if (closeTag)
th.endElement("", "", elementName);
}
/** Ends the Document. */
protected void writeEndDocument() throws SAXException {
th.endDocument();
}
}