XML 2 Class [xml 转化为 序列化代码工具]


    我经常要编写一些可序列化的类,用于存储配置,通过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;}
 }

}

一个带集合的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>

它对应的序列化代码为:

[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();
 }

}

可以看到,比较复杂的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";
    }

}


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();
        }

    }

}


有些人喜欢看代码,了解思路;而有些人则喜欢直接使用工具,所以我希望这个工具对大家有所帮助,并提供了代码和执行程序的下载。

下载地址:

/Files/Chinasf/Xml2Class.rar

随飞 2006年6月10日星期六

posted @ 2006-06-10 10:04  suifei  阅读(3101)  评论(4编辑  收藏  举报