lipsync/bocoree/XmlSerializer.cs

432 lines
16 KiB
C#
Raw Normal View History

/*
* XmlSerializer.cs
* Copyright (c) 2009 kbinani
*
* This file is part of bocoree.
*
* bocoree is free software; you can redistribute it and/or
* modify it under the terms of the BSD License.
*
* bocoree 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.
*/
#if JAVA
package org.kbinani.xml;
import java.io.*;
import java.util.*;
import java.lang.reflect.*;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
import org.w3c.dom.*;
/**
* .NETのSystem.Xml.Serialization.XmlSerializerと同じ書式で入出力するためのXMLシリアライザ<br>
* <br>
* <dl>
* <dt>getXmlElementNameメソッド</dt>
* <dd>getter/setter名からXMLのード名を調べる</dd>
* <dt>isXmlIgnoredメソッド</dt>
* <dd>XMLに出力するかどうかを決める</dd>
* <dt>getGenericTypeNameメソッド</dt>
* <dd>調</dd>
* </dl>
* <pre>
* public class Test2{
public float value = 1.0f;
private boolean m_b = true;
private int m_i = 2;
public Vector<Integer> list = new Vector<Integer>();
public boolean isHoge(){
return m_b;
}
public void setHoge( boolean value ){
m_b = value;
}
public int getInteger(){
return m_i;
}
public void setInteger( int value ){
m_i = value;
}
public static String getXmlElementName( String name ){
if( name.equals( "value" ) ){
return "Value";
}else if( name.equals( "list" ) ){
return "List";
}
return name;
}
public static boolean isXmlIgnored( String name ){
if( name.equals( "Integer" ) ){
return true;
}
return false;
}
public static String getGenericTypeName( String name ){
if( name.equals( "list" ) ){
return "java.lang.Integer";
}
return "";
}
}
* </pre>
* XMLの入出力が可能になります
* <pre>
&lt;Test2&gt;
&lt;Value&gt;1.0&lt;/Value&gt;
&lt;Hoge&gt;true&lt;/Hoge&gt;
&lt;List&gt;
&lt;int&gt;1&lt;/int&gt;
&lt;int&gt;2&lt;/int&gt;
&lt;/List&gt;
&lt;/Test2&gt;
* </pre>
*/
public class XmlSerializer{
private Document m_document;
private Class m_class;
private boolean m_static_mode = false;
private boolean m_indent = true;
private int m_indent_width = 2;
public boolean isIndent(){
return m_indent;
}
public void setIndent( boolean value ){
m_indent = value;
}
public int getIndentWidth(){
return m_indent_width;
}
public void setIndentWidth( int value ){
if( value < 0 ){
m_indent_width = 0;
}else{
m_indent_width = value;
}
}
public XmlSerializer( Class cls ){
m_class = cls;
}
public Object deserialize( InputStream stream ){
try{
DocumentBuilderFactory fact = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = fact.newDocumentBuilder();
Document doc = builder.parse( stream );
Object ret = parseNode( m_class, null, doc.getDocumentElement() );
return ret;
}catch( Exception ex ){
System.out.println( "XmlSerializer.deserialize; ex=" + ex );
return null;
}
}
private Object parseNode( Class t, Class parent_class, Node node ){
NodeList childs = node.getChildNodes();
int numChild = childs.getLength();
Object obj;
String str = node.getTextContent() + "";
if( t.equals( Integer.TYPE ) || t.equals( Integer.class ) ){
return Integer.parseInt( str );
}else if( t.equals( Byte.TYPE ) || t.equals( Byte.class ) ){
return Byte.parseByte( str );
}else if( t.equals( Short.TYPE ) || t.equals( Short.class ) ){
return Short.parseShort( str );
}else if( t.equals( Float.TYPE ) || t.equals( Float.class ) ){
return Float.parseFloat( str );
}else if( t.equals( Double.TYPE ) || t.equals( Double.class ) ){
return Double.parseDouble( str );
}else if( t.equals( Boolean.TYPE ) || t.equals( Boolean.class ) ){
return Boolean.parseBoolean( str );
}else if( t.equals( String.class ) ){
return str;
}else if( t.isEnum() ){
return Enum.valueOf( t, str );
}else if( t.isArray() || t.equals( Vector.class ) ){
// Class tがstatic String getGenericTypeName( String )を実装しているかどうか調べる
Method method = null;
if( parent_class == null ){
return null;
}
for( Method m : parent_class.getDeclaredMethods() ){
if( !m.getName().equals( "getGenericTypeName" ) ){
continue;
}
int modifier = m.getModifiers();
if( !Modifier.isStatic( modifier ) || !Modifier.isPublic( modifier ) ){
continue;
}
if( !m.getReturnType().equals( String.class ) ){
continue;
}
Class[] args = m.getParameterTypes();
if( args.length != 1 ){
continue;
}
if( !args[0].equals( String.class ) ){
continue;
}
method = m;
break;
}
if( method == null ){
return null;
}
try{
String content_class_name = (String)method.invoke( null, node.getNodeName() );
Class content_class = Class.forName( content_class_name );
Vector<Object> vec = new Vector<Object>();
String element_name = getCliTypeName( content_class );
if( element_name.equals( "" ) ){
element_name = content_class.getSimpleName();
}
for( int i = 0; i < numChild; i++ ){
Node c = childs.item( i );
if( c.getNodeType() == Node.ELEMENT_NODE ){
Element f = (Element)c;
if( !f.getTagName().equals( element_name ) ){
continue;
}
vec.add( parseNode( content_class, t, c ) );
}
}
if( t.isArray() ){
int length = vec.size();
Object arr = Array.newInstance( content_class, length );
for( int i = 0; i < length; i++ ){
Array.set( arr, i, vec.get( i ) );
}
return arr;
}else if( t.equals( Vector.class ) ){
return vec;
}
}catch( Exception ex ){
System.out.println( "XmlSerializer.parseNode; ex=" + ex );
return null;
}
}
try{
obj = t.newInstance();
}catch( Exception ex ){
return null;
}
XmlMember[] members = XmlMember.extractMembers( t );
for( int i = 0; i < numChild; i++ ){
Node c = childs.item( i );
if( c.getNodeType() == Node.ELEMENT_NODE ) {
Element f = (Element)c;
String name = f.getTagName();
for( XmlMember xm : members ){
if( f.getTagName().equals( xm.getName() ) ) {
xm.set( obj, parseNode( xm.getType(), t, c ) );
break;
}
}
}
}
return obj;
}
public void serialize( OutputStream stream, Object obj ) throws TransformerConfigurationException,
ParserConfigurationException,
TransformerException,
IllegalAccessException{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
DOMImplementation domImpl=builder.getDOMImplementation();
m_document = domImpl.createDocument( null, m_class.getSimpleName(), null );
Element root = m_document.getDocumentElement();
parseFieldAndProperty( m_class, obj, root );
TransformerFactory tfactory = TransformerFactory.newInstance();
Transformer transformer = tfactory.newTransformer();
if( m_indent ){
transformer.setOutputProperty( OutputKeys.INDENT, "yes" );
}
transformer.setOutputProperty( OutputKeys.METHOD, "xml" );
if( m_indent ){
transformer.setOutputProperty( "{http://xml.apache.org/xalan}indent-amount", "" + m_indent_width );
}
transformer.transform( new DOMSource( m_document ), new StreamResult( stream ) );
}
private void parseFieldAndProperty( Class t, Object obj, Element el ) throws IllegalAccessException{
if( obj == null ){
return;
}
XmlMember[] members = XmlMember.extractMembers( t );
for( XmlMember xm : members ){
String name = xm.getName();
Element el2 = m_document.createElement( name );
printItemRecurse( xm.getType(), xm.get( obj ), el2 );
el.appendChild( el2 );
}
}
private void printItemRecurse( Class t, Object obj, Element parent ) throws IllegalAccessException{
try{
if ( !tryWriteValueType( t, obj, parent ) ){
if( t.isArray() || t.equals( Vector.class ) ){
Object[] array = null;
if( t.isArray() ){
array = (Object[])obj;
}else if( t.equals( Vector.class ) ){
array = ((Vector)obj).toArray();
}
if( array != null ){
for( Object o : array ){
if( o != null ){
String name = getCliTypeName( o.getClass() );
if( name.equals( "" ) ){
name = o.getClass().getSimpleName();
}
Element element = m_document.createElement( name );
printItemRecurse( o.getClass(), o, element );
parent.appendChild( element );
}
}
}
}else{
parseFieldAndProperty( t, obj, parent );
}
}
}catch( Exception ex ){
System.out.println( "printItemRecurse; ex=" + ex );
}
}
private static String getCliTypeName( Class t ){
if( t.equals( Boolean.class ) || t.equals( Boolean.TYPE ) ){
return "bool";
}else if( t.equals( Double.class ) || t.equals( Double.TYPE ) ){
return "double";
}else if( t.equals( Integer.class ) || t.equals( Integer.TYPE ) ){
return "int";
}else if( t.equals( Long.class ) || t.equals( Long.TYPE ) ){
return "long";
}else if( t.equals( Short.class ) || t.equals( Short.TYPE ) ){
return "short";
}else if( t.equals( Float.class ) || t.equals( Float.TYPE ) ){
return "float";
}else if( t.equals( String.class ) ){
return "string";
}else{
return "";
}
}
private boolean tryWriteValueType( Class t, Object obj, Element element ){
if( t.equals( Boolean.class ) || t.equals( Boolean.TYPE ) ){
element.appendChild( m_document.createTextNode( (Boolean)obj + "" ) );
return true;
}else if( t.equals( Double.class ) || t.equals( Double.TYPE ) ){
element.appendChild( m_document.createTextNode( (Double)obj + "" ) );
return true;
}else if( t.equals( Integer.class ) || t.equals( Integer.TYPE ) ){
element.appendChild( m_document.createTextNode( (Integer)obj + "" ) );
return true;
}else if( t.equals( Long.class ) || t.equals( Long.TYPE ) ){
element.appendChild( m_document.createTextNode( (Long)obj + "" ) );
return true;
}else if( t.equals( Short.class ) || t.equals( Short.TYPE ) ){
element.appendChild( m_document.createTextNode( (Short)obj + "" ) );
return true;
}else if( t.equals( Float.class ) || t.equals( Float.TYPE ) ){
element.appendChild( m_document.createTextNode( (Float)obj + "" ) );
return true;
}else if( t.equals( String.class ) ){
if( obj == null ){
element.appendChild( m_document.createTextNode( "" ) );
}else{
element.appendChild( m_document.createTextNode( (String)obj ) );
}
return true;
}else if( t.isEnum() ){
if( obj == null ){
for( Field f : t.getDeclaredFields() ){
String name = f.getName();
if( !name.startsWith( "$" ) ){
element.appendChild( m_document.createTextNode( name ) );
break;
}
}
}else{
element.appendChild( m_document.createTextNode( obj + "" ) );
}
return true;
}else{
return false;
}
}
}
#else
using System;
using System.IO;
using bocoree.xml;
namespace bocoree.xml {
public class XmlSerializer {
private bool m_serialize_static_mode = false;
System.Xml.Serialization.XmlSerializer m_serializer;
XmlStaticMemberSerializer m_static_serializer;
public XmlSerializer( Type cls ) {
m_serializer = new System.Xml.Serialization.XmlSerializer( cls );
}
public XmlSerializer( Type cls, bool serialize_static_mode )
{
m_serialize_static_mode = serialize_static_mode;
if ( serialize_static_mode )
{
m_static_serializer = new XmlStaticMemberSerializer( cls );
}
else
{
m_serializer = new System.Xml.Serialization.XmlSerializer( cls );
}
}
public object deserialize( Stream stream ) {
if ( m_serialize_static_mode )
{
m_static_serializer.Deserialize( stream );
return null;
}
else
{
return m_serializer.Deserialize( stream );
}
}
public void serialize( Stream stream, object obj ) {
if ( m_serialize_static_mode )
{
m_static_serializer.Serialize( stream );
}
else
{
m_serializer.Serialize( stream, obj );
}
}
}
}
#endif