/*
* Copyright (c) 2002-2003 by OpenSymphony
* All rights reserved.
*/
package com.opensymphony.util;
import org.xml.sax.*;
import org.xml.sax.helpers.AttributesImpl;
import org.xml.sax.helpers.DefaultHandler;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;
/**
* XMLReaderAdapter converts a java bean to its xml representation. It does
* this by simulating a SAX XMLReader which an xslt processor can use as
* a SAXSource.
*
* @author <a href="mailto:[email protected]">Victor Salaman</a>
* @version $Revision: 5 $
*/
public class XMLReaderAdapter implements Locator, XMLReader {
//~ Static fields/initializers /////////////////////////////////////////////
private static final Object[] NULLPARAMS = new Object[0];
private static final String EMPTYSTRING = null; //new String();
//~ Instance fields ////////////////////////////////////////////////////////
private AttributesImpl atts = new AttributesImpl();
private ContentHandler contentHandler = new DefaultHandler();
private Object object;
private String root = null;
private String systemId;
//~ Constructors ///////////////////////////////////////////////////////////
public XMLReaderAdapter(Object object) {
this(object, null);
}
public XMLReaderAdapter(Object object, String root) {
this.object = object;
this.root = root;
}
//~ Methods ////////////////////////////////////////////////////////////////
public int getColumnNumber() {
return -1;
}
public void setContentHandler(ContentHandler handler) {
this.contentHandler = handler;
}
public ContentHandler getContentHandler() {
return contentHandler;
}
public void setDTDHandler(DTDHandler handler) {
}
public DTDHandler getDTDHandler() {
return null;
}
public void setEntityResolver(EntityResolver resolver) {
}
public EntityResolver getEntityResolver() {
return null;
}
public void setErrorHandler(ErrorHandler handler) {
}
public ErrorHandler getErrorHandler() {
return null;
}
public void setFeature(String featureId, boolean on) throws SAXNotRecognizedException, SAXNotSupportedException {
}
public boolean getFeature(String featureId) throws SAXNotRecognizedException {
return false;
}
public int getLineNumber() {
return -1;
}
public void setObject(Object object) {
this.object = object;
}
public void setProperty(String propertyId, Object property) throws SAXNotRecognizedException, SAXNotSupportedException {
}
public Object getProperty(String name) throws SAXNotRecognizedException {
throw new SAXNotRecognizedException(name);
}
public String getPublicId() {
return null;
}
public void setRoot(String root) {
this.root = root;
}
public String getSystemId() {
return systemId;
}
public void parse(InputSource source) throws IOException, SAXException {
parse();
}
public void parse(String s) throws IOException, SAXException {
parse();
}
public void parse() throws IOException, SAXException {
if (object == null) {
throw new SAXException("no object to reflected defined");
}
if (contentHandler == null) {
throw new SAXException("no content handler defined");
}
contentHandler.setDocumentLocator(this);
contentHandler.startDocument();
walk(object, (root == null) ? "data" : root, false);
contentHandler.endDocument();
}
private String getTagName(String tagName) {
boolean lastWasLower = false;
int bufIndex = 0;
int oIndex = tagName.length();
StringBuffer buff = new StringBuffer(tagName);
for (int i = 0; i < oIndex; i++) {
char c = tagName.charAt(i);
if (i > 0) {
if (lastWasLower && Character.isUpperCase(c)) {
buff.setCharAt(bufIndex, Character.toLowerCase(c));
buff.insert(bufIndex, '-');
bufIndex++;
}
} else {
buff.setCharAt(0, Character.toLowerCase(c));
lastWasLower = true;
}
bufIndex++;
}
return buff.toString();
}
private void walk(Object object, String name, boolean useKey) throws SAXException {
boolean accessorsFound;
if (!useKey) {
contentHandler.startElement(EMPTYSTRING, name, EMPTYSTRING, atts);
} else {
AttributesImpl atts = new AttributesImpl();
atts.addAttribute(EMPTYSTRING, EMPTYSTRING, "key", "key", name);
contentHandler.startElement(EMPTYSTRING, "item", EMPTYSTRING, atts);
}
try {
if (object != null) {
Class c = object.getClass();
if (c.isAssignableFrom(String.class)) {
String value = (String) object;
contentHandler.characters(value.toCharArray(), 0, value.length());
} else {
PropertyDescriptor[] props = Introspector.getBeanInfo(c, Object.class).getPropertyDescriptors();
accessorsFound = false;
for (int i = 0; i < props.length; i++) {
Method m = props[i].getReadMethod();
String s = m.getName();
if ((s.startsWith("get") && (s.length() > 3)) || (s.startsWith("is") && (s.length() > 2))) {
String attributeName = getTagName(s.substring(s.startsWith("is") ? 2 : 3));
Class rt = m.getReturnType();
if (attributeName.equals("class")) {
continue;
}
if (m.getParameterTypes().length == 0) {
Object value = m.invoke(object, NULLPARAMS);
if (value == null) {
continue;
}
accessorsFound = true;
if (Collection.class.isAssignableFrom(value.getClass())) {
Collection cole = (Collection) value;
contentHandler.startElement(EMPTYSTRING, attributeName, EMPTYSTRING, atts);
for (Iterator colIter = cole.iterator();
colIter.hasNext();) {
Object obj = (Object) colIter.next();
walk(obj, "item", false);
}
contentHandler.endElement(EMPTYSTRING, attributeName, EMPTYSTRING);
continue;
} else if (Enumeration.class.isAssignableFrom(value.getClass())) {
Enumeration e = (Enumeration) value;
contentHandler.startElement(EMPTYSTRING, attributeName, EMPTYSTRING, atts);
while (e.hasMoreElements()) {
Object obj = (Object) e.nextElement();
walk(obj, "item", false);
}
contentHandler.endElement(EMPTYSTRING, attributeName, EMPTYSTRING);
continue;
} else if (Vector.class.isAssignableFrom(value.getClass())) {
Vector vec = (Vector) value;
contentHandler.startElement(EMPTYSTRING, attributeName, EMPTYSTRING, atts);
for (int ix = 0; ix < vec.size(); ix++) {
Object obj = (Object) vec.elementAt(ix);
walk(obj, "item", false);
}
contentHandler.endElement(EMPTYSTRING, attributeName, EMPTYSTRING);
continue;
}
if (Map.class.isAssignableFrom(value.getClass())) {
contentHandler.startElement(EMPTYSTRING, attributeName, EMPTYSTRING, atts);
Map map = (Map) value;
for (Iterator iter = map.entrySet().iterator();
iter.hasNext();) {
Map.Entry entry = (Map.Entry) iter.next();
walk(entry.getValue(), (String) entry.getKey(), true);
}
contentHandler.endElement(EMPTYSTRING, attributeName, EMPTYSTRING);
continue;
} else {
walk(value, attributeName, false);
}
}
}
}
if (!accessorsFound) {
contentHandler.characters(object.toString().toCharArray(), 0, object.toString().length());
}
}
}
} catch (Exception e) {
throw new SAXException(e);
}
if (!useKey) {
contentHandler.endElement(EMPTYSTRING, name, EMPTYSTRING);
} else {
contentHandler.endElement(EMPTYSTRING, "item", EMPTYSTRING);
}
}
}
|