[转载]如何将List转换相应的Html(xsl动态转换)(一)

[转载]如何将List转换相应的Html(xsl动态转换)(一) – JasenKin – 博客园.

一、前言

根据指定的xsl样式将List<T>转换相应的Html,其中涉及到怎样将List<T>转换成DataTable,如何将xml文本、xsl样式文本动态转换成html以及如何设置以及控制xsl样式。主要步骤如下:

步骤一、将List<T>转换成DataTable。

步骤二、将Xml与Xsl动态转换成Html。

步骤三、设置以及控制Xsl的内容样式。

以上的三个步骤本人将以此顺序介绍相关的内容,分别对应相关的随笔,因为本人上班的时候不能上网以及时间上的问题,所以才将该文章分3次来写。

二、类图设计

以上的内容涉及的类图虽然很简单,但是本人还是花了不少时间的来实现具体功能,代码质量还是可以保证的。EntityMapper负责将 List<T>转换成DataTable(目前先将就着用这个,还有一个比较复杂的,涉及的东西比较多,此处不会讲解,以后有时间再 写),XslTransform负责将xml文本、xsl文本转换成html,XslTransformFacade外观模式封装其中的细节,如下:

三、将List<T>转换成DataTable,再转换成xml的具体实现

这里主要是个思路的问题,先将List<T>转换成DataTable,然后将DataTable添加到DataSet中,最后通过 DataSet的GetXml()方法获取Xml内容。这里思路正确的话,实现不是很复杂。先看下XslTransformFacade类,基本思路都封 装在该类中:

public class XslTransformFacade
{
public static string ToHtml(List entities,string xslText) where T : new()
{
if (ValidateArgs(entities,xslText))
{
return string.Empty;
}

string xmlText= GetXmlText(entities);

using (XslTransform xslTransform = new XslTransform())
{
return xslTransform.Transfer(xmlText, xslText);
}
}

private static bool ValidateArgs(List entities, string xslText)
{
return entities == null || entities.Count == 0
|| string.IsNullOrWhiteSpace(xslText);
}

private static string GetXmlText(List entities) where T : new()
{
using (DataSet dataSet = new DataSet("DataSet"))
{
DataTable dataTable = EntityMapper.ToDataTable(entities);
dataSet.Tables.Add(dataTable);
return dataSet.GetXml();
}
}
}

这一步骤主要是通过GetXmlText(List entities)方法来实现的。EntityMapper.ToDataTable(entities)方法将在下面介绍。生成的Xml如下(示例):

-
-
MapperInfoIndex0
2011-05-24T00:27:23.734375+08:00
true
0

0   www.codeplex.com?Id=0

-
MapperInfoIndex1
2011-05-24T00:27:23.734375+08:00
false
1
www.codeplex.com?Id=1

-

其次第12-15行主要是将xmlText、xslText转换成html,这将在后续的文章中介绍具体实现:

using (XslTransform xslTransform = new XslTransform())
{
return xslTransform.Transfer(xmlText, xslText);
}

四、将List<T>转换成DataTable

这里主要是通过反射将List<T>转换成DataTable。其中需要设置DataTable的DataColumnCollection集合以及设置DataRowCollection集合。具体代码如下:

public sealed class EntityMapper
{
public static DataTable ToDataTable(List entities) where T : new()
{
if (entities == null || entities.Count == 0)
{
return new DataTable();
}

using (DataTable dataTable = new DataTable(typeof(T).Name))
{
PropertyInfo[] properties = typeof(T).GetProperties();

SetColumnsType(properties, dataTable);
SetTableContent(entities, properties, dataTable);

return dataTable;
}
}

private static void SetTableContent(List entities,
PropertyInfo[] properties, DataTable dataTable)
{
foreach (T entity in entities)
{
AddTableRowsAndContent(properties, entity,dataTable);
}
}

private static void AddTableRowsAndContent(PropertyInfo[] properties,
T entity, DataTable dataTable)
{
DataRow newRow = dataTable.NewRow();
foreach (PropertyInfo propertyInfo in properties)
{
if (!CanGetPropertyValue(propertyInfo,dataTable))
{
continue;
}

try
{
object objValue = propertyInfo.GetValue(entity, null);
newRow[propertyInfo.Name] = objValue ?? DBNull.Value;
}
finally
{
}
}

dataTable.Rows.Add(newRow);
}

private static bool CanGetPropertyValue(PropertyInfo propertyInfo, DataTable dataTable)
{
return propertyInfo.CanRead &amp;&amp;
dataTable.Columns.Contains(propertyInfo.Name);
}

private static void SetColumnsType(PropertyInfo[] properties, DataTable dataTable)
{
Type colType = null;

foreach (PropertyInfo propInfo in properties)
{
if (propInfo.PropertyType.IsGenericType)
{
colType = Nullable.GetUnderlyingType(propInfo.PropertyType);
}
else
{
colType = propInfo.PropertyType;
}

if (colType.FullName.StartsWith("System"))
{
dataTable.Columns.Add(propInfo.Name, colType);
}
}
}
}

这里主要的操作步骤为以下2行代码:

14 SetColumnsType(properties, dataTable);
15 SetTableContent(entities, properties, dataTable);

14行设置列的类型,15行设置DataRowCollection的DataRow内容,对于上面的代码,再多的解释都是无用的,看具体代码就行了。

其中需要解释一下的就是54-58行:

54 private static bool CanGetPropertyValue(PropertyInfo propertyInfo, DataTable dataTable)
55 {
56 return propertyInfo.CanRead &&
57 dataTable.Columns.Contains(propertyInfo.Name);
58 }
因为当属性不可读,并且DataColumnCollection不包行该属性名时,赋值可能会抛出异常的。

其次还提一下第10行:

10 using (DataTable dataTable = new DataTable(typeof(T).Name))

这里用using来释放资源,主要是使代码中不存在任何警告,警告有时候使系统奔溃也有可能。否则进行代码分析的时候会出现警告信息,如下图所示:

五、DataTable 转换成List<T> (这个是附加的,与此主题无关,但是也是EntityMapper 的一部分)

虽然以前写了一篇《 将DataRow转换成相应的对象(通用以及泛型操作) 》 ,但是并不是将DataTable 转换成List<T>,后续也有些地方进行了改进,代码如下:

public class EntityMapperTest
{
[TestMethod()]
public void ToDataTableTest()
{
List entities = CreateMapperInfos(9);
DataTable result = EntityMapper.ToDataTable(entities);
Assert.IsNotNull(result);
Assert.IsNotNull(result.Rows);
Assert.AreEqual(9, result.Rows.Count);
int index = 0;
foreach (DataRow dataRow in result.Rows)
{
Assert.AreEqual(dataRow[“Name”],
string.Concat(“MapperInfoIndex”, index.ToString()));
Assert.AreEqual(dataRow[“IsActive”], index % 2 == 0 ? true : false);
Assert.AreEqual(dataRow[“Value”], index);
Assert.IsNotNull(dataRow[“CreatedTime”]);
Assert.AreEqual(dataRow[“Percent”], DBNull.Value);
index++;

}
}

private List CreateMapperInfos(int count)
{
List entities = new List();
for (int index = 0; index < count; index++) { entities.Add(new MapperInfo() { Name = string.Concat("MapperInfoIndex", index.ToString()), IsActive = (index % 2 == 0 ? true : false), CreatedTime = DateTime.Now, Value = index }); } return entities; } } [/csharp] 七、总结 最近二个多月,忙死我了。这段时间转SIT测试了,终于又可以轻松一阵了,哈哈。这些随笔的内容都是上班时间之外写的,每次写的代码都做单元测试,主要是避免出现显而易见的BUG,以及将代码积累并且更新到自己的框架中。接下来的一篇主要是如何将xml文本、xsl文本动态转换成html,这个花费了本人一段时间,一直在摸索才整理出来的,主要是通过XslCompiledTransform.Transform(XmlReader input, XmlWriter results)来实现的,本人已经更新了几个版本了,这个应该是最终版本的,同时也是最精简的版本。

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏