(注:已有更新的、更方便的解决方案,详见:导入Excel格式读者数据)
很多客户在问,能否将EXCEL数据格式转换为DP2系统数据格式,从而实现将外部数据批量导入到DP2系统中。
鉴于这些外来的EXCEL数据格式五花八门,没有一个统一的标准,所以在DP2系统中不可能预先提供一个大小通吃,自动转换的相关工具。我们必须对这些不同的EXCEL进行分析,再将电子表格中的数据对应转换为DP2系统数据的对应字段。
事实上,利用DP2系统数据格式采用当前最具开放性与结构化的XML(可扩展标注语言)标准,可以很容易找到EXCEL数据与DP2数据的对应关系。
下面,我将通过模拟学校图书馆从教务处获得一个EXCEL学生名录,并对应转换为DP2读者数据的流程,演示一下数据转换。
一、将EXCEL文件转换为XML格式
在office 2003及以上版本中的EXCEL程序打开将电子表格文件(*.xls)——从office 2003开始,office系列开始支持XML格式的文档。如图(为保护隐私,我将学生姓名隐藏):
在EXCEL中,通过“另存为”方式,将当前.xls文件另存为“XML 电子表格 2003()”——在另存为对话框中的“保存类型”中选择此项。
另存时,程序会提示是否去掉某些不兼容的功能,选择“是”:
现在,将会产生一个以XML为扩展名的文件,它就是一个采用XML标准的数据格式。我们可用记事本程序打开它查看内容(不要双击它打开,因为双击它,会根据文件头部的处理指令,自动调EXCEL程序来打开,这跟你之前装载.xls文件看到的效果没啥区别),如图:
仔细观察,可以看出这个文件中的Worksheet元素对应于EXCEL中的一个工作表,Table元素对应于其中的一个表格,Row元素对应于表格中的一行,Cell元素对应于这行中的一列(单元格)。
也就是说,我们只需要处理这些重复的Row及Cell,定位其顺序,即可对应转换成DP2系统读者数据格式中的元素(字段)中。
由于现在的电子表格数据是XML格式的,我们DP2系统读者数据格式也是XML格式的,XML转换成另一个XML,最好的办法是借助XSLT(可扩展样式转换语言)标准。
二、编写可扩展样式转换语言
可扩展样式转换语言可通过开发工具进行编写,如无开发工具,也可直接利用纯文本编辑器(如微软的notepad.exe)进行编写。
首先,引入相应的名字空间,这些名字空间除了可扩展样式语言采用的外,还有DP2系统读者数据格式采用的"http://dp2003.com/dprms"以及XML电子表格数据采用"urn:schemas-microsoft-com:office:spreadsheet"(不明白微软在XML电子表格中采用同一个名字空间的两个不同前缀的深意,先照搬过来再说):
xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dprms="http://dp2003.com/dprms" xmlns:e="urn:schemas-microsoft-com:office:spreadsheet" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" exclude-result-prefixes="e ss">
其次,希望输入的结果为UTF-8编码的XML文档(可选):
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
由于电子表格可能具有多个工作表,为了区分这些工作表,我们可以设置一个参数,将其值传递到后面的模板中:
<xsl:param name="sheetname">读者信息xsl:param>
<xsl:template match="e:Workbook">
<xsl:element name="dprms:collection">
<xsl:apply-templates select="e:Worksheet[@ss:Name=$sheetname]"/>
xsl:element>
xsl:template>
开始层层匹配模板(从工作表找到工作表中的表格中的行,再找到行中的各单元格。匹配的同时,输出DP2读者数据的封装元素root):
<xsl:template match="e:Worksheet">
<xsl:apply-templates select="e:Table/e:Row"/>
xsl:template>
<xsl:template match="ss:Row">
<xsl:element name="root">
<xsl:apply-templates select="e:Cell"/>
xsl:element>
xsl:template>
<xsl:template match="ss:Cell">
<xsl:variable name="curCol">
<xsl:choose>
<xsl:when test="@ss:Index">
<xsl:value-of select="@ss:Index"/>
xsl:when>
<xsl:otherwise>
<xsl:call-template name="cell-index">
<xsl:with-param name="idx" select="1"/>
xsl:call-template>
xsl:otherwise>
xsl:choose>
xsl:variable>
<xsl:choose>
<xsl:when test="$curCol=1">
<xsl:element name="name">
<xsl:value-of select="normalize-space(ss:Data)"/>
xsl:element>
xsl:when>
—其它匹配元素略-->
xsl:choose>
xsl:template>
上面模板中,可以看到设置了一个curCol变量,这是本可扩展样式转换文件的一个重点与要点。由于在XML格式电子表格中,对于空的单元格,并不是完全采用不含数据元素的cell元素表达,为了节省数据尺寸,采用在下一个cell元素中添加ss:Index属性实现跳过空单元格并重新定位新单元格的方式。所以,并不能简单通过position()函数定位不同的Cell,因而,为curCol变量值设计了一个递归调用模板,命名为"cell-index":
<xsl:template name="cell-index">
<xsl:param name="idx"/>
<xsl:if test="$idx <= position()">
<xsl:choose>
<xsl:when test="preceding-sibling::ss:Cell[position()=$idx]/@ss:Index">
<xsl:value-of select="preceding-sibling::ss:Cell[position()=$idx]/@ss:Index +$idx"/>
xsl:when>
<xsl:when test="$idx = position()">
<xsl:value-of select="$idx"/>
xsl:when>
<xsl:otherwise>
<xsl:call-template name="cell-index">
<xsl:with-param name="idx" select="$idx+1"/>
xsl:call-template>
xsl:otherwise>
xsl:choose>
xsl:if>
xsl:template>
至此,可扩展样式文件编辑完成。
三、转换XML格式的电子表格数据为DP2系统读者数据格式
可以用多种方式实现XML的样式转换,我们采用C#编一个转换程序实现转换后的文件输出:
在XML文件输入框中,通过右边的文件浏览按钮,查找到待转换的XML格式的电子表格文件。
在XSLT转换文件输入框中,通过右边的文件浏览按钮,查找到刚才编制的可扩展样式转换文件。
在结果输出目录输入框中,通过右边的文件夹浏览按钮,确定结果文件输出目录。
然后,点击样式转换按钮,会在下部的文本框中,显示转换后的结果。并且,在指定的结果输出目录中,会创建出以默认的“output.xml”文件名命名的结果文件
如果需要转换程序及可扩展样式文件,请与我直接联系。