mirror of
https://git.femboyfinancial.jp/james/lipsync.git
synced 2024-11-29 21:22:00 -08:00
432 lines
16 KiB
C#
432 lines
16 KiB
C#
|
/*
|
|||
|
* 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>
|
|||
|
<Test2>
|
|||
|
<Value>1.0</Value>
|
|||
|
<Hoge>true</Hoge>
|
|||
|
<List>
|
|||
|
<int>1</int>
|
|||
|
<int>2</int>
|
|||
|
</List>
|
|||
|
</Test2>
|
|||
|
* </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
|