/* Serializer.java -- Recursively serializes an object as XML.
Copyright (C) 2005 The University of Sheffield.
This file is part of the CASheW-s editor.
The CASheW-s editor is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
The CASheW-s editor is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with The CASheW-s editor; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA.
*/
package nongnu.cashews.xml;
import java.lang.reflect.Field;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import nongnu.cashews.language.process.CompositeProcess;
import nongnu.cashews.language.process.Sequence;
import nongnu.cashews.xml.schema.TypeMapper;
import nongnu.cashews.xml.schema.XsdType;
import org.w3c.dom.Document;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSSerializer;
/**
* Generically serializes an object to an XML tree.
*
* @author Andrew John Hughes (gnu_andrew@member.fsf.org)
*/
public class Serializer
{
/**
* Implementation of the DOM for use within this class.
*/
private static DOMImplementation domImpl;
/**
* Initialize the DOM implementation (one time operation only).
*
* @throws InstantiationException if the implementation class couldn't
* be instantiated.
* @throws IllegalAccessException if the implementation class can't be
* accessed.
* @throws ClassNotFoundException if the implementation class can't be
* found.
*/
private static void initializeImpl()
throws InstantiationException, IllegalAccessException,
ClassNotFoundException
{
if (domImpl == null)
{
DOMImplementationRegistry registry =
DOMImplementationRegistry.newInstance();
domImpl = registry.getDOMImplementation("LS 3.0");
}
}
/**
* Serializes the specified object into an XML tree. If the supplied
* document argument is not null
, the resulting tree
* is appended it. Otherwise, a new document is created.
*
* @param object the object to serialize.
* @param root the root node to append to, or null
* if a new root node should be created.
* @param document the document to use for creation.
* @return the serialized object in XML form.
* @throws IllegalAccessException if a field can't be accessed.
*/
public static Node serialize(Xmlizable object, Node root,
Document document)
throws IllegalAccessException
{
List fields = new LinkedList();
Class clazz = object.getClass();
Element objRoot = createElement(document, clazz.getSimpleName());
while (clazz != null)
{
fields.addAll(0, Arrays.asList(clazz.getDeclaredFields()));
clazz = clazz.getSuperclass();
}
for (Field field: fields)
{
Object value = field.get(object);
if (value == null)
continue;
if (value instanceof Collection)
{
Collection collection = (Collection) value;
for (Object obj : collection)
{
if (obj instanceof Xmlizable)
serialize((Xmlizable) value, objRoot, document);
}
}
else if (value instanceof Xmlizable)
serialize((Xmlizable) value, objRoot, document);
else
{
Element element = createElement(document, field.getName());
serializeValue(document, element, value);
objRoot.appendChild(element);
}
}
if (root != null)
{
root.appendChild(objRoot);
return root;
}
return objRoot;
}
/**
* Converts an XML document to a String
.
*
* @param document the document to convert.
*/
public static String convertDocumentToString(Document document)
{
DOMImplementationLS loadAndSave = (DOMImplementationLS) domImpl;
LSSerializer serializer = loadAndSave.createLSSerializer();
return serializer.writeToString(document);
}
/**
* Serializes a reflected class field and its contents into an XML element.
* An XML schema datatype is searched for first, in order to provide
* the most appropriate translation. If this fails, the
* toString()
content is used.
*
* @param document the document instance for creating further XML nodes.
* @param element the element to serialize to.
* @param value the value to serialize.
* @return the serialized element.
*/
private static void serializeValue(Document document, Element element,
Object value)
{
TypeMapper mapper = new TypeMapper();
Class clazz = value.getClass();
XsdType schemaType = mapper.map(clazz);
if (schemaType == null)
element.appendChild(document.createTextNode(value.toString()));
else
element.appendChild(schemaType.translateValue(document, value));
}
/**
* Creates an element with the appropriate naming schema.
*
* @param document the document for creating elements.
* @param name the proposed document name.
* @return the created element.
*/
private static Element createElement(Document document, String name)
{
char firstChar = name.charAt(0);
if (Character.isUpperCase(firstChar))
name = Character.toLowerCase(firstChar)
+ name.substring(1, name.length());
return document.createElement(name);
}
/**
* A simple test harness to ensure that objects can be successfully
* converted to XML.
*
* @param args the command-line arguments.
* @throws InstantiationException if a class couldn't be
* instantiated.
* @throws IllegalAccessException if a class can't be accessed.
* @throws ClassNotFoundException if a class can't be found.
* @throws URISyntaxException if one of the names is not a valid URI.
*/
public static void main(String[] args)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException, URISyntaxException
{
CompositeProcess process = new CompositeProcess("MyProcess");
Sequence sequence = new Sequence();
process.setControlStructure(sequence);
initializeImpl();
Document document = domImpl.createDocument(null,null,null);
document.appendChild(Serializer.serialize(process, null, document));
System.out.println(convertDocumentToString(document));
}
}