MS要将Office Open XML 格式成为国际标准,实现一统江湖。MS将Office 格式开放,还是向好的方面发展。OOXMLSDK 2.0 将会在Office 2010版本正式发行,现使用Bata版本进行读写Excel2007。
说先俺的系统配置:
系统:Windows Server 2003 R2 X64
开发软件:Microsoft VS 2008 Team
Office版本:Excel2007
OOXML版本:Office Open XML SDK2.0 Bata
关于OOXML的标准就不多说,先看看文件结构,单元格映射信息存放在部件tableSingleCells中,工作表信息存放在sheet,共享字符信息存放在sharedStrings中
使用到的主要部件将会有 xl/tables/tableSingleCells1.xml,xl/worksheets/sheet1.xml
4.1建立XML映射:俺有这样一张表Book1.xlsx,想通过读取Excel数据,显示出来。
俺想通过XML MAP工作表的单元格,然后程序读取映射单元格中的值和Xpath。首先,建立映射关系,映射表中『用户名称』,『客户联系人』,『联系电话』,『客户经理』,『客户经理联系电话』,『业务类型』,『前端数量』,『业务类别』,『区域』字段值。第一步,要建立XML映射文件,T1schema.Xml映射文件如下:
<?xml version="1.0" standalone="yes"?>
<QQTintDataSet xmlns="http://tempuri.org/QQTintDataSet.xsd">
<yyexcel>
<id>1</id>
<Customer></Customer>
<CustomerContact></CustomerContact>
<CustomerTelephone></CustomerTelephone>
<AccountManager></AccountManager>
<AMTelephone></AMTelephone>
<AccessType></AccessType>
<AccessAmount></AccessAmount>
<BusinessName></BusinessName>
<Regional></Regional>
</yyexcel>
</QQTintDataSet>
在Excel2007“开发工具”选项卡上的“XML”组中,单击“源”。在“XML 源”任务窗格中,单击“XML 映射”。添加T1schema.Xml映射文件, 确认后如图
拖动『ns1:Customer』到单元格『用户名称』,如此类推,建立XML映射
关于Excel2007如何显示“XML源”按钮
http://office.microsoft.com/zh-cn/excel/HP102064082052.aspx
4.2 编写程序,读取单元格的值。新建一个控制台应用程序解决方案ConsoleApplication2,在ConsoleApplication2项目添加引用,引用为Office Open XML SDK2.0 Bata安装目录下DocumentFormat.OpenXml.dll文件,打开Program.cs,在文件头添加使用的库:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using System.Text.RegularExpressions;
using System.IO.Packaging;
4.2.1创建一个方法,用于读取单元格的值,并返回其值。方法名称为getCellValue,参数依次为文件名,工作表名称,单元格名称。
private static string getCellValue(string fileName, string sheetName, string addressName)
打开Excel2007文件,并取得相应的工作表
SpreadsheetDocument document = SpreadsheetDocument.Open(fileName, false);
IEnumerable<Sheet> sheets = document.WorkbookPart.Workbook.Descendants<Sheet>().Where(s => s.Name == sheetName);
WorksheetPart worksheetPart = (WorksheetPart)document.WorkbookPart.GetPartById(sheets.First().Id);
Worksheet worksheet = worksheetPart.Worksheet;
获取存在worksheetPart内部SingleCellTablePart(xl/tables/tableSingleCells1.xml)
SingleCellTablePart customxmlmap = worksheetPart.SingleCellTablePart;
获取符合条件的SingleXmlCell集合
IEnumerable<SingleXmlCell> singlexmlcells = customxmlmap.SingleXmlCells.Descendants<SingleXmlCell>();
获取每个SingleXmlCell
foreach (SingleXmlCell cellxmlmap in singlexmlcells)
{
获取xmlCellPr子树
XmlCellProperties xmlcellp = cellxmlmap.XmlCellProperties;
获取子树xmlPr的Xpath属性(映射Xpath)和单元格名称(XML属性r)
Console.WriteLine("单元格{1}映像信息:{0}", xmlcellp.XmlProperties.XPath, cellxmlmap.CellReference.Value);
}
获取单元格行序号
uint rowIndex = GetRowIndex(addressName);
获取单元格列名称
string colName = GetColumnName(addressName);
根据行序号和列名称,得到单元格
Cell cell = GetSpreadsheetCell(worksheet, colName, rowIndex);
如果单元格是数字格式,在sheet.xml中<v></v>直接表示单元格的值,所以直接返回,如表中单元格“I4”。
if (cell == null)
{
//指定的单元格不存在.
return "找不到任何符合条件的单元格";
}
if (cell.DataType == null)
{
if (cell.CellValue != null)
{
return cell.CellValue.Text;
}
}
如果单元格是字符格式或布尔格式,需要根据sheet.xml中t属性值转换。t=”s”表示字符,t=”b”表示布尔,
string str = "找不到任何符合条件的值";
switch (cell.DataType.ToString())
{
case "s":
单元格的值是字符类型
SharedStringItem item;
SharedStringTablePart shareStringPart;
获取shareString部件
if (document.WorkbookPart.GetPartsOfType<SharedStringTablePart>().Count() > 0)
{
shareStringPart = document.WorkbookPart.GetPartsOfType<SharedStringTablePart>().First();
int requestedString = Convert.ToInt32(cell.CellValue.Text);
根据在sheet.xml中<v></v>表示单元格的值,查找shareString获取相应字符。
item = shareStringPart.SharedStringTable.Elements<SharedStringItem>().ElementAt(requestedString);
str = item.Text.Text;
}
Console.WriteLine("单元格的类型是:S");
break;
case "b":
单元格的值是布尔类型,根据在sheet.xml中<v></v>表示单元格的值,转换成相应字符。
if (cell.CellValue.Text == "1")
{
str = "TRUE";
}
else
{
str = "FALSE";
}
Console.WriteLine("单元格的类型是:B");
break;
default:
Console.WriteLine("单元格的类型是:{0}",cell.DataType);
break;
}
4.2.2以上出现三个辅助函数,分别是GetRowIndex,GetColumnName,GetSpreadsheetCell,说明如下:
// 创建正则表达式,根据单元格名称匹配行序号.
private static uint GetRowIndex(string cellName)
{
Regex regex = new Regex(@"/d+");
Match match = regex.Match(cellName);
return uint.Parse(match.Value);
}
// 根据单元格名称匹配列序号,从而得出单元格列序号.
private static string GetColumnName(string cellName)
{
// 创建正则表达式,根据单元格名称匹配单元格列序号.
Regex regex = new Regex("[A-Za-z]+");
Match match = regex.Match(cellName);
return match.Value;
}
根据行列关系获取单元格
private static Cell GetSpreadsheetCell(Worksheet worksheet, string columnName, uint rowIndex)
{
IEnumerable<Row> rows = worksheet.GetFirstChild<SheetData>().Elements<Row>().Where(r => r.RowIndex == rowIndex);
if (rows.Count() == 0)
{
// 找不到匹配的行号.
return null;
}
IEnumerable<Cell> cells = rows.First().Elements<Cell>().Where(c => string.Compare(c.CellReference.Value, columnName + rowIndex, true) == 0);
if (cells.Count() == 0)
{
// 找不到匹配的单元格.
return null;
}
return cells.First();
}
4.2.3主过程如下:
static void Main(string[] args)
{
string str = getCellValue("Book1.xlsx", "业务流程相关信息", "E4");
Console.WriteLine("单元格的值是:{0}",str);
}
4.2.4运行结果如下:
getCellValue("Book1.xlsx", "业务流程相关信息", "I4");
getCellValue("Book1.xlsx", "业务流程相关信息", "B3");