在刚到公司的时候,接到一个比较重要的任务,从Excel导入。就是把用户的数据从Excel数据里导入到我们的GBQ4工程文件中。中间有个内容是生成日志。 提示用户Excel里的哪些数据导入了,哪些数据没有导入, 没有导入的原因是什么,也就是给一个导入结果日志, 以Html格式呈现。
当做此任务时,自然想到导入后产生的日志信息内容是存储在GSP文件里的(一种XML文件格式),这时自然联想到用xsl转换实现。但最后终因没有吃透这块技术而放弃了,采用了大家都能想到的一种做法,用字符串替换的方式处理。就是先做好一个Html文件,把其中要显示内容的地方做个标记,然后用代码动态生成Html的标记内容,最后存储成html格式。 因此很是贻笑大方。
希望本篇文章能对后面同志要做Xml到Html转换的时候提供一个参考。
现在做审核任务,同样又面临着导入Excel这个问题。同样也需要给出一个日志。这时总不能走老路了吧,不能再被贻笑大方了。帮仔细研究了下xsl如何使用。经过分析,发现其实也是比较简单的,就是有几个点要做好,尤其是Xpath要理解到位。在讲这个问题前,我先把最终的需求给大家看下,如下图:
图1
原文件(GSP文件)内容,以XML方式查看如下(选取了部分内容):
图2
在进行如何处理之前,还是先简单说下Xsl用法,如果你已经很熟悉这块了,可以跳过此部分。在这次处理此问题上,我们只用到了三个语法
1. <xsl:for-each select="节点">
2. <xsl:if test="条件">
3. <xsl:value-ofselect="节点名称"/>
一、Xsl 基础知识
详细内容可参阅此处: http://www.w3school.com.cn/xsl/讲的很详细。
在此我就简单说下几个地方:
我们也举个例子:有以下一段test.Xml文件:
<?xmlversion="1.0" encoding="UTF-8"?>
<doc>
<Hints>
<Message>字段XXX不存在</Message>
</Hints>
<Warnings>
<Message>XXXXXX</Message>
</Warnings>
<Errors>
<Message>这个问题不好.</Message>
</Errors>
</doc>
用XmlSpy创建一个Xls文件test.xsl
<?xmlversion="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:templatematch="/">
<html>
<head>
<title>测试用的代码</title>
</head>
<body>
<tableborder="1" bgcolor="#9acd32">
<tbody>
<tr><td><p>下面是所有的提示信息:</p></td>
<xsl:for-eachselect="doc/Hints">
<td><xsl:value-ofselect="Message"/></td>
</xsl:for-each>
</tr></tbody></table>
<p>下面是所有的错误信息:</p>
<xsl:for-eachselect="doc/Errors">
<p><xsl:value-ofselect="Message"/></p>
</xsl:for-each></body>
</html>
</xsl:template>
</xsl:stylesheet>
<xsl:templatematch='/'> 元素: match 属性用于关联 XML 元素和模板。match属性也可用来为整个文档定义模板。match 属性的值是 XPath 表达式(举例,match="/"定义整个文档)。也就是指的Xml文件中doc下所有的节点, 包括doc
<xsl:for-eachselect="doc/Hints">元素:是指对doc/Hints下所有的节点进行遍历。在遍历过程中,你可以进行判断,取值。
<xsl:value-ofselect="Message"/>元素,是指在遍历的时候,对于doc/Hints下所有的节点Message,取其所指的值。
<xsl:iftest="Message='3'">:则表示,只有当前Message节点的值为3成立时,才做后面的代码。
上面的内容就做这么多解释。如果还有不明白的,可以看下教程:http://www.w3school.com.cn/xsl/
好了,下面的问题是:如何把生成转换后的Html网页。有三种办法,在这里我只说两个:
1. 所下红色字体所示:其中,href后面所指的文件就是xsl文件,跟Xml文件同目录。
<?xmlversion="1.0" encoding="UTF-8"?>
<?xml-stylesheettype="text/xsl" href="test.xsl"?>
这样,用IE浏览器直接打开Xml文件,你就会看到了:
2. 用JavaScript写的:新做一个Html文件:写这样几行代码:
<html>
<body>
<script type="text/javascript">
// Load XML
var xml = new ActiveXObject("Microsoft.XMLDOM")
xml.async = false
xml.load("Test.xml")
// Load XSL
var xsl = new ActiveXObject("Microsoft.XMLDOM")
xsl.async = false
xsl.load("test.xsl")
// Transform
document.write(xml.transformNode(xsl))
</script>
</body>
</html>
就可以了。
二、由GSP文件生成Html的Log文件
1.要生成Htm格式,首先要先做一个Html模板,这样才能让界面显示的更好看,这个内容大家可以自己解决,在此不在叙述。分析下源Xml文件不难看出有几个特点:
a.有命名空间,所以在做xsl文件时,记得带上命名空间,不然无法取到相应的节点,因此,我们的xsl在第二行应写成这样:
<xsl:stylesheetversion="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:a="attribute" xmlns:c="collection"xmlns:o="object">
b. 此文件的结构是很明显的一个数据为结构,级别为
Model -> Database-> Tables ->Table。在Table上分了并行的两层o:TableSchema与o:TableData, 分别用于描述数据字段与记录内容。
2. 基于以上分析,我们以出NotMatchedExcelBQItem这张表的内容以表格形式显示看该怎么做。
我把其具体内容摘抄如下:
<o:Table TableKind="0">
<o:TableSchema>
<a:Name>NotMatchedExcelBQItem</a:Name>
<a:Remark>Excel表中识别出的没有匹配上组价的清单项</a:Remark>
<a:CommandEnable>True</a:CommandEnable>
<c:FieldSchemas>
<o:FieldSchema FieldKind="0">
<a:FieldName>ID</a:FieldName>
<a:DisplayName>索引</a:DisplayName>
<a:DataType>2</a:DataType>
</o:FieldSchema>
<o:FieldSchema FieldKind="2">
<a:FieldName>ExcelRowNo</a:FieldName>
<a:DisplayName>Excel行号</a:DisplayName>
<a:StrLength>255</a:StrLength>
<a:TrimSpace>True</a:TrimSpace>
</o:FieldSchema>
<o:FieldSchema FieldKind="2">
<a:FieldName>Code</a:FieldName>
<a:DisplayName>编码</a:DisplayName>
<a:StrLength>255</a:StrLength>
<a:TrimSpace>True</a:TrimSpace>
</o:FieldSchema>
<o:FieldSchema FieldKind="2">
<a:FieldName>Description</a:FieldName>
<a:DisplayName>名称</a:DisplayName>
<a:DataType>10</a:DataType>
</o:FieldSchema>
<o:FieldSchema FieldKind="2">
<a:FieldName>Unit</a:FieldName>
<a:DisplayName>单位</a:DisplayName>
<a:StrLength>255</a:StrLength>
<a:TrimSpace>True</a:TrimSpace>
</o:FieldSchema>
<o:FieldSchema FieldKind="2">
<a:FieldName>Quantity</a:FieldName>
<a:DisplayName>工程量</a:DisplayName>
<a:StrLength>255</a:StrLength>
<a:TrimSpace>True</a:TrimSpace>
</o:FieldSchema>
</c:FieldSchemas>
</o:TableSchema>
<o:TableData>
<c:Records>
<o:Record>
<ID>0</ID>
<ExcelRowNo>2</ExcelRowNo>
<Code>01010001001</Code>
<Description>平整场地</Description>
<Unit>m3</Unit>
<Quantity>150</Quantity>
</o:Record>
<o:Record>
<ID>1</ID>
<ExcelRowNo>3</ExcelRowNo>
<Code>01010001002</Code>
<Description>挖土方</Description>
<Unit>m3</Unit>
<Quantity>100</Quantity>
</o:Record>
<o:Record>
<ID>2</ID>
<ExcelRowNo>4</ExcelRowNo>
<Code>01010001003</Code>
<Description>搅拌运输</Description>
<Unit>kg</Unit>
<Quantity>1200</Quantity>
</o:Record>
</c:Records>
</o:TableData>
</o:Table>
好,以表格方式出, 那肯定先把Html的Table写下:
<tableborderColor="#111111"height="52" width="800" border="1"id="table2">
<tr><thalign="left" width="50%" height="25"bgcolor="#CCCCCC"></th></tr>
</table>
第一步,我们应该称把表格的列标题显示出来,显示列标题,也就是把o:TableSchema里的显示名称displayName结点上的内容显示出来就可以。同时注意,不显示节点属性FieldKind为0的节点。同时,定位到此张表的Xpath要注意,因为有很多的o:Table,我是没有办法区分表ErrorImportToGBQ4,所以,在把所有的表遍历一次,用if语句来做判断要不要处理。
定位到表的xpath应该是:GSPModel/c:Databases/o:Database[a:Name='DB']/c:Tables/o:Table。如查这个不理解,建议学习下xpath相关内容。
写法如下:
<xsl:for-eachselect="GSPModel/c:Databases/o:Database[a:Name='DB']/c:Tables/o:Table[@TableKind='0']">
<xsl:iftest="o:TableSchema/a:Name='ErrorImportToGBQ4'">
<tr><xsl:for-eachselect="o:TableSchema/c:FieldSchemas/o:FieldSchema[@FieldKind!='0']">
<th align="left" width="50%" height="25"bgcolor="#CCCCCC">
<xsl:value-of select="a:DisplayName"/></th>
</xsl:for-each>
</tr>
</xsl:if>
</xsl:for-each>
通过红色节点,就能把DisplayName的内容显示出来了。
第二步,显示数据内容,即:o:TableData>下的<c:Records>里的每条Reords内容。道理同上,可以这样写:如黑体所示,我们知道只有4列,故直接把列表写出,出值即可了。
<xsl:for-eachselect="o:TableData/c:Records/o:Record">
<tr>
<th><xsl:value-ofselect="ExcelRowNo"/></th>
<th><xsl:value-ofselect="Code"/></th>
<th><xsl:value-ofselect="Description"/></th>
<th><xsl:value-ofselect="Unit"/></th>
<th><xsl:value-ofselect="Quantity"/></th>
</tr>
</xsl:for-each>
这样这段代码合起来就是:
<table borderColor="#111111" width="800"border="1" id="table2">
<xsl:for-eachselect="GSPModel/c:Databases/o:Database[a:Name='DB']/c:Tables/o:Table[@TableKind='0']">
<xsl:iftest="o:TableSchema/a:Name='ErrorImportToGBQ4'">
<tr>
<xsl:for-eachselect="o:TableSchema/c:FieldSchemas/o:FieldSchema[@FieldKind!='0']">
<th align="left"><xsl:value-ofselect="a:DisplayName"/></th>
</xsl:for-each>
</tr>
<xsl:for-eachselect="o:TableData/c:Records/o:Record">
<tr>
<th><xsl:value-ofselect="ExcelRowNo"/></th>
<th><xsl:value-ofselect="Code"/></th>
<th><xsl:value-ofselect="Description"/></th>
<th><xsl:value-ofselect="Unit"/></th>
<th><xsl:value-ofselect="Quantity"/></th>
</tr>
</xsl:for-each>
</xsl:if>
</xsl:for-each>
</table>
做完后,记得把Xml文件最前面加上这样一行:
<?xml-stylesheet type="text/xsl"href="xsl文件名称"?>
再用浏览器查看就可以看到效果了:
这样就完成了把一段Xml文件数据内容转换为Html格式的日志了。