利用 .Net XML 解析 Execl XML单元格
/Files/chaobaojun/parseexcelxmlsrc.zip 下载源代码 转载 http://www.vckbase.com/document/viewdoc/?id=1726
阅读本文需要有 XML 规范基础 及 .net XML 解析基础
本文示例代码使用 Visual Stdio 2005 、Office Execl 2007
一、首先我们来看看Execl XML的开头
下面这段是文档的开头,其中定义了一些有用的命名空间,本文要用到的是:
ss:"urn:schemas-microsoft-com:office:spreadsheet",
它代表了工作表空间。
<?xml version="1.0" ?> <?mso-application progid="Excel.Sheet"?> <workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40"> </workbook>中间一些跳过不管,直接看Worksheet工作表段落。Worksheet字段的Name属性表示工作表名称 Table 字段中的保存了表格的行、列数目等属性 :
<Worksheet ss:Name="Sheet1"> <Table ss:ExpandedColumnCount="7" ss:ExpandedRowCount="13" x:FullColumns="1" x:FullRows="1" ss:DefaultColumnWidth="54" ss:DefaultRowHeight="13.5">接下来是关键部分,也是最乱的地方,表的数据区。
<Row ss:AutoFitHeight="0"/> <Row ss:AutoFitHeight="0"/> <Cell ss:Index="2"><Data ss:Type="String">a</Data></Cell> <Cell><Data ss:Type="String">b</Data></Cell> ...... </Row> <Row ss:Index="4" ss:AutoFitHeight="0"> <Cell><Data ss:Type="String">9</Data></Cell> <Cell><Data ss:Type="String">10</Data></Cell> </Row> ......上面的数据区如下图所示:
数据区在下面是其他Table表格、下一个Worksheet工作区、表格样式等信息,这里不详细讨论了。
二、Execl XML数据区的格式框架
首先了解一下构架,从上面的数据区编码可以看出,有如下规律:
需要注意的是,根据存盘情况不同,Row的情况会有变化,目前观察有如下几种:
由于Row的框架会变,我们的程序就必须覆盖所有情况。不知道MS为什么要这样设计,但是很明显我们写代码时将会比较痛苦......
三、部分解析代码
全部的Execl单元格解析比较复杂,这里只介绍基本的XML解析。
.net XML 解析模型
1.读入Execl XML文件
//有时候用户需要打开Execl的同时做解析,所以我们使用流来构造XML //我们的目的只是读出单元格,所以使用XPathDocument可以提高解析性能 //用到的命名空间 using namespace System::IO; using namespace System::Xml; using namespace System::Xml::XPath; //按下面的参数构造流 FileStream^ sr = File::Open("c:\Book1.XML",FileMode::Open,FileAccess::Read,FileShare::ReadWrite); //用流来构造XPathDocument XPathDocument^ doc = gcnew XPathDocument(sr);2.构造游标、命名空间
//用XPathDocument来构造XPathNavigator游标 XPathNavigator^ navigator = doc->CreateNavigator(); //navigator->NameTable是被原子化的XML文档内容 XmlNamespaceManager^ manager = gcnew XmlNamespaceManager(navigator->NameTable); //添加命名空间,并起个名字叫ss manager->AddNamespace("ss","urn:schemas-microsoft-com:office:spreadsheet");3.查询节点
//找到指定WorkSheet中Name属性,Select需要节点的绝对路径 XPathNodeIterator^ node = navigator->Select("/ss:Workbook/ss:Worksheet/@ss:Name",manager); XPathNavigator^ child = node->Current; //未知原因SelectChild()查询子结点总是失败4.操作节点游标
//移动到节点的第一个属性 child->MoveToFirstAttribute(); //移动到该节点的下一个属性 child->MoveToNextAttribute(); //如果在属性中则MoveToParent()回到节点,如果在节点上则回到上一级节点 child->MoveToParent(); //移动到下一个同级结点 child->MoveToNext(); //移动到第一个子结点 child->MoveToFirstChild(); //还有其他很多 ..... //得到当前游标位置上的名称(可能是节点名称(标记),也可能是属性名称) child->Name; //得到当前游标位置上的值(可能是节点的值,也可能是属性值) chile->Value;四、示例代码
示例代码的功能是取出Execl中指定的一列,并按照这列的值建立同名的文件夹。
由于Execl XML的特殊结构,程序里面的解析比较复杂,大家下载后有时间可以看看。
程序现在还有些小问题,需要改进。
解析思路为:
1.找到用户要求的Worksheet工作表
2.游标移动到Table
3.找到第一个带数据的Row;如果是相对行位置,则计算出其绝对行号(只有可能是1或2)
4.按照第一个带数据的Row所在的绝对行号,找到用户要求的起始行所在的Row位置;注意其间会混杂相对行位置和绝对行位置
5.在该Row内找用户要求的列(注意其间会混杂相对列位置和绝对列位置);如果找不到,则下移一行(注意其间会混杂相对行位置和绝对行位置),再找,直到找到该列为止
6.得到Data的值(取得指定数据项),做操作
7.如果用户指定的结束行号大于表中的行号,则以表中的末尾行号为准
运行效果:
数据解析工作非常辛苦、烦闷,同时也需要极大的耐心。希望我的这篇文章能给大家提供一些帮助。