我经常要编写一些可序列化的类,用于存储配置,通过XML的属性标记可以很容易完成这些工作。但是大量的工作任务让我没有多少时间经常编写些‘体力代码’,于是就考虑如何简化这个工作。
那么XML文件是最终的结构,那么能否从XML结构通过某种工具还原为原始的序列化类代码呢?答案是肯定的。
例如:
一个简单的XML 的描述:
<Test x="100.01" y="199.202" />
它对应的序列化代码为:
[Serializable]
public class Test
{
protected double _x;
protected double _y;
[XmlAttribute()]
public double X
{
get {return this._x;}
set {this._x=value;}
}
[XmlAttribute()]
public double Y
{
get {return this._y;}
set {this._y=value;}
}
}
public class Test
{
protected double _x;
protected double _y;
[XmlAttribute()]
public double X
{
get {return this._x;}
set {this._x=value;}
}
[XmlAttribute()]
public double Y
{
get {return this._y;}
set {this._y=value;}
}
}
一个带集合的XML代码:
<Object Name="MyObject">
<Fields>
<Field Name="Title">
<Values>
<Value Name="ID" PrimaryKey="true"/>
<Value Name="FirstName" Unique="false"/>
<Value Name="LastName" Unique="false" Indexed="true"/>
</Values>
</Field>
</Fields>
<Methods>
<Method Name="Add">
<Params>
<Param Name="X" value="1"/>
<Param Name="Y" value="2"/>
</Params>
</Method>
</Methods>
</Object>
<Fields>
<Field Name="Title">
<Values>
<Value Name="ID" PrimaryKey="true"/>
<Value Name="FirstName" Unique="false"/>
<Value Name="LastName" Unique="false" Indexed="true"/>
</Values>
</Field>
</Fields>
<Methods>
<Method Name="Add">
<Params>
<Param Name="X" value="1"/>
<Param Name="Y" value="2"/>
</Params>
</Method>
</Methods>
</Object>
它对应的序列化代码为:
[Serializable]
public class Param
{
protected int _value;
protected string _name;
[XmlAttribute()]
public int Value
{
get {return this._value;}
set {this._value=value;}
}
[XmlAttribute()]
public string Name
{
get {return this._name;}
set {this._name=value;}
}
}
[Serializable]
public class Object
{
protected string _name;
protected ArrayList _fields;
protected ArrayList _methods;
[XmlAttribute()]
public string Name
{
get {return this._name;}
set {this._name=value;}
}
[XmlArray()]
[XmlArrayItem(typeof(Field))]
public ArrayList Fields
{
get {return this._fields;}
}
[XmlArray()]
[XmlArrayItem(typeof(Method))]
public ArrayList Methods
{
get {return this._methods;}
}
public Object()
{
this._fields=new ArrayList();
this._methods=new ArrayList();
}
}
[Serializable]
public class Field
{
protected string _name;
protected ArrayList _values;
[XmlAttribute()]
public string Name
{
get {return this._name;}
set {this._name=value;}
}
[XmlArray()]
[XmlArrayItem(typeof(Value))]
public ArrayList Values
{
get {return this._values;}
}
public Field()
{
this._values=new ArrayList();
}
}
[Serializable]
public class Value
{
protected string _name;
protected bool _unique;
protected bool _primaryKey;
protected bool _indexed;
[XmlAttribute()]
public string Name
{
get {return this._name;}
set {this._name=value;}
}
[XmlAttribute()]
public bool Unique
{
get {return this._unique;}
set {this._unique=value;}
}
[XmlAttribute()]
public bool PrimaryKey
{
get {return this._primaryKey;}
set {this._primaryKey=value;}
}
[XmlAttribute()]
public bool Indexed
{
get {return this._indexed;}
set {this._indexed=value;}
}
}
[Serializable]
public class Method
{
protected string _name;
protected ArrayList _params;
[XmlAttribute()]
public string Name
{
get {return this._name;}
set {this._name=value;}
}
[XmlArray()]
[XmlArrayItem(typeof(Param))]
public ArrayList Params
{
get {return this._params;}
}
public Method()
{
this._params=new ArrayList();
}
}
public class Param
{
protected int _value;
protected string _name;
[XmlAttribute()]
public int Value
{
get {return this._value;}
set {this._value=value;}
}
[XmlAttribute()]
public string Name
{
get {return this._name;}
set {this._name=value;}
}
}
[Serializable]
public class Object
{
protected string _name;
protected ArrayList _fields;
protected ArrayList _methods;
[XmlAttribute()]
public string Name
{
get {return this._name;}
set {this._name=value;}
}
[XmlArray()]
[XmlArrayItem(typeof(Field))]
public ArrayList Fields
{
get {return this._fields;}
}
[XmlArray()]
[XmlArrayItem(typeof(Method))]
public ArrayList Methods
{
get {return this._methods;}
}
public Object()
{
this._fields=new ArrayList();
this._methods=new ArrayList();
}
}
[Serializable]
public class Field
{
protected string _name;
protected ArrayList _values;
[XmlAttribute()]
public string Name
{
get {return this._name;}
set {this._name=value;}
}
[XmlArray()]
[XmlArrayItem(typeof(Value))]
public ArrayList Values
{
get {return this._values;}
}
public Field()
{
this._values=new ArrayList();
}
}
[Serializable]
public class Value
{
protected string _name;
protected bool _unique;
protected bool _primaryKey;
protected bool _indexed;
[XmlAttribute()]
public string Name
{
get {return this._name;}
set {this._name=value;}
}
[XmlAttribute()]
public bool Unique
{
get {return this._unique;}
set {this._unique=value;}
}
[XmlAttribute()]
public bool PrimaryKey
{
get {return this._primaryKey;}
set {this._primaryKey=value;}
}
[XmlAttribute()]
public bool Indexed
{
get {return this._indexed;}
set {this._indexed=value;}
}
}
[Serializable]
public class Method
{
protected string _name;
protected ArrayList _params;
[XmlAttribute()]
public string Name
{
get {return this._name;}
set {this._name=value;}
}
[XmlArray()]
[XmlArrayItem(typeof(Param))]
public ArrayList Params
{
get {return this._params;}
}
public Method()
{
this._params=new ArrayList();
}
}
可以看到,比较复杂的XML代码的序列化类编码工作量是比较麻烦而且单调的。
那么如何才能将XML生成这样的逆向代码呢?
1、 递归遍历XML Node
2、 登记实体类的名称,类似“public class Method”
3、 登记所有属性的信息,解析属性类型,类似“protected string _name;”
// 检查是否为 boolean
if ((val == "true") || (val == "false"))
{
ptype = "bool";
}
// 检查是否为 int ,如果带小数,则表示为 double
if (Char.IsDigit(val, 0))
{
ptype = "int";
if (val.IndexOf(".") != -1)
{
ptype = "double";
}
}
if ((val == "true") || (val == "false"))
{
ptype = "bool";
}
// 检查是否为 int ,如果带小数,则表示为 double
if (Char.IsDigit(val, 0))
{
ptype = "int";
if (val.IndexOf(".") != -1)
{
ptype = "double";
}
}
4、 登记集合类的名称,用于创建类似“[XmlArrayItem(typeof(Param))]”的代码
5、 输出代码
实现这些步骤的代码:
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Xml;
using System.Windows.Forms;
namespace Infotech.Config.Tools.Xml2Class
{
public sealed class ClassInfo
{
public string name;
public Hashtable properties; //保存属性
public ArrayList collections; //保存集合名
public Hashtable collectionTypes; //保存集合对应类型
public ClassInfo(string name)
{
this.name = name;
properties = new Hashtable();
collections = new ArrayList();
collectionTypes = new Hashtable();
}
}
/// <summary>
/// XML 转 Class
/// </summary>
/// <example>
/// <code escape="true">
/// Example 1:
/// <Database Name="MyDB">
/// <Tables>
/// <Table Name="Person">
/// <Fields>
/// <Field Name="ID" PrimaryKey="true"/>
/// <Field Name="FirstName" Unique="false"/>
/// <Field Name="LastName" Unique="false" Indexed="true"/>
/// </Fields>
/// </Table>
/// </Tables>
/// </Database>
/// Example 2:
/// <ComplexNumber Real="12.34" Imaginary="45.67"/>
/// </code>
/// </example>
public class ClassGenerator
{
protected Hashtable classInfoList;
public ClassGenerator()
{
classInfoList = new Hashtable();
}
public string Generate(string src)
{
classInfoList.Clear();
string dest = "";
XmlDocument doc = new XmlDocument();
try
{
doc.LoadXml(src);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return "";
}
XmlNode root = doc.DocumentElement;
ProcessClass(root);
dest = EmitCode();
return dest;
}
protected void ProcessClass(XmlNode node)
{
string className = node.Name;
ClassInfo ci;
if (classInfoList.Contains(className))
{
ci = (ClassInfo)classInfoList[className];
}
else
{
ci = new ClassInfo(className);
classInfoList[className] = ci;
}
foreach (XmlAttribute attr in node.Attributes)
{
string name = attr.Name;
string val = attr.Value.ToLower();
string ptype = "string";
// 检查属性是否存在
if (!ci.properties.Contains(name))
{
// 检查是否为 boolean
if ((val == "true") || (val == "false"))
{
ptype = "bool";
}
// 检查是否为 int ,如果带小数则表示为 double
if (Char.IsDigit(val, 0))
{
ptype = "int";
if (val.IndexOf(".") != -1)
{
ptype = "double";
}
}
ci.properties[name] = ptype;
}
foreach (XmlNode childNode in node.ChildNodes)
{
if (!ci.collections.Contains(childNode.Name))
{
ci.collections.Add(childNode.Name);
foreach (XmlNode grandchildNode in childNode.ChildNodes)
{
//增加集合类型
if (!ci.collectionTypes.Contains(childNode.Name))
{
ci.collectionTypes[childNode.Name] = grandchildNode.Name;
}
//递归调用
ProcessClass(grandchildNode);
}
}
}
}
}
protected string EmitCode()
{
StringBuilder sb = new StringBuilder();
foreach (DictionaryEntry entry in classInfoList)
{
ClassInfo ci = (ClassInfo)entry.Value;
string cname = ci.name.ToUpper()[0] + ci.name.Substring(1);
sb.Append("//由 xml2Class 工具生成");
sb.Append("[Serializable]\r\n");
sb.Append("public class " + cname + "\r\n");
sb.Append("{\r\n");
//创建属性变量
foreach (DictionaryEntry prop in ci.properties)
{
string pname = (string)prop.Key;
string ptype = (string)prop.Value;
pname = pname.ToLower()[0] + pname.Substring(1);
sb.Append("\tprotected " + ptype + " _" + pname + ";\r\n");
}
//创建集合变量
foreach (string collName in ci.collections)
{
string name = collName.ToLower()[0] + collName.Substring(1);
sb.Append("\tprotected ArrayList _" + name + ";\r\n");
}
//创建属性
foreach (DictionaryEntry prop in ci.properties)
{
string pname = (string)prop.Key;
string ptype = (string)prop.Value;
pname = pname.ToLower()[0] + pname.Substring(1);
string sname = pname.ToUpper()[0] + pname.Substring(1);
sb.Append("\t[XmlAttribute()]\r\n");
sb.Append("\tpublic " + ptype + " " + sname + "\r\n");
sb.Append("\t{\r\n");
sb.Append("\t\tget {return this._" + pname + ";}\r\n");
sb.Append("\t\tset {this._" + pname + "=value;}\r\n");
sb.Append("\t}\r\n");
}
//创建集合
foreach (string collName in ci.collections)
{
string name = collName.ToUpper()[0] + collName.Substring(1);
string collNameSmall = collName.ToLower()[0] + collName.Substring(1);
sb.Append("\t[XmlArray()]\r\n\t[XmlArrayItem(typeof(" + ci.collectionTypes[name] + "))]\r\n");
sb.Append("\tpublic ArrayList " + name + "\r\n");
sb.Append("\t{\r\n");
sb.Append("\t\tget {return this._" + collNameSmall + ";}\r\n");
sb.Append("\t}\r\n");
}
// 创建构造函数,当有子集合才需要
if (ci.collections.Count > 0)
{
sb.Append("\tpublic " + cname + "()\r\n");
sb.Append("\t{\r\n");
foreach (string collName in ci.collections)
{
string name = collName.ToLower()[0] + collName.Substring(1);
sb.Append("\t\tthis._" + name + "=new ArrayList();\r\n");
}
sb.Append("\t}\r\n");
}
sb.Append("}\r\n\r\n");
}
return sb.ToString();
}
}
}
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Xml;
using System.Windows.Forms;
namespace Infotech.Config.Tools.Xml2Class
{
public sealed class ClassInfo
{
public string name;
public Hashtable properties; //保存属性
public ArrayList collections; //保存集合名
public Hashtable collectionTypes; //保存集合对应类型
public ClassInfo(string name)
{
this.name = name;
properties = new Hashtable();
collections = new ArrayList();
collectionTypes = new Hashtable();
}
}
/// <summary>
/// XML 转 Class
/// </summary>
/// <example>
/// <code escape="true">
/// Example 1:
/// <Database Name="MyDB">
/// <Tables>
/// <Table Name="Person">
/// <Fields>
/// <Field Name="ID" PrimaryKey="true"/>
/// <Field Name="FirstName" Unique="false"/>
/// <Field Name="LastName" Unique="false" Indexed="true"/>
/// </Fields>
/// </Table>
/// </Tables>
/// </Database>
/// Example 2:
/// <ComplexNumber Real="12.34" Imaginary="45.67"/>
/// </code>
/// </example>
public class ClassGenerator
{
protected Hashtable classInfoList;
public ClassGenerator()
{
classInfoList = new Hashtable();
}
public string Generate(string src)
{
classInfoList.Clear();
string dest = "";
XmlDocument doc = new XmlDocument();
try
{
doc.LoadXml(src);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return "";
}
XmlNode root = doc.DocumentElement;
ProcessClass(root);
dest = EmitCode();
return dest;
}
protected void ProcessClass(XmlNode node)
{
string className = node.Name;
ClassInfo ci;
if (classInfoList.Contains(className))
{
ci = (ClassInfo)classInfoList[className];
}
else
{
ci = new ClassInfo(className);
classInfoList[className] = ci;
}
foreach (XmlAttribute attr in node.Attributes)
{
string name = attr.Name;
string val = attr.Value.ToLower();
string ptype = "string";
// 检查属性是否存在
if (!ci.properties.Contains(name))
{
// 检查是否为 boolean
if ((val == "true") || (val == "false"))
{
ptype = "bool";
}
// 检查是否为 int ,如果带小数则表示为 double
if (Char.IsDigit(val, 0))
{
ptype = "int";
if (val.IndexOf(".") != -1)
{
ptype = "double";
}
}
ci.properties[name] = ptype;
}
foreach (XmlNode childNode in node.ChildNodes)
{
if (!ci.collections.Contains(childNode.Name))
{
ci.collections.Add(childNode.Name);
foreach (XmlNode grandchildNode in childNode.ChildNodes)
{
//增加集合类型
if (!ci.collectionTypes.Contains(childNode.Name))
{
ci.collectionTypes[childNode.Name] = grandchildNode.Name;
}
//递归调用
ProcessClass(grandchildNode);
}
}
}
}
}
protected string EmitCode()
{
StringBuilder sb = new StringBuilder();
foreach (DictionaryEntry entry in classInfoList)
{
ClassInfo ci = (ClassInfo)entry.Value;
string cname = ci.name.ToUpper()[0] + ci.name.Substring(1);
sb.Append("//由 xml2Class 工具生成");
sb.Append("[Serializable]\r\n");
sb.Append("public class " + cname + "\r\n");
sb.Append("{\r\n");
//创建属性变量
foreach (DictionaryEntry prop in ci.properties)
{
string pname = (string)prop.Key;
string ptype = (string)prop.Value;
pname = pname.ToLower()[0] + pname.Substring(1);
sb.Append("\tprotected " + ptype + " _" + pname + ";\r\n");
}
//创建集合变量
foreach (string collName in ci.collections)
{
string name = collName.ToLower()[0] + collName.Substring(1);
sb.Append("\tprotected ArrayList _" + name + ";\r\n");
}
//创建属性
foreach (DictionaryEntry prop in ci.properties)
{
string pname = (string)prop.Key;
string ptype = (string)prop.Value;
pname = pname.ToLower()[0] + pname.Substring(1);
string sname = pname.ToUpper()[0] + pname.Substring(1);
sb.Append("\t[XmlAttribute()]\r\n");
sb.Append("\tpublic " + ptype + " " + sname + "\r\n");
sb.Append("\t{\r\n");
sb.Append("\t\tget {return this._" + pname + ";}\r\n");
sb.Append("\t\tset {this._" + pname + "=value;}\r\n");
sb.Append("\t}\r\n");
}
//创建集合
foreach (string collName in ci.collections)
{
string name = collName.ToUpper()[0] + collName.Substring(1);
string collNameSmall = collName.ToLower()[0] + collName.Substring(1);
sb.Append("\t[XmlArray()]\r\n\t[XmlArrayItem(typeof(" + ci.collectionTypes[name] + "))]\r\n");
sb.Append("\tpublic ArrayList " + name + "\r\n");
sb.Append("\t{\r\n");
sb.Append("\t\tget {return this._" + collNameSmall + ";}\r\n");
sb.Append("\t}\r\n");
}
// 创建构造函数,当有子集合才需要
if (ci.collections.Count > 0)
{
sb.Append("\tpublic " + cname + "()\r\n");
sb.Append("\t{\r\n");
foreach (string collName in ci.collections)
{
string name = collName.ToLower()[0] + collName.Substring(1);
sb.Append("\t\tthis._" + name + "=new ArrayList();\r\n");
}
sb.Append("\t}\r\n");
}
sb.Append("}\r\n\r\n");
}
return sb.ToString();
}
}
}
有些人喜欢看代码,了解思路;而有些人则喜欢直接使用工具,所以我希望这个工具对大家有所帮助,并提供了代码和执行程序的下载。
下载地址: