Excel文档处理之Open XML
来源:互联网 发布:mac 截图 任意区域 编辑:程序博客网 时间:2024/05/22 12:11
引言
在使用Open XML处理Excel文档之前,需要先确定它的作用范围,Open XML适用于2007版本及以上的Excel文档的处理。
第二步就是配置Open XML的开发环境:Open XML相关下载链接。
1、新建Excel文档
咱们先从一个实际的Excel文档入手,在桌面上新建一个Excel文档,默认会有一个Sheet,可以理解为一个工作表或一个页面。
创建一个Excel所等价的代码如下:
//本代码段为简化代码,只作理解之用。//SpreadsheetDocument:Excel文档的变量类型//以path中所指定的地址和名称创建一个Excel文档//SpreadsheetDocumentType.Workbook:指明创建的文件类型为后缀名为.xlsx的Excel文档SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Create(path, SpreadsheetDocumentType.Workbook);将刚刚新建的Excel文档的后缀名改为rar(压缩包格式),然后打开压缩包,看到如下图所示的目录,其中xl文件夹中的文件很重要,需要仔细研究。打开xl文件夹。
先打开workbook.xml,默认会用浏览器显示其内容,workbook.xml主要对sheet(理解为工作表或页面)进行宏观性全局性的描述。下图中,第二行开始到结束,由叫做“workbook”的元素包裹在最外层,可以把workbook理解为工作薄,但不完全等价于Excel文件。红色方框框起来的元素为“ sheets”,它的内部描述了该文档有几个sheet(理解为工作表或页面)。由于新建的Excel文档默认只有一个sheet,所以“sheets”元素的内部只有一个“sheet”元素,对应着创建Excel文档后默认的“Sheet1”工作表,图中的sheet元素内部,有三个必备属性:r:id、sheetId、name。r:id是字符串类型的属性,以“rId”+数字作为其内容;sheetId为数字类型的属性;name就是该sheet的名字。前两个属性都属于sheet的id值,都是隐含的内在的属性,name属性是外在的显露出来的属性,图中name属性的值“Sheet1”刚好对应新建的Excel中的默认的sheet名称。
2、添加一个sheet工作表
倘若在Excel中添加一个工作表,并将其命名为“测试”,会有什么变化呢?具体的操作要么把Excel文件后缀名恢复原样,要么可以再新建一个Excel,并添加一个工作表。再次打开workbook.xml文件时,会发现多了一个sheet元素。该sheet元素对应的r:id和sheetId的值都比默认的sheet元素的值增加了1,name属性的值为“测试”。
添加一个工作表等价的代码如下:
//本代码段为简化代码,只作理解之用。//workbookPart:管理Workbook工作薄//WorksheetPart:管理工作表,一个WorksheetPart对应一个工作表//workbookPart.AddNewPart<WorksheetPart>():添加一个新的WorksheetPartWorksheetPart worksheetPart = workbookPart.AddNewPart<WorksheetPart>();//workbookPart.Workbook.Sheets:Workbook元素中的Sheets元素//Sheets.Elements<Sheet>():Sheets元素中Sheet元素的集合//Elements<Sheet>().LastOrDefault():Sheet元素集合中最后一个Sheet元素或默认的Sheet元素Sheet sheet = workbookPart.Workbook.Sheets.Elements<Sheet>().LastOrDefault();//定义默认的sheetId值//当工作薄中一个工作表也没有时,便以1作为新添加的工作表的Sheet元素的Id值//当工作薄中存在工作表时,便将最后一个工作表的Id值加1作为新添加的工作表的Sheet元素的Id值UInt32Value sheetId = 1;if (sheet != null){ sheetId = sheet.SheetId + 1;}//AppendChild:添加一个子元素workbookPart.Workbook.Sheets.AppendChild(new Sheet(){ //Id为字符串类型的Id属性 Id = workbookPart.GetIdOfPart(worksheetPart), //SheetId为数值类型的Id属性 SheetId = sheetId, //工作表的名称 Name = sheetName});
3、向sheet工作表中添加内容
在上方压缩包目录图中,打开worksheets文件夹。该目录下有一个名为“sheet1.xml"的文件,对应默认的”Sheet1“工作表。有多少个工作表,这个文件夹里面就有多少个sheet文件,sheet文件对所有非空表格的信息都进行了登记。
打开sheet1.xml文件,内容如下图所示。其中sheetViews元素可以描述当前选中的表格所在的位置,由于新建的Excel文档没有选中表格,所有sheetViews没有描述;sheetData元素记录非空表格的位置及表格内容,同样,由于Excel没有写入任何内容,sheetData中也就没有记录。
这时,对空白的Sheet1工作表添加如下图所示的内容。分别在A1、B2、C3单元格添加了“1”、“数据”、“Data”,并选中B1单元格。添加这些数据后,sheet1.xml文件主要的变化如下图。sheetViews元素中,selection元素描述选中的单元格为B1。sheetData元素中,有三个row元素,分别对应添加的“1”、“数据”、“Data”;在row元素中,r属性表示第几行,c元素记录非空表格的位置及表格内容;在c元素中,r元素表示单元格的位置,其中第一个c元素中,v元素表示单元格的内容,第二个和第三个c元素的解释请看下面的内容。
在xl文件夹中,多了一个名为sharedStrings.xml的文件,这个文件名字面上的意思是共享字符串,这是Excel中很有意思的一个东西,它将可能会重复用到的字符串都存储于这个文件中。打开它,内容如下图所示,si元素中存储着可能会重复用到的字符串,可以想象,当N个单元格中的内容都是“数据”时,那么Excel就不用为每个单元格分配额外的存储空间,而只需要在上图中的v元素中存储该字符串的引用即可,例:在下图中,数据在sharedStrings.xml文件中的位置是第0个(默认从第0个开始),上图中c元素中t属性赋值为“s”,表明该单元格的内容为共享字符串,v元素中的值为0,表示该单元格中的内容为sharedStrings.xml文件中第0个字符串。
向表格中添加内容的代码如下:
//本代码段为简化代码,只作理解之用。//SheetData:记录非空单元格的位置及内容//worksheetPart:管理工作表,一个WorksheetPart对应一个工作表SheetData sheetData = worksheetPart.Worksheet.Elements<SheetData>().FirstOrDefault();//Row:工作表中的行Row row = sheetData.Elements<Row>().LastOrDefault();//添加普通数据void AddData(object data){ Cell cell = row.AppendChild(new Cell() { //CellValue:单元格内容 CellValue = new CellValue() { Text = data.ToString() }, //DataType:单元格类型 DataType = CellValues.String, });}//添加共享字符串private void AddSharedString(object data){ Cell cell = row.AppendChild(new Cell() { CellValue = new CellValue(Convert.ToString(GetSharedStringItemIndex(data.ToString()))), DataType = CellValues.SharedString, });}//获取指定字符串在SharedStringTable中的索引值,不存在就创建int GetSharedStringItemIndex(string value){ //字符串从0开始标记 int index = 0; //寻找是否有与value相同的字符串,若有,则将index设置为对应的标记值,并返回 //SharedStringItem:共享字符串的数据类型 //sharedStringTable:共享字符串表 foreach (SharedStringItem item in sharedStringTable.Elements<SharedStringItem>()) { if (item.InnerText == value) { return index; } index++; } //若没有与value相同的字符串,则添加一个字符串到共享字符串表中,并将其内容设置为value sharedStringTable.AppendChild(new SharedStringItem(new Text(value))); return index;}
4、表格样式
在xl文件夹中有一个styles.xml文件,这个文件保存着单元格的格式,包含背景、边框、字体等设置。在刚刚新建的Excel文档中,styles.xml中主要内容如下列图所示。fonts: 以font元素为单位存储字体样式;fills:以fill元素为单位存储填充样式;borders:以border元素为单位存储边框样式。以上每个元素都有一个相同的属性count,用于表示该元素包含几个子元素。在font元素中,sz:字体大小;color:字体颜色;name:字体类型。在fill元素中,patternFill:填充样式。在border元素中,left、right、top、bottom分别表示左右上下边框的样式。cellXfs:以xf为单位存储表格样式,此处存储的表格样式是对font元素、fill元素、border元素的调用和组合。在xf元素中,将第0个border元素、第0个fill元素和第0个font元素组合成一个表格样式。在n个表格样式中,往往会有相同的字体样式、填充样式、边框样式,因此使用引用的方式设置表格样式可以节约存储空间。再者,在常规的Excel文档中,往往一大堆内容使用同一个表格样式,使用引用的方式调用表格样式可以节省大量存储空间。
倘若将第二行第二列的“数据”的单元格填充颜色设置为黄色,字体颜色设置为红色,worksheets文件夹中的sheet1.xml将会发生如下图所示的主要变化,在第二个row元素(即r 属性的值为2的row元素)中,位置为B2的c元素的s属性(单元格样式style)的值为1,表示该单元格的单元格样式引用上图中cellXfs元素中的第1个xf元素(上图中只有第0 个 xf元素)。
上方填充颜色和字体颜色的设置导致xl文件夹中styles.xml也发生了相应的变化,如下列三张图所示。多了一个font元素,该元素中,color属性的值“FFFF0000”代表红色,意为字体颜色为红色;多了一个fill元素,该元素中,fgColor的值“FFFFFF00”代表黄色,以为填充颜色为黄色;cellXfs元素中多了一个xf元素,fontId值为“2”,fontId值为“2”,即引用下方第一张图中的font和第二张图中的fill,并组合成一个单元格样式,供上图中红色方框内的s属性调用。
上述添加单元格样式的代码如下:
//本代码段为简化代码,只作理解之用。//Stylesheet:单元格样式Stylesheet stylesheet = workbookPart.WorkbookStylesPart.Stylesheet;//添加一个填充样式Fill fill = stylesheet.Fills.AppendChild(new Fill(){ PatternFill = new PatternFill() { PatternType = PatternValues.Solid, ForegroundColor = new ForegroundColor() { Rgb = new HexBinaryValue((Color.Yellow).ToArgb().ToString("X")) } }});//添加一个字体样式Font font = stylesheet.Fonts.AppendChild(new Font(){ Color = new Color() { Rgb=new HexBinaryValue((Color.Red).ToArgb().ToString("X")) }});//添加一个单元格样式stylesheet.CellFormats.AppendChild(new CellFormat(){ //引用上方定义的fill FillId = (uint)fill.Index, //引用上方定义的font FontId = (uint)font.Index});
5、代码
代码分为两个部分:OXExcel类:Excel文档结构层次的节点或元素的处理;OXSheet:工作表内容层次的节点或元素的处理。
注:本代码段是本人经多次试验后的结果,但依然不尽如人意,主要表现在两个方面:1、表格样式部分只编写了修改背景颜色的功能;2、超链接的添加会导致一个后遗症,打开Excel文档后不修改任何东西,关闭时总会有一个是否保存的提示。
using System;using System.Linq;using System.Runtime.InteropServices;using DocumentFormat.OpenXml;using DocumentFormat.OpenXml.Packaging;using DocumentFormat.OpenXml.Spreadsheet;using System.IO;namespace OpenXMLDemo{ public class OXExcel { //判断文件是否只读的相关定义 [DllImport("kernel32.dll")] public static extern IntPtr _lopen(string lpPathName, int iReadWrite); [DllImport("kernel32.dll")] public static extern bool CloseHandle(IntPtr hObject); public const int OF_READWRITE = 2; public const int OF_SHARE_DENY_NONE = 0x40; public static IntPtr HFILE_ERROR = new IntPtr(-1); //OpenXml中涉及Excel的元素,定义全局变量,方便长时间读写Excel文档 //SpreadsheetDocument:Excel文档的变量类型 private SpreadsheetDocument spreadsheetDocument = null; //WorkbookPart:Excel文档的总管 private WorkbookPart workbookPart = null; //表格格式总管 private Stylesheet stylesheet = null; //文件路径+名字 private string path; //程序运行时,打开通过文件流载入的Excel文件会提示只读 private FileStream fileStream; //指定Excel的路径(包含名称) public OXExcel(string path) { this.path = path; } //载入Excel public bool LoadExcel() { //Excel是否存在 if (System.IO.File.Exists(path)) { //Excel是否只读 if (!IsReadOnly()) { //使用文件流载入Excel,使得程序运行时,使用本程序外的软件打开Excel时,将会提示Excel只读,不能编辑。 //可以防止在程序外部打开Excel,导致本程序失去对Excel的载入,从而程序崩溃、异常。 fileStream = new FileStream(path, FileMode.Open, FileAccess.ReadWrite); //OpenSettings:Excel打开后的设置 OpenSettings openSettings = new OpenSettings(); //设置Excel不自动保存 openSettings.AutoSave = false; spreadsheetDocument = SpreadsheetDocument.Open(fileStream, true, openSettings); workbookPart = spreadsheetDocument.WorkbookPart; //下列子元素若不存在,则需要重新创建Excel if (workbookPart == null || workbookPart.Workbook == null || workbookPart.Workbook.Sheets == null || workbookPart.SharedStringTablePart == null || workbookPart.SharedStringTablePart.SharedStringTable == null || workbookPart.WorkbookStylesPart == null || workbookPart.WorkbookStylesPart.Stylesheet == null) { createExcel(); } stylesheet = workbookPart.WorkbookStylesPart.Stylesheet; } else { //只读 return false; } } else { createExcel(); } return true; } //判断指定路径的Excel是否只读 private bool IsReadOnly() { IntPtr vHandle = _lopen(path, OF_READWRITE | OF_SHARE_DENY_NONE); if (vHandle == HFILE_ERROR) { CloseHandle(vHandle); return true; } CloseHandle(vHandle); return false; } //创建Excel private void createExcel() { //SpreadsheetDocument if (spreadsheetDocument == null) { //以path中所指定的地址和名称创建一个Excel文档 //SpreadsheetDocumentType.Workbook:指明创建的文件类型为后缀名为.xlsx的Excel文档 spreadsheetDocument = SpreadsheetDocument.Create(path, SpreadsheetDocumentType.Workbook); } //WorkbookPart workbookPart = spreadsheetDocument.WorkbookPart; if (workbookPart == null) { workbookPart = spreadsheetDocument.AddWorkbookPart(); } //Workbook if (workbookPart.Workbook == null) { workbookPart.Workbook = new Workbook(); } //Sheets if (workbookPart.Workbook.Sheets == null) { workbookPart.Workbook.Sheets = new Sheets(); } //SharedStringTablePart if (workbookPart.SharedStringTablePart == null) { workbookPart.AddNewPart<SharedStringTablePart>(); } //SharedStringTabel if (workbookPart.SharedStringTablePart.SharedStringTable == null) { workbookPart.SharedStringTablePart.SharedStringTable = new SharedStringTable(); } workbookPart.SharedStringTablePart.SharedStringTable.Save(); //WorkbookStylesPart if (workbookPart.WorkbookStylesPart == null) { workbookPart.AddNewPart<WorkbookStylesPart>(); } //Stylesheet if (workbookPart.WorkbookStylesPart.Stylesheet == null) { workbookPart.WorkbookStylesPart.Stylesheet = new Stylesheet(); } workbookPart.Workbook.Save(); //经过我的大量实践,在创建Workbook和Worksheet后,均需调用spreadsheetDocument.Dispose()方法,否则Excel文件会有问题 //但是Dispose()后,所有资源均释放了,所以需要重新载入Excel //也许有人会想,为什么不在所有关于Excel的操作(包括创建、读写)完成后,再调用Dispose()? //我的回答是:程序总会出现异常,异常时,并不会自动调用Dispose //请原谅我的强迫症,1、为了能在程序运行时,保持对Excel的载入。2、遇到程序异常时,Excel文件不会出现任何问题。 reLoad(); } //释放定义的全局变量等所有资源,并重新载入Excel private void reLoad() { Dispose(); LoadExcel(); } //判断Worksheet是否存在 public bool IsWorksheetExist(string sheetName) { //workbookPart:管理Workbook工作薄 //workbookPart.Workbook.Sheets:Workbook元素中的Sheets元素 //Sheets.Elements<Sheet>():Sheets元素中Sheet元素的集合 //Elements<Sheet>().FirstOrDefault():Sheet元素集合中第一个Sheet元素或默认的Sheet元素 //FirstOrDefault(s => s != null && s.Name != null && s.Name == sheetName)等同于如下代码 //foreach(Sheet s in workbookPart.Workbook.Sheets.Elements<Sheet>()) //{ // 寻找Name与sheetName相同的Sheet元素 // if(s! = null && s.Name != null && s.Name == sheetName) // { // sheet = s; // break; // } //} //Sheet是工作表在宏观上的元素,它存储工作表的标识和名称 Sheet sheet = workbookPart.Workbook.Sheets.Elements<Sheet>(). FirstOrDefault(s => s != null && s.Name != null && s.Name == sheetName); if (sheet == null) { return false; } //WorksheetPart:管理工作表,一个WorksheetPart对应一个工作表 //Worksheet是工作表在微观上的元素,它主要存储工作表中非空表格的内容 WorksheetPart worksheetPart = (WorksheetPart)workbookPart.GetPartById(sheet.Id); //Worksheet,SheetData if (worksheetPart.Worksheet == null || worksheetPart.Worksheet.Elements<SheetData>().FirstOrDefault() == null) { return false; } return true; } //添加一个工作表 public void AddWorksheetPart(string sheetName) { Sheet sheet = workbookPart.Workbook.Sheets.Elements<Sheet>(). FirstOrDefault(s => s != null && s.Name != null && s.Name == sheetName); WorksheetPart worksheetPart = null; if (sheet != null) { worksheetPart = (WorksheetPart)workbookPart.GetPartById(sheet.Id); } else { worksheetPart = workbookPart.AddNewPart<WorksheetPart>(); } //Worksheet if (worksheetPart.Worksheet == null) { worksheetPart.Worksheet = new Worksheet(); } //SheetData if (worksheetPart.Worksheet.Elements<SheetData>().FirstOrDefault() == null) { //workbookPart.AddNewPart<WorksheetPart>():添加一个新的WorksheetPart worksheetPart.Worksheet.AppendChild(new SheetData()); } worksheetPart.Worksheet.Save(); //Sheet if (sheet == null) { sheet = workbookPart.Workbook.Sheets.Elements<Sheet>().LastOrDefault(); //定义默认的sheetId值,当工作薄中一个工作表也没有时,便以1作为新添加的Sheet元素的Id值 UInt32Value sheetId = 1; if (sheet != null) { sheetId = sheet.SheetId + 1; } //AppendChild:添加一个子元素 workbookPart.Workbook.Sheets.AppendChild(new Sheet() { //Id为字符串类型的Id属性 Id = workbookPart.GetIdOfPart(worksheetPart), //SheetId为数值类型的Id属性 SheetId = sheetId, //工作表的名称 Name = sheetName }); } workbookPart.Workbook.Save(); //此处解释同上方CreateExcel()方法中一致 reLoad(); } //获取工作表 public WorksheetPart GetWorksheetPart(string sheetName) { //WorksheetPart Sheet sheet = workbookPart.Workbook.Sheets.Elements<Sheet>().FirstOrDefault(s => s != null && s.Name != null && s.Name == sheetName); WorksheetPart worksheetPart = null; if (sheet != null) { worksheetPart = (WorksheetPart)workbookPart.GetPartById(sheet.Id); } else { return null; } //Worksheet,SheetData if (worksheetPart.Worksheet == null || worksheetPart.Worksheet.Elements<SheetData>().FirstOrDefault() == null) { return null; } return worksheetPart; } //获取共享字符串表 public SharedStringTable GetSharedStringTable() { return workbookPart.SharedStringTablePart.SharedStringTable; } //根据背景颜色获取自定义的表格样式的索引,不存在则创建 public int GetStyleIndexByBackColor(System.Drawing.Color color) { checkStylesheet(); int fillIndex = getFillIndex(color); int index = 0; foreach (CellFormat cellFormat in stylesheet.CellFormats.Elements<CellFormat>()) { if (cellFormat != null && cellFormat.FillId != null && cellFormat.FillId == fillIndex && cellFormat.FontId == null && cellFormat.BorderId == null) { return index; } index++; } stylesheet.CellFormats.AppendChild(new CellFormat() { FillId = (uint)fillIndex, }); stylesheet.Save(); return index; } //检验Stylesheet的完整性 private void checkStylesheet() { if (stylesheet.Fonts == null) { stylesheet.Fonts = new Fonts(); } if (stylesheet.Fonts.ChildElements.Count == 0) { stylesheet.Fonts.AppendChild(new Font()); } if (stylesheet.Fills == null) { stylesheet.Fills = new Fills(); } if (stylesheet.Fills.ChildElements.Count == 0) { stylesheet.Fills.AppendChild(new Fill() { PatternFill = new PatternFill() { PatternType = PatternValues.None } }); stylesheet.Fills.AppendChild(new Fill() { PatternFill = new PatternFill() { PatternType = PatternValues.Gray125 } }); } if (stylesheet.Borders == null) { stylesheet.Borders = new Borders(); } if (stylesheet.Borders.ChildElements.Count == 0) { stylesheet.Borders.AppendChild(new Border()); } if (stylesheet.CellFormats == null) { stylesheet.CellFormats = new CellFormats(); if (stylesheet.CellFormats.ChildElements.Count == 0) { stylesheet.CellFormats.AppendChild(new CellFormat()); } } stylesheet.Save(); } //根据背景颜色获取Stylesheet的子元素Fill的索引值,不存在则创建 private int getFillIndex(System.Drawing.Color color) { int fillIndex = 0; foreach (Fill fill in stylesheet.Fills.Elements<Fill>()) { if (fill != null && fill.PatternFill != null && fill.PatternFill.PatternType != null && fill.PatternFill.PatternType == PatternValues.Solid && fill.PatternFill.ForegroundColor != null && fill.PatternFill.ForegroundColor.Rgb != null && fill.PatternFill.ForegroundColor.Rgb.Value != null && fill.PatternFill.ForegroundColor.Rgb.Value == color.ToArgb().ToString("X")) { return fillIndex; } fillIndex++; } stylesheet.Fills.AppendChild(new Fill() { PatternFill = new PatternFill() { PatternType = PatternValues.Solid, ForegroundColor = new ForegroundColor() { Rgb = new HexBinaryValue(color.ToArgb().ToString("X")) } } }); stylesheet.Save(); return fillIndex; } // 释放所有资源 public void Dispose() { if (stylesheet != null) { stylesheet.Save(); stylesheet = null; } if (workbookPart != null) { workbookPart.Workbook.Save(); workbookPart = null; } if (spreadsheetDocument != null) { spreadsheetDocument.Close(); spreadsheetDocument.Dispose(); spreadsheetDocument = null; } if (fileStream != null) { fileStream.Flush(); fileStream.Close(); fileStream.Dispose(); fileStream = null; } } } public class OXSheet { //定义WorksheetPart子元素节点 private WorksheetPart worksheetPart = null; private SharedStringTable sharedStringTable = null; //SheetData:记录非空单元格的位置及内容 private SheetData sheetData = null; //指向当前行Row private Row currentRow = null; //根据ASCII码获取字母A的int编码值 private int begin = 'A' - 1; public OXSheet(WorksheetPart worksheetPart, SharedStringTable sharedStringTable) { this.worksheetPart = worksheetPart; sheetData = worksheetPart.Worksheet.Elements<SheetData>().FirstOrDefault(); currentRow = sheetData.Elements<Row>().LastOrDefault(); if (currentRow == null) { AddRow(); } this.sharedStringTable = sharedStringTable; } //添加一行 public void AddRow() { currentRow = new Row(); sheetData.AppendChild(currentRow); } //在当前行中添加一个的普通表格 public void AddCell(object data) { addCell(data, -1); } //在当前行中添加一个指定表格样式的普通表格 public void AddCell(object data, int styleIndex) { addCell(data, styleIndex); } private void addCell(object data, int styleIndex) { Cell cell = currentRow.AppendChild(new Cell() { //CellValue:单元格内容 CellValue = new CellValue() { Text = data.ToString() }, //DataType:单元格类型 DataType = CellValues.String, }); if (styleIndex != -1) { cell.StyleIndex = (uint)styleIndex; } } //在当前行中添加一个类型为共享字符串的表格 public void AddSharedStringCell(object data) { addSharedStringCell(data, -1); } //在当前行中添加一个类型为共享字符串、指定表格样式的表格 public void AddSharedStringCell(object data, int styleIndex) { addSharedStringCell(data, styleIndex); } private void addSharedStringCell(object data, int styleIndex) { Cell cell = currentRow.AppendChild(new Cell() { CellValue = new CellValue( Convert.ToString(getSharedStringItemIndex(data.ToString()))), DataType = CellValues.SharedString, }); if (styleIndex != -1) { cell.StyleIndex = (uint)styleIndex; } } //获取指定字符串在SharedStringTable中的索引值,不存在就创建 private int getSharedStringItemIndex(string value) { //字符串从0开始标记 int index = 0; //寻找是否有与value相同的字符串,若有,则将index设置为对应的标记值,并返回 //SharedStringItem:共享字符串的数据类型 //sharedStringTable:共享字符串表 foreach (SharedStringItem item in sharedStringTable.Elements<SharedStringItem>()) { if (item.InnerText == value) { return index; } index++; } //若没有与value相同的字符串,则添加一个字符串到共享字符串表中,并将其内容设置为value sharedStringTable.AppendChild(new SharedStringItem(new Text(value))); sharedStringTable.Save(); return index; } //在当前行中添加一个超链接表格 public void AddHyperLink(object data) { addHyperlink(data, -1); } //在当前行中添加一个超链接表格 public void AddHyperLink(object data, int styleIndex) { addHyperlink(data, styleIndex); } private void addHyperlink(object data, int styleIndex) { Cell cell = currentRow.AppendChild(new Cell() { CellFormula = new CellFormula() { Text = string.Format("HYPERLINK({0}{1}{0},{0}{1}{0})", "\"", data.ToString()) }, CellValue = new CellValue(data.ToString()), DataType = CellValues.String, }); if (styleIndex != -1) { cell.StyleIndex = (uint)styleIndex; } } //指定行和列定位表格,写入数据 public void Write(int rowIndex, int colIndex, object data) { Cell cell = getCell(getRow(rowIndex), colIndex); cell.CellValue = new CellValue(data.ToString()); } //读取指定行和列的内容 public string Read(int rowIndex, int colIndex) { Row row = getRow(rowIndex); Cell cell = getCell(row, colIndex); string value = string.Empty; if (cell.CellValue != null && cell.CellValue.InnerText != null) { value = cell.CellValue.InnerText; if (cell.DataType != null && cell.DataType == CellValues.SharedString) { return sharedStringTable.ElementAt(Int32.Parse(value)).InnerText; } else { return value; } } return value; } //根据行索引值获取列Row private Row getRow(int rowIndex) { Row row = sheetData.Elements<Row>().FirstOrDefault(r => r != null && r.RowIndex != null && r.RowIndex == rowIndex); if (row == null) { row = new Row() { RowIndex = (uint)rowIndex }; Row lastRow = sheetData.Elements<Row>().LastOrDefault(); if ((lastRow != null && lastRow.RowIndex != null && lastRow.RowIndex < rowIndex) || lastRow == null) { sheetData.AppendChild(row); } else { Row refRow = sheetData.Elements<Row>().FirstOrDefault(r => r != null && r.RowIndex != null && r.RowIndex > rowIndex); sheetData.InsertBefore(row, refRow); } } return row; } //根据指定行和列索引获取单元格Cell private Cell getCell(Row row, int colIndex) { Cell cell = row.Elements<Cell>().FirstOrDefault(c => c != null && c.CellReference != null && c.CellReference.Value == getColNameByColIndex(colIndex) + row.RowIndex); if (cell == null) { cell = new Cell() { CellReference = getColNameByColIndex(colIndex) + row.RowIndex, DataType = CellValues.String }; Cell lastCell = row.Elements<Cell>().LastOrDefault(); if ((lastCell != null && getColIndexByCellReference(lastCell.CellReference.Value) < colIndex) || lastCell == null) { row.AppendChild(cell); } else { Cell nextCell = row.Elements<Cell>().FirstOrDefault(c => c != null && c.CellReference != null && getColIndexByCellReference(c.CellReference.Value) > colIndex); row.InsertBefore(cell, nextCell); } } return cell; } //根据第一行中的表格内容,通过与给定的字符串进行匹配获取列的索引值 public int GetColIndexByHeaderName(string headerName) { int index = 1; Row row = getRow(1); foreach (Cell cell in row.Elements<Cell>()) { if (cell != null && cell.CellValue != null && cell.CellValue.InnerText != null && cell.CellValue.InnerText == headerName) { return index; } index++; } row.AppendChild(new Cell() { CellValue = new CellValue() { Text = headerName.ToString() } }); return index; } //根据表格的索引值(如A1)获取列的索引值 private int getColIndexByCellReference(string cellReference) { System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex(@"[A-Z]{1,}"); System.Text.RegularExpressions.Match match = regex.Match(cellReference); string value = match.Value; return getColIndexByColName(value); } //根据列的名称(如A)获取列的索引值 private int getColIndexByColName(string colName) { int index = 0; char[] names = colName.ToCharArray(); int length = names.Length; for (int i = 0; i < length; i++) { index += (names[i] - begin) * (int)Math.Pow(26, length - i - 1); } return index; } //根据列的索引值获取列名(如A) private string getColNameByColIndex(int index) { string colName = ""; if (index < 0) { return colName; } while (index > 26) { colName += ((char)(index % 26 + begin)).ToString(); index = index / 26; } colName += ((char)(index % 26 + begin)).ToString(); return colName; } //保存工作表 public void Save() { worksheetPart.Worksheet.Save(); } }}
- Excel文档处理之Open XML
- OPEN XML 生成excel
- xml文档转换Excel
- Open Xml -- Excel文件解析
- 使用Office Open XML将XML数据写入Word2007文档表格之二
- Open XML之我见
- openpyxl 处理 excel 文档学习之workbook及worksheet学习
- C# 处理XML文档
- 处理XML文档
- Linq处理XML文档
- javascript xml 文档处理
- SAX --- 处理 XML 文档
- 使用XML创建Excel文档
- 使用XML创建Excel文档
- 如何操作 Office Open XML 格式文档
- 如何:修改 Office Open XML 文档【转载】
- Office Open XML 打印Word文档目录
- Open Xml - 向文档中添加文本
- User Interest Profiling from User Generated Visual Content----论文笔记
- word怎么转换成pdf文档——两种转换方法分享
- JavaScript学习——web通信长连接
- [hdu1561] The more, The Better 【树形DP】
- openSuse linux下安装升级ftp服务
- Excel文档处理之Open XML
- Linux系统如何查看及修改文件读写权限
- Android 基于Message的进程间通信 Messenger完全解析
- Eclipse中的Web项目自动部署到Tomcat
- Python的“绑定机制”(self)
- spark 的相关配置
- iOS学习(三)Objective-C 类的声明
- Android性能优化 浅析
- Android Viewflipper详解。。