在Excel保存文档时,如何在编辑后保留OpenXml单元属性?

时间:2015-07-01 04:19:40

标签: c# excel openxml openxml-sdk

我想导出包含数据的Excel文件,以便我的用户可以:

  • 下载Excel文件(从我的程序导出)
  • 编辑文件中的数据
  • 保存
  • 上传Excel文件(将其重新导入我的程序)

基本上我会给他们一个离线文件的经验,如果他们没有任何互联网访问权限,他们就可以编辑(因为我们是一个Web应用程序)

使用OpenXml SDK创建Excel文件时,我使用OpenXmlElement.SetAttribute方法将属性添加到工作表的列,行和单元格中。使用我添加的属性,以便在重新导入时,我可以将编辑的数据与应该存储的位置进行匹配。

我导出的属性是:

  • 数据库ID
  • 原始值(导出时的数据库值,以便在导入时轻松同步)
  • 上次修改导出数据的日期

对于单元格,导出例程如下所示:

var cell = new Cell {
   CellReference = string.Format("{0}{1}", Column.Reference, Row.Index),
   DataType = this.CellDataType
};

foreach (var keyValuePair in this.AttributeDictionary) {
   cell.SetAttribute(new OpenXmlAttribute {
      LocalName = keyValuePair.Key,
      Value = keyValuePair.Value.ToString()
   });
}

此导出正常。在OpenXml Productivity Tool中检查导出的文件时,我可以看到属性已正确添加。在Excel中编辑后保存文件时,不会保留属性。有没有办法告诉Excel保留属性,还是有另一种方法可以最好地保存我需要的数据,以便轻松重新输入数据?

旁边问题:

如果Excel不保留它们,有哪些属性?

1 个答案:

答案 0 :(得分:1)

我认为您不能强制Excel绕过未知的属性,但您可以使用ExtensionListsExtensions添加扩展元素。 Excel将往返这些元素,并设计(据我所知)存储应用程序特定数据,就像您一样。

似乎没有太多关于我可以找到的文档,但是ECMA-376 spec的第3部分提到了扩展。

以下代码将创建一个工作表,其中包含单元格A1中的值和ExtensionList,其中包含一个Extension作为该单元格的子级:

public static void CreateSpreadsheetWorkbook(string filepath)
{
    if (File.Exists(filepath))
        File.Delete(filepath);

    using (SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Create(filepath, SpreadsheetDocumentType.Workbook))
    {
        // Add a WorkbookPart to the document.
        WorkbookPart workbookpart = spreadsheetDocument.AddWorkbookPart();
        workbookpart.Workbook = new Workbook();

        // Add a WorksheetPart to the WorkbookPart.
        WorksheetPart worksheetPart = workbookpart.AddNewPart<WorksheetPart>();

        SheetData sheetData = new SheetData();
        worksheetPart.Worksheet = new Worksheet(sheetData);

        // Add Sheets to the Workbook.
        Sheets sheets = spreadsheetDocument.WorkbookPart.Workbook.AppendChild<Sheets>(new Sheets());

        // Append a new worksheet and associate it with the workbook.
        Sheet sheet = new Sheet()
        {
            Id = spreadsheetDocument.WorkbookPart.
                GetIdOfPart(worksheetPart),
            SheetId = 1,
            Name = "Sheet1"
        };
        sheets.Append(sheet);

        Row row = new Row()
        {
            RowIndex = 1U
        };

        Cell cell = new Cell()
        {
            CellReference = "A1",
            CellValue = new CellValue("A Test"),
            DataType = CellValues.String
        };

        ExtensionList extensions = new ExtensionList();
        Extension extension = new Extension()
            {
                Uri = "Testing1234"
            };
        extensions.AppendChild(extension);
        extension.AddNamespaceDeclaration("ns", "http://tempuri/someUrl");

        cell.AppendChild(extensions);

        row.Append(cell);

        sheetData.Append(row);

        workbookpart.Workbook.Save();

        // Close the document.
        spreadsheetDocument.Close();
    }
}

以下内容将再次读取该值,即使该文件已经通过Excel进行了四舍五入。

public static void ReadSheet(string filename, string sheetName)
{
    using (SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Open(filename, false))
    {
        WorkbookPart workbookPart = spreadsheetDocument.WorkbookPart;
        //get the correct sheet
        Sheet sheet = workbookPart.Workbook.Descendants<Sheet>().Where(s => s.Name == sheetName).First();
        if (sheet != null)
        {
            WorksheetPart worksheetPart = workbookPart.GetPartById(sheet.Id) as WorksheetPart;
            foreach (Cell cell in  worksheetPart.Worksheet.Descendants<Cell>())
            {
                ExtensionList extensions = cell.GetFirstChild<ExtensionList>();
                if (extensions != null)
                {
                    Extension extension = extensions.GetFirstChild<Extension>();
                    if (extension != null)
                    {
                        Console.WriteLine("Cell {0} has value {1}", cell.CellReference, extension.Uri);
                    }
                }
            }
        }
    }
}

输出

  

单元格A1的值为Testing1234

关于你的问题:

  

如果Excel不保留它们,有哪些属性?

我不太确定 - 我使用OpenXmlAttribute类的唯一一次是当我使用SAX方法编写文档时。在这种情况下,您需要明确地将属性与元素一起编写。例如:

List<OpenXmlAttribute> oxa = new List<OpenXmlAttribute>();

//cell reference attribute
oxa.Add(new OpenXmlAttribute("r", "", "A1"));
//cell type attribute
oxa.Add(new OpenXmlAttribute("t", "", "str"));
//write the start element of a cell with the above attributes
oxw.WriteStartElement(new Cell(), oxa);
//write a value to the cell
oxw.WriteElement(new CellValue("Test"));
//write the end element
oxw.WriteEndElement();

我的answer here有一个使用SAX方法的完整示例。