/* 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)); } }