很多时候做项目的时候都会需要数据测试,比如做分页时要进行分页测试就必须要有数据用来测试,而数据来源?数据库无疑是一个很好的选择,但这时要创建一个数据库再创建测试用的表,此时你是否会感觉麻烦了点?个人认为是有点麻烦。。。
最近自己无聊也用jQuery做了个分页的控件,测试时就遇到了这个问题:数据来源的问题。本想就用数据库来测试的,但因为怕麻烦就想能不能有其他的比较好的方式来实现,因为类似需要一些数据测试的问题以后仍会遇到,就想着现在找一个好的方法来解决它。就有了编写个符合自己需求的xml系列化的方法。
系列化xml,一开始想到的是.Net Framework里的XmlSerializer,代码如下:
/// <summary>
/// 序列化
/// </summary>
/// <param name="obj">对象</param>
/// <param name="filepath">文件路径</param>
public static bool Save(object obj, string filepath)
{
bool success = false;
FileStream fs = null;
try
{
fs = new FileStream(filepath, FileMode.Create, FileAccess.ReadWrite);
XmlSerializer serializer = new XmlSerializer(obj.GetType());
serializer.Serialize(fs, obj);
success = true;
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (fs != null)
{
fs.Close();
fs.Dispose();
}
}
return success;
}
/// <summary>
/// 反系列化
/// </summary>
/// <param name="type">对象类型</param>
/// <param name="filepath">文件路径</param>
/// <returns></returns>
public static object Load(Type type, string filepath)
{
FileStream fs = null;
try
{
fs = new FileStream(filepath, FileMode.Open, FileAccess.ReadWrite);
XmlSerializer serializer = new XmlSerializer(type);
return serializer.Deserialize(fs);
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (fs != null)
{
fs.Close();
fs.Dispose();
}
}
}
如上,其实挺简单的,可测试才发现这并不能实现自己想要的效果...
所以没办法就自己写了一个简单的方法:
/// <summary>
/// 将object对象系列化成xml
/// </summary>
/// <param name="obj">可系列化的对象</param>
/// <param name="filename">文件路径</param>
public static XmlDocument XmlSerialize(string filename, object obj)
{
FileInfo fileInfo = new FileInfo(filename);
if (!fileInfo.Exists) //不存在文件创建文件
{
CreateFile(filename);
}
XmlDocument xmlDoc = new XmlDocument();
string name = obj.GetType().Name;
xmlDoc.Load(filename);
XmlNode node = xmlDoc.SelectSingleNode("Entity");
CreateSubElement(ref xmlDoc, node, obj, name);
xmlDoc.Save(filename);
return xmlDoc;
}
/// <summary>
/// 创建子元素
/// </summary>
/// <param name="xmlDoc">需要创建子元素的xml文档</param>
/// <param name="obj">要系列化的对象</param>
public static void CreateSubElement(ref XmlDocument xmlDoc, XmlNode node, object obj, string name)
{
XmlElement root = xmlDoc.CreateElement(name); //子元素根
node.AppendChild(root);
foreach (var item in obj.GetType().GetProperties())
{
string value = "Null";
var objValue = item.GetValue(obj, null);
var proName = item.Name;
Type type = item.PropertyType;
bool isClass = IsClass(type); //判断属性类型是否为类
if (isClass)
{
object o = CreateExample(type);
string filename = XmlHelper.GetFileName(type.Name);
FileInfo fileInfo = new FileInfo(filename);
if (!fileInfo.Exists) //不存在引用对象文件,则创建引用对象文件
{
CreateFile(filename);
}
CreateSubElement(ref xmlDoc, root, o, type.Name);
continue;
}
if (objValue != null)
{
value = objValue.ToString();
}
XmlElement element = xmlDoc.CreateElement(proName);
element.SetAttribute("DataType", item.PropertyType.Name); //添加属性类型名称
element.InnerText = value;
root.AppendChild(element);
}
}
/// <summary>
/// 根据TypeCode枚举判读是否为引用对象
/// </summary>
/// <param name="type">判断类型</param>
/// <returns></returns>
public static bool IsClass(Type type)
{
string[] typeCodeNameArray = Enum.GetNames(typeof(TypeCode));
foreach (string item in typeCodeNameArray)
{
if (type.Name == item)
{
return false;
}
}
return true;
}
/// <summary>
/// 创建Xml文件
/// </summary>
/// <param name="filename">文件路径</param>
public static void CreateFile(string filename)
{
FileStream stream = null;
XmlWriter xmlWriter = null;
try
{
stream = new FileStream(filename, FileMode.Create, FileAccess.ReadWrite);
XmlDocument xmlDoc = new XmlDocument();
XmlDeclaration declaration = xmlDoc.CreateXmlDeclaration("1.0", "utf-8", null);
XmlNode rootNode = xmlDoc.CreateNode(XmlNodeType.Element, null, "Entity", null);
rootNode.InnerText = "";
xmlDoc.AppendChild(declaration);
xmlDoc.InsertAfter(rootNode, declaration);
xmlWriter = XmlWriter.Create(stream);
xmlDoc.WriteTo(xmlWriter);
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (xmlWriter != null) xmlWriter.Close();
if (stream != null) stream.Close();
}
}
以下是创建对象实例方法:
/// <summary>
/// 创建对象实例
/// </summary>
/// <param name="type">对象类型</param>
/// <returns></returns>
public static object CreateExample(Type type)
{
object obj = Activator.CreateInstance(type);
return obj;
}
因为要保存N条数据,所以自己定制了一个Xml文件的格式,如下:
<?xml version="1.0" encoding="utf-8"?>
<Entity>
</Entity>
其实思路挺简单的,将要系列化的对象和文件路径传入,判断项目中是否存在以该xml文件,如果不存在则创建,先前说过xml文件格式有个限制(其格式如上),然后根据对象属性名称/值,创建xml元素,相应的判断属性是否为引用对象如果是创建相应的引用对象。
呵呵、这表述能力实在无法恭维。哎。。。至于反系列化就不多说了,直接给代码:
/// <summary>
/// 反系列化xml
/// </summary>
/// <param name="type">可系列化的对象类型</param>
/// <param name="xmlNode">xml中对象对应的节点</param>
/// <returns></returns>
public static object XmlDeserialize(Type type,XmlNode xmlNode)
{
XmlElement xe = (XmlElement)xmlNode;
object parentObj = CreateExample(type);
foreach (var parentItem in parentObj.GetType().GetProperties())
{
var parentSetobj = parentObj.GetType().GetProperty(parentItem.Name);
XmlElement xmlElement = (XmlElement)xe.SelectSingleNode(parentItem.Name);
Type parentType = parentItem.PropertyType;
bool isClass = IsClass(parentType);
if (isClass)
{
object subObj = CreateExample(parentType);
string subName = subObj.GetType().Name;
XmlNode subNode = xe.SelectSingleNode(subName);
foreach (var subItem in subObj.GetType().GetProperties())
{
XmlElement subxl = (XmlElement)subNode;
var subSetobj = subObj.GetType().GetProperty(subItem.Name);
Type proType = subItem.PropertyType;
if (IsClass(proType))
{
subObj = XmlDeserialize(subObj.GetType(), subNode);
continue;
}
object value = Convert.ChangeType(subxl.SelectSingleNode(subItem.Name).InnerText, proType);
subSetobj.SetValue(subObj, value, null);
}
parentSetobj.SetValue(parentObj, subObj, null);
continue;
}
object parentValue = Convert.ChangeType(xmlElement.InnerText, parentType);
parentSetobj.SetValue(parentObj, parentValue, null);
}
return parentObj;
}
系列化和反系列化实现以后,相应的就是对系列化后的文件进行增、删、改、查操作了,这些在整理,以后再上源码。
以下是系列化后文件:
<?xml version="1.0" encoding="utf-8"?>
<Entity>
<Student>
<StudentNo DataType="String">001</StudentNo>
<Name DataType="String">MrChen</Name>
<Sex DataType="String">男</Sex>
<BirthDay DataType="DateTime">1989-5-14 22:05:01</BirthDay>
<Course>
<CourseNo DataType="String">Null</CourseNo>
<CourseName DataType="String">Null</CourseName>
<Id DataType="String">ab0a7aa2-4295-4fe6-910c-1e61c47a942c</Id>
<CreateTime DataType="DateTime">2011-5-14 22:05:01</CreateTime>
<IsDelete DataType="Boolean">False</IsDelete>
<Version DataType="DateTime">2011-5-14 22:05:01</Version>
</Course>
<Id DataType="String">295afde9-b5ce-465c-b267-ae948cce3ec7</Id>
<CreateTime DataType="DateTime">2011-5-14 22:05:01</CreateTime>
<IsDelete DataType="Boolean">False</IsDelete>
<Version DataType="DateTime">2011-5-14 22:05:01</Version>
</Student>
<Student>
<StudentNo DataType="String">002</StudentNo>
<Name DataType="String">MrChen</Name>
<Sex DataType="String">男</Sex>
<BirthDay DataType="DateTime">1989-5-14 22:05:43</BirthDay>
<Course>
<CourseNo DataType="String">Null</CourseNo>
<CourseName DataType="String">Null</CourseName>
<Id DataType="String">fb674255-0af9-4863-b2dc-b29b112b4ad5</Id>
<CreateTime DataType="DateTime">2011-5-14 22:05:43</CreateTime>
<IsDelete DataType="Boolean">False</IsDelete>
<Version DataType="DateTime">2011-5-14 22:05:43</Version>
</Course>
<Id DataType="String">8ccafe8c-5d7b-4e1d-9721-c8393e392929</Id>
<CreateTime DataType="DateTime">2011-5-14 22:05:43</CreateTime>
<IsDelete DataType="Boolean">False</IsDelete>
<Version DataType="DateTime">2011-5-14 22:05:43</Version>
</Student>
</Entity>
而反系列化后就是一个对象了。