如何把xml文件转换成vml图形
如何把xml文件转换成vml图形
摘要:在很多情况下,我们需要把数据转换成图表的形式来显示。一直有个想法儿就是数据用xml来表示,这个xml文件可以用asp或者asp.net在服务器端提取数据库并拼接而成。然后写个通用的xslt文件把这些xml文件转换成柱形,饼形,曲线形等图形报表。因为这里面涉及好多xslt和css高级的东西,比如说xslt的递归处理,和css的表达式等,所以做这个东西的时候很费力,而且到最后还有一些遗憾的地方。本示例没有用xslt和javascript交互的地方,下次改进的时候如果能利用好javascript的灵活性和面向对象特性的话,以及xslt的一些高级的内容的话,我想这次遗留下的问题应该会解决的,也许我们还可以不把它们进一步封装成自定义服务器控件,以达到重用的效果。
首先要说的是,利用VML做图表,我肯定不是第一个,james用js写的vmlchart组件,还有网上流行的三个用asp输出的特漂亮的图表,这些例子都很好,不过我用的时候感觉灵活性还是不太好,于是我才想好好研究研究。因为用vml做图表有很多的优势,以前我和群里的朋友讨论过这个问题。下面是我当时的一些随笔。
报表里一般都有生成自定义图表的功能,OWC是不错的选择,微软提供的免费组件,可是如果用在WEB上性能是个问题,如果访问量大的话,每个访问都会实例化一次OWC对象,非常消耗资源,如果用居网内的信息系统还可以考虑,其它ACTIVEX图表组件应该也有这个缺陷吧,我想一个可行的办法就是调用客户端的OWC来生成图表,然后利用远程XML或者WEB服务来作为数据源,可是这样如果是WEB系统的话,OWC的分发部署还是个问题,有些人的浏览器默认禁止下载ACTIVEX,对于一个有广大访问者的网站,强制用户下载某个组件我感觉不是很好吧。水晶报表的性能据说已经优化非常好了,能经得住很高的访问流量,sqlserver reporting serivice是一套web serivice,可以跨平台,我看过微软的培训录像,功能也很强大,能生成各种格式,但是还得建立专门的报表服务器,也很麻烦,如果有一套vml或者svg的图表类库就好了,可以在客户端显示丰富的图表,而不用下载插件,也不用损耗服务器性能,不行去国外的开源网站逛逛,看看有没有好看的,现成的,功能强大的VML chart,呵呵。
先来看我们准备的原始xml文件,是一个投票系统的元数据,因为民意调查一般都是用柱形图显示的,所以就用这个来做示例,而且引起我对VML感兴趣的原因之一也是我想用VML做一个显示调查结果的念头。
vote.xml
<?xml-stylesheet type="text/xsl" href="Vmlchart.xslt"?>
<votelist>
<vote type="rect" desc="你喜欢哪个语言?">
<item name="asp.net" color="red">100</item>
<item name="c#" color="aqua">20</item>
<item name="asp" color="blue">60</item>
<item name="vb.net" color="gray">25</item>
<item name="delphi" color="green">72</item>
<item name="java" color="lime">62</item>
<item name="python" color="maroon">29</item>
<item name="c++" color="navy">55</item>
<item name="php" color="olive">18</item>
</vote>
</votelist>
然后我们来看样式表,这个样式表是我昨天下午早就写好了的,经过一上午的研究,基本上没有做什么改进,哎。本来呢,我想让它转换出来的图形更加专业一些,我想给图形加上X坐标和Y坐标,再在每个图形的上面显示它们各自代表的条目,以及占总投票数的百分比之类的信息,可惜我让它显示条目名称的时候整个图表的宽度加大了,而且每个柱形的间距也加大了,我当时是用的vml的textbox和css的绝对定位来做的条目名称显示。如果把position设置成absolute 所有的名称都会重叠在一起,如果设置成relative,柱形图的间距就会加大,因为每个柱形之间加了textbox的位置,随意被撑开了,然后呢我想设置成absolute,然后根据循环的次数来让textbox的left属性每次加50象素,让它正好位于自己条形图的上方。可是弄了一上午,用xsl:param,xsl:with-param,xsl:variable弄了好半天也没弄出来,xsl:variable一经声明值就不能变了,随意不能在循环的时候更新它的值,而xsl:param只能在xsl:call-template里面修改它的值,而且xsl:call-template里用xsl:with-param修改param的值的时候还得必须应用xsl:param声明的模板,否则param的作用域打不到那里,所以只能用递归来模拟这种循环增加值的效果,这就需要一个全局变量来控制xsl:if的条件,在解析完item元素后停止让left+50,可是这个全局变量的值怎么也变不了,我弄了好几次,都提示递归太深,造成解析死循环,我晕的,想不到这XSLT简直不是一般的复杂,不知道以后的XAML会复杂到何等程度,我快疯了,就带着遗憾先把这个效果做完吧。
VmlChart.xslt
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:v="urn:schemas-microsoft-com:vml">
<xsl:template match="/">
<HTML>
<HEAD>
<STYLE>v\:*{behavior:url(#default#VML);}</STYLE>
<TITLE>蛙蛙池塘图表</TITLE>
</HEAD>
<BODY>
<xsl:apply-templates select="votelist" />
</BODY>
</HTML>
</xsl:template>
<xsl:template match="votelist" name="votelist">
<xsl:for-each select="vote">
<div style="POSITION:absolute ;Z-INDEX:3;LEFT:110px;TOP:10px;font-size:14px;">
<b>调查:
<xsl:value-of select="@desc"/>
</b>
</div>
<xsl:for-each select="item">
<v:rect style="POSITION:relative ;Z-INDEX:3;LEFT:100px;TOP:25px;width:20;height:{.};" fillcolor="{@color}"
stroked="f">
</v:rect>
</xsl:for-each>
<table style="POSITION:absolute ;Z-INDEX:3;LEFT:110px;TOP:145px;border:1px solid #f1f1f1;font-size:12px;">
<xsl:for-each select="item">
<tr>
<td>
<v:rect style="Z-INDEX:3;width:15;height:15;" fillcolor="{@color}"
stroked="f">
</v:rect>
<xsl:value-of select="."/>
</td>
<td>
<xsl:value-of select="@name"/>
</td>
</tr>
</xsl:for-each>
</table>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
到现在我们打开第一步建立的vote.xml就可以看到,它已经成功的转换成了图形,是不是有些效果了呀,呵呵。其实还可以用css滤境让条形图做一些渐变色,透明处理等效果,让它更好看,我在下载的代码里提供了几个静态的vml图表,大家可以预览一下这个效果。文件名叫vmlchart.htm。单纯浏览xml文件,它会只显示个图表,而往往图表应该穿插在一段文字之间,我们一般在html文件中想要呈现图表的地方让它显示,下面我们做了一个html文件,来演示这个过程。
Chart.htm
<HEAD>
<STYLE>v\:*{behavior:url(#default#VML);}</STYLE>
<SCRIPT language="jscript">
var objSrcTree, ObjXSLT, objCache;
function init()
{
objSrcTree = new ActiveXObject('MSXML2.DOMDocument.4.0');
objSrcTree.async = false;
objSrcTree.load('vote.xml');
objXSLT=new ActiveXObject('MSXML2.FreeThreadedDOMDocument.4.0');
objXSLT.async = false;
objXSLT.load('VmlChart.xslt');
objCache = new ActiveXObject("Msxml2.XSLTemplate.4.0");
objCache.stylesheet = objXSLT;
}
function show(title)
{
var objXSLTProc = objCache.createProcessor();
objXSLTProc.input = objSrcTree;
objXSLTProc.transform();
output.innerHTML = objXSLTProc.output;
}
</SCRIPT>
</HEAD>
<BODY onload="init();show('TITLE');">
<DIV id="output" <div style="POSITION:absolute ;Z-INDEX:3;LEFT:250px;TOP:100px;"></DIV>
</BODY>
</HTML>
上面的代码,看不懂,不要着急,我最后会给大家提供一些我在昨天和今天看的一些文章和资料的地址,里面有丰富的关于我在做这个演示中解决各种问题的答案,我就不在画蛇添足,狗尾续貂的加那么多注释了,以前我就爱贴代码,有人便提醒我,把思路说说就行了,别人没空看你那些代码的,所以呢我现在就着重贴关键重要的代码,把完整代码以附件的形式提供给大家下载。
最后呢,因为目前我所展示给大家的和.NET一点儿关系也没有,而且好几次我发这样类似的文章到首页都被T了回来,原因是和.NET无关,所以呢,我得再写个.NET的例子,以便和.NET沾上边儿,好放到首页上来。下面是代码。
Default.aspx
<%@ Import Namespace="System.Xml" %>
<%@ Import Namespace="System.Xml.XPath" %>
<%@ Import Namespace="System.Xml.Xsl" %>
<script runat="server">
private const String filename = "vote.xml";
private const String stylesheet = "VmlChart.xslt";
private void Page_Load(object sender, System.EventArgs e)
{
if (!IsPostBack)
{
XslTransform xslt = new XslTransform();
xslt.Load(Server.MapPath(stylesheet));
XPathDocument xpathdocument = new XPathDocument( Server.MapPath(filename));
XmlTextWriter writer = new XmlTextWriter(Response.Output);
writer.Formatting = Formatting.Indented;
xslt.Transform(xpathdocument, null, writer, null);
}
}
</script>
上面的代码我也不多解释了,都是在MSDN里抄的,有兴趣看看MSDN吧,不过感觉.NET里关于XML处理的有好几个类特别有意思,比用脚本处理xml有趣多了。
改进:希望看到此POST的XML高手把偶的例子修改一下,以便让每个条形的上面显示它的投票数和占总投票数的比例,想做到这个我是一点儿思路也没有了,然后呢如果解决了这个问题的话,我想把它封装成一个htc的可重用组件,然后呢,进一步弄成.NET 自定义控件。
小节:有关XML的技术简直是数不胜数,而且应用也越来越广,想做好一个程序员,在知识上必须要有一定的深度和广度,XML无所不在,而且前途广大,随意还是从现在开始深入研究它吧。
脚注:下面提供一些我找的一些链接
Fusionner deux fichiers XML en XSLT
http://developpeur.journaldunet.com/ressource/xml/xml_merge.shtml
使用XSLT参数控制转换
http://www.zdnet.com.cn/developer/common/printfriend/printfriendly.htm?AT=39310562-3800066897t-20000560c
周未XSLT培训资料!
http://edobnet.cnblogs.com/archive/2004/06/21/17437.html
javascript如何控制xsl:param参数值?
http://forum.opendl.com/viewtopic.php?t=211&sid=cc8420a8ad950340828e03a0fc1c276a
XPath+XSLT
http://blog.joycode.com/saucer/archive/2004/08/02/29299.aspx
XML有问必答
http://forum.opendl.com/viewforum.php?f=5
IBM XML
http://www-128.ibm.com/developerworks/cn/xml/
技巧:将 XSLT 查找表打包成 EXSLT 函数
http://www-128.ibm.com/developerworks/cn/xml/x-tiplook2.html?ca=dwcn-newsletter-xml
XSLT知识总结
http://www.21ds.net/article/_3/_9/2005-05/28/567_1.html
发赛特技术网XSLT专题
http://www.ftponline.com/china/class.aspx?sort=XSLT
XSLT中的循环
http://bbs.xml.org.cn/dispbbs.asp?boardID=8&ID=12106
源码下载地址:https://files.cnblogs.com/onlytiancai/TestVml.rar