一、前言
紧跟着上一篇随笔,本文主要涉及到如何将xml与xsl动态转换成html,这个才是最关键的地方,所有的内容都是围绕这个主题来进行开展的。根据指定的xsl样式将List<T>转换相应的Html,相关的随笔如下:
(一)、将List<T>转换成DataTable。
(二)、将Xml与Xsl动态转换成Html。
(三)、设置以及控制Xsl的内容样式。
二、XslTransform的具体实现
XslTransform主要的职责为:将xml与xsl动态转换成html。其中,XslCompiledTransform 提供了很多方法可以进行相关的转换,但使用起来并不是十分方便,因此必须在该基础上来对目前的类进行相关封装以及提取。具体的代码如下:
1
public
class
XslTransform : IDisposable
2
{
3
public
StringWriter StringWriter
4
{
5
get
;
6
private
set
;
7
}
8
9
public
StringReader XmlStringReader
10
{
11
get
;
12
private
set
;
13
}
14
15
public
StringReader XslStringReader
16
{
17
get
;
18
private
set
;
19
}
20
21
public
XslTransform()
22
{
23
this
.StringWriter
=
new
StringWriter();
24
}
25
26
public
string
Transfer(
string
xmlText,
string
xslText)
27
{
28
if
(
string
.IsNullOrWhiteSpace(xmlText)
29
||
string
.IsNullOrWhiteSpace(xslText))
30
{
31
return
string
.Empty;
32
}
33
this
.XmlStringReader
=
new
StringReader(xmlText);
34
this
.XslStringReader
=
new
StringReader(xslText);
35
36
return
TransferXmlAndXslToHtml();
37
}
38
39
private
string
TransferXmlAndXslToHtml()
40
{
41
try
42
{
43
using
(XmlTextWriter writer
=
new
XmlTextWriter(
this
.StringWriter))
44
{
45
return
ToHtml(writer);
46
}
47
}
48
catch
49
{
50
return
string
.Empty;
51
}
52
}
53
54
private
string
ToHtml(XmlTextWriter writer)
55
{
56
XslCompiledTransform xslTransform
=
new
XslCompiledTransform();
57
xslTransform.Load(XmlReader.Create(
this
.XslStringReader));
58
xslTransform.Transform(XmlReader.Create(
this
.XmlStringReader), writer);
59
60
return
this
.StringWriter.ToString();
61
}
62
63
#region
IDisposable 成员
64
65
public
void
Dispose()
66
{
67
this
.Dispose(
true
);
68
GC.SuppressFinalize(
this
);
69
}
70
71
private
void
Dispose(
bool
disposing)
72
{
73
if
(
this
.StringWriter
!=
null
)
74
{
75
this
.StringWriter.Dispose();
76
}
77
if
(
this
.XslStringReader
!=
null
)
78
{
79
this
.XslStringReader.Dispose();
80
}
81
if
(
this
.XmlStringReader
!=
null
)
82
{
83
this
.XmlStringReader.Dispose();
84
}
85
}
86
87
#endregion
88
}
XslTransform 类主要的方法为54-61行的代码,如下所示:
54 private string ToHtml(XmlTextWriter writer)
55 {
56 XslCompiledTransform xslTransform = new XslCompiledTransform();
57 xslTransform.Load(XmlReader.Create(this.XslStringReader));
58 xslTransform.Transform(XmlReader.Create(this.XmlStringReader), writer);
59
60 return this.StringWriter.ToString();
61 }
第57行加载XSL的样式文本,58行在原有基础上将XML转换成XmlTextWriter对象。其中XmlTextWriter在初始化时,StringWriter对象作为参数传递进去,如以下的43行代码:
43 using (XmlTextWriter writer = new XmlTextWriter(this.StringWriter))
因此直接返回this.StringWriter.ToString();就获取到了我们所需的Html了。
其次,XslTransform 类还有一个注意的要点:实现IDisposable接口主要是将用到的资源及时释放掉,避免造成其他影响。
三、Xsl文件的设置以及添加到资源文件中
(1)创建MapperInfoXslContent.xslt样式文件,内容如下(目前使用最简单的,不做任何处理的样式文件):
<?
xml version
=
"
1.0
"
encoding
=
"
utf-8
"
?>
<
xsl:stylesheet version
=
"
1.0
"
xmlns:xsl
=
"
http://www.w3.org/1999/XSL/Transform
"
>
<
xsl:template match
=
"
/
"
>
<
html
>
<
head
>
<
title
>
demo
</
title
>
</
head
>
<
body
>
<
table
>
<
tr
>
<
td
>
<
table border
=
"
1px
"
bordercolor
=
"
#000000
"
cellspacing
=
"
0px
"
style
=
"
border-collapse:collapse
"
>
<
tr bgcolor
=
"
#9acd32
"
>
<
th width
=
"
80
"
>
Name
</
th
>
<
th width
=
"
80
"
>
Value
</
th
>
<
th width
=
"
80
"
>
Percent
</
th
>
<
th width
=
"
230
"
>
CreatedTime
</
th
>
<
th width
=
"
60
"
>
IsActive
</
th
>
<
th width
=
"
190
"
>
TargerUrl
</
th
>
</
tr
>
<
xsl:
for
-
each select
=
"
DataSet/MapperInfo
"
>
<
tr
>
<
td bgcolor
=
"
#ff00ff
"
width
=
"
80
"
>
<
xsl:value
-
of select
=
"
Name
"
/>
</
td
>
<
td width
=
"
80
"
>
<
xsl:value
-
of select
=
"
Value
"
/>
</
td
>
<
td bgcolor
=
"
#ff00ff
"
width
=
"
80
"
>
<
xsl:value
-
of select
=
"
Percent
"
/>
</
td
>
<
td width
=
"
230
"
>
<
xsl:value
-
of select
=
"
CreatedTime
"
/>
</
td
>
<
td bgcolor
=
"
#ff00ff
"
width
=
"
60
"
>
<
xsl:value
-
of select
=
"
IsActive
"
/>
</
td
>
<
td width
=
"
190
"
>
<
xsl:value
-
of select
=
"
TargetUrl
"
/>
</
td
>
</
tr
>
</
xsl:
for
-
each
>
</
table
>
</
td
>
</
tr
>
</
table
>
</
body
>
</
html
>
</
xsl:template
>
</
xsl:stylesheet
>
(2)然后再创建XslResource.resx资源文件,将MapperInfoXslContent.xslt样式文件添加到XslResource.resx资源文件中,如下图所示:
四、转换后的效果
经过转换后得到的Html显示效果如下(测试过程中可以以HTML格式来查看字符串):
五、相关的单元测试
示例的单元测试代码如下(仅做了一些最基础的测试,验证内容是否存在):
[TestMethod()]
public
void
TransferTest()
{
string
xmlText
=
GetXmlText();
string
xslText
=
XslResource.MapperInfoXslContent;
string
htmlContent
=
string
.Empty;
using
(XslTransform xslTransform
=
new
XslTransform())
{
htmlContent
=
xslTransform.Transfer(xmlText, xslText);
}
Assert.IsTrue(
!
string
.IsNullOrWhiteSpace(htmlContent));
Assert.IsTrue(htmlContent.Contains(
"
true
"
));
Assert.IsTrue(htmlContent.Contains(
"
false
"
));
for
(
int
index
=
0
; index
<
3
; index
++
)
{
Assert.IsTrue(htmlContent.Contains(
string
.Concat(
"
MapperInfoIndex
"
, index.ToString())));
Assert.IsTrue(htmlContent.Contains(
string
.Format(
@"
www.codeplex.com?Id={0}
"
, index)));
Assert.IsTrue(htmlContent.Contains(index.ToString()));
}
}
private
string
GetXmlText()
{
List
<
MapperInfo
>
entities
=
CreateMapperInfos(
3
);
DataTable dataTable
=
EntityMapper.ToDataTable
<
MapperInfo
>
(entities);
DataSet dataSet
=
new
DataSet(
"
DataSet
"
);
dataSet.Tables.Add(dataTable);
return
dataSet.GetXml();
}
private
List
<
MapperInfo
>
CreateMapperInfos(
int
count)
{
List
<
MapperInfo
>
entities
=
new
List
<
MapperInfo
>
();
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,
Percent
=
GetPercent(index),
TargetUrl
=
string
.Format(
@"
www.codeplex.com?Id={0}
"
, index)
});
}
return
entities;
}
private
decimal
?
GetPercent(
int
index)
{
if
(index
%
2
==
0
)
{
return
index;
}
return
null
;
}
六、总结
上面涉及的仅仅是其中的一种,代码应该是比较精简的。还有另外一种采用XPathNavigator的,也就是笛子说的:“如果使用 XmlWriter 或 XmlDocument,则可以避开这个问题。另外,XslCompiledTransform.Transform 方法重载了几个版本中,如果我没记错的话,最应优先使用的是xml数据源为 XPathNavigator 的版本。”。关于这种情况,可以通过XmlDocument来创建相关的XPathNavigator对象,即:XPathNavigator navigator = XmlDocument.DocumentElement.CreateNavigator(),这种版本的我也重写了一份,但是好像没有转换成功,因此就采用这种模式了。下一篇主要涉及到XSL样式的设计以及相关的函数、模板的应用。