XML是一种很方便的描述数据的方法,其格式也比较接近HTML,因此就有了想把XML直接通过网页的形式显示在浏览器中的想法。但是直接打开XML文件,浏览器是无法解析的,只是把文档的结构原封不动地呈现出来而已。例如,我们有一个学生课程表的文档schedule.xml,用浏览器直接打开是这个样子的。(不过不知道为什么只能在IE中打开,在chrome中打开后无法显示,求教)
那么如何将XML文档能够以比较容易看懂的方式显示在网页上呢?通过查找资料以后得知有一种XML文档叫做XSLT(EXtensible Stylesheet Language Transform,可扩展样式表语言转换)。详见http://www.w3school.com.cn/xsl/index.asp。
接着就是要选择我们比较容易看懂的形式了。由于是课程表,我们当然首选采用表格的形式展现。但是在确定展现的具体手段时却遇到了瓶颈。究竟是采用课程驱动、还是时间驱动的形式?经过反复试验和调试,终于确定以时间为驱动,采用逐单元格填充的方式进行转换。最终生成的XSLT代码如下(部分):
-
<?xml version="1.0" encoding="gb2312"?>
-
-
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
-
-
<xsl:template match="/">
-
<html>
-
<body>
-
<h2>我的课程表</h2>
-
<table border="1">
-
<tr bgcolor="#9acd32">
-
<th></th>
-
<th align="center">1</th>
-
<th align="center">2</th>
-
<th align="center">3</th>
-
<th align="center">4</th>
-
<th align="center">5</th>
-
<th align="center">6</th>
-
<th align="center">7</th>
-
<th align="center">8</th>
-
<th align="center">9</th>
-
<th align="center">10</th>
-
<th align="center">11</th>
-
</tr>
-
<tr>
-
<td>周一</td>
-
<xsl:for-each select="schedule/day">
-
<xsl:if test="week = '周一'">
-
<td>
-
<xsl:for-each select="course">
-
<xsl:choose>
-
<xsl:when test="time = 1">
-
<xsl:value-of select="name"></xsl:value-of>
-
</xsl:when>
-
<xsl:otherwise>
-
-
</xsl:otherwise>
-
</xsl:choose>
-
</xsl:for-each>
-
</td>
-
...
-
</xsl:if>
-
</xsl:for-each>
-
</tr>
-
....
-
</table>
-
</body>
-
</html>
-
</xsl:template>
-
-
</xsl:stylesheet>
接下来就是要将XML和XSLT结合起来了。
XML输出有两种方式,一种是流的形式,另一种是文件的形式。采用流的方式其实并不适用,因为文档流默认是填充在一个文件的前面的,如果是采用HTML或者ASPX等文件,会影响整个文档的结构。因此采用文件的方法,即将所有XML节点写入一个文件,并保存在服务器上。当然,随着用户数量的增多,生成的XML文件必然会越来越多,所以还得增加一个定期删除的机制,这个不在我们讨论范围之内因此不再赘述。
之前从数据库中读出数据并写入一个List的方法如下:
-
using System;
-
using System.Collections.Generic;
-
using System.Linq;
-
using System.Web;
-
using System.Configuration;
-
using System.Xml;
-
using System.Web.UI;
-
using System.Web.UI.WebControls;
-
-
namespace CampusSystem
-
{
-
public enum Weekday { 周一, 周二, 周三, 周四, 周五 };
-
-
public struct CourseToXML
-
{
-
public string course_id;
-
public string name;
-
public Weekday week;
-
public string[] times;
-
}
-
-
public static class ScheduleMaker
-
{
-
static string connString = ConfigurationManager.ConnectionStrings["CampusConnectionString"].ConnectionString;
-
static CampusDBDataContext db = new CampusDBDataContext(connString);
-
-
public static List<CourseToXML> MakeScheduleList(string uid)
-
{
-
string course_id = string.Empty;
-
string name = string.Empty;
-
string allTime = string.Empty;
-
-
CourseToXML ctx = new CourseToXML();
-
List<CourseToXML> ctxl = new List<CourseToXML>();
-
-
var mySchedule = from ms in db.Schedule where ms.student_id == uid select ms.course_id;
-
foreach (string cid in mySchedule)
-
{
-
var courseInfo = from ci in db.Course where ci.course_id == cid select new { ci.course_id, ci.name, ci.time };
-
foreach (var c in courseInfo)
-
{
-
course_id = c.course_id;
-
name = c.name;
-
allTime = c.time;
-
string[] oneTimes = allTime.Split(';');
-
foreach (string oneTime in oneTimes)
-
{
-
string[] weekAndTime = oneTime.Split(',');
-
string week = weekAndTime[0];
-
string[] times = weekAndTime[1].Split('.');
-
-
ctx.course_id = course_id;
-
ctx.name = name;
-
-
ctx.times = times;
-
switch (week)
-
{
-
case "周一":
-
ctx.week = Weekday.周一;
-
break;
-
case "周二":
-
ctx.week = Weekday.周二;
-
break;
-
case "周三":
-
ctx.week = Weekday.周三;
-
break;
-
case "周四":
-
ctx.week = Weekday.周四;
-
break;
-
case "周五":
-
ctx.week = Weekday.周五;
-
break;
-
default:
-
break;
-
}
-
-
ctxl.Add(ctx);
-
}
-
}
-
}
-
ctxl.Sort((CourseToXML ctxA, CourseToXML ctxB) =>
-
{
-
if (ctxA.week == ctxB.week)
-
return ctxA.times[0].CompareTo(ctxB.times[0]);
-
else
-
return ctxA.week.CompareTo(ctxB.week);
-
});
-
-
return ctxl;
-
-
}
-
}
-
}
需要查询的页面schedule.aspx如下:(前提是需要有一个存放生成后的html文档的html文件。)
-
using System;
-
using System.Collections.Generic;
-
using System.Linq;
-
using System.Web;
-
using System.Web.UI;
-
using System.Web.UI.WebControls;
-
using System.Xml;
-
using System.Xml.Xsl;
-
-
namespace CampusSystem
-
{
-
public partial class schedule : System.Web.UI.Page
-
{
-
string uid;
-
-
protected void Page_Load(object sender, EventArgs e)
-
{
-
uid = GetUID();
-
List<CourseToXML> list = ScheduleMaker.MakeScheduleList(uid); //读出数据库中数据
-
MakeScheduleXML(list, uid); //生成XML文档
-
-
XslCompiledTransform xslt = new XslCompiledTransform();
-
xslt.Load(Server.MapPath("schedule.xsl"));
-
xslt.Transform(Server.MapPath("Schedule/schedule_" + uid + ".xml"), Server.MapPath("schedule.html"));
-
//这个方法就是将指定的XML文件通过指定的XSL文件转换以后生成到一个指定的html文件中。
-
-
Response.Redirect("schedule.html");
-
}
-
-
private string GetUID()
-
{
-
string uid = string.Empty;
-
HttpCookie cookie = Request.Cookies["LOGIN"];
-
if (cookie != null) // 若Cookie不为空,则采用cookie
-
{
-
uid = cookie["uid"];
-
}
-
else // 否则采用Session
-
{
-
uid = (string)Session["uid"];
-
}
-
return uid;
-
}
-
-
protected void MakeScheduleXML(List<CourseToXML> list, string uid)
-
{
-
XmlDocument xmlDoc = new XmlDocument();
-
XmlDeclaration decl = xmlDoc.CreateXmlDeclaration("1.0", "utf-8", null);
-
xmlDoc.AppendChild(decl);
-
-
XmlElement root = xmlDoc.CreateElement("schedule");
-
xmlDoc.AppendChild(root);
-
-
-
for (int weekday = 0; weekday < 5; weekday++)
-
{
-
XmlNode nodeDay = xmlDoc.CreateElement("day");
-
root.AppendChild(nodeDay);
-
XmlNode week = null;
-
switch (weekday)
-
{
-
case 0:
-
week = xmlDoc.CreateElement("week");
-
week.InnerText = Weekday.周一.ToString();
-
break;
-
case 1:
-
week = xmlDoc.CreateElement("week");
-
week.InnerText = Weekday.周二.ToString();
-
break;
-
case 2:
-
week = xmlDoc.CreateElement("week");
-
week.InnerText = Weekday.周三.ToString();
-
break;
-
case 3:
-
week = xmlDoc.CreateElement("week");
-
week.InnerText = Weekday.周四.ToString();
-
break;
-
case 4:
-
week = xmlDoc.CreateElement("week");
-
week.InnerText = Weekday.周五.ToString();
-
break;
-
default:
-
break;
-
}
-
nodeDay.AppendChild(week);
-
-
foreach (CourseToXML ctx in list)
-
{
-
XmlNode course = null;
-
if (weekday == (int)(ctx.week))
-
{
-
course = xmlDoc.CreateElement("course");
-
foreach (string t in ctx.times)
-
{
-
XmlNode time = xmlDoc.CreateElement("time");
-
time.InnerText = t;
-
course.AppendChild(time);
-
}
-
XmlNode name = xmlDoc.CreateElement("name");
-
name.InnerText = ctx.name;
-
course.AppendChild(name);
-
nodeDay.AppendChild(course);
-
}
-
-
}
-
}
-
-
xmlDoc.Save(Server.MapPath("Schedule/schedule_" + uid + ".xml"));
-
}
-
}
-
}
运行以后自动返回所生成的html文档,就能看到结果了。
虽然还略显简陋就是了,当然,这个可以通过css来控制,这里也不再赘述。
总结
为了完成这个任务,采取了一切能想到的方法。包括XMLDocument,XSLT转换,LINQ,泛型,Lambda表达式,还有XML本身的设计等等,很多知识的大综合。也是对自己学习能力和综合应用能力一个提高。真正的成就感就是在这样不断解决问题的过程中产生的,也是给了我继续把项目做好的动力。