无法使用带F#的OpenXml附加工作表(FSharp)

时间:2011-04-18 12:33:54

标签: f# openxml

OpenXml文档中的CreateSpreadsheetWorkbook示例方法确实直接转换为F#。问题似乎是Sheets对象的Append方法。代码执行时没有错误,但生成的xlsx文件缺少应该附加的内部Xml,并且Excel无法读取该文件。我怀疑问题源于将功能性F#结构转换为System.Collections类型,但我没有直接证据。

我在C#和VB.NET(即文档示例)中运行了类似的代码,它完美地执行并创建了一个可读的,完整的xlsx文件。

我知道我可以直接处理XML,但我想了解F#和OpenXml之间不匹配的性质。有什么建议吗?

代码几乎直接来自示例:

namespace OpenXmlLib
open System
open DocumentFormat
open DocumentFormat.OpenXml
open DocumentFormat.OpenXml.Packaging 
open DocumentFormat.OpenXml.Spreadsheet

module OpenXmlXL = 
   // this function overwrites an existing file without warning!
   let CreateSpreadsheetWorkbook (filepath: string) = 
      // Create a spreadsheet document by supplying the filepath.
      // By default, AutoSave = true, Editable = true, and Type = xlsx.
      let spreadsheetDocument = SpreadsheetDocument.Create(filepath, SpreadsheetDocumentType.Workbook)
      // Add a WorkbookPart to the document.
      let workbookpart = spreadsheetDocument.AddWorkbookPart()
      workbookpart.Workbook <- new Workbook()

      // Add a WorksheetPart to the WorkbookPart.
      let worksheetPart = workbookpart.AddNewPart<WorksheetPart>()
      worksheetPart.Worksheet <- new Worksheet(new SheetData())

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

      // Append a new worksheet and associate it with the workbook.
      let sheet = new Sheet() 
      sheet.Id <-  stringValue(spreadsheetDocument.WorkbookPart.GetIdOfPart(worksheetPart))
      //Console.WriteLine(sheet.Id.Value)

      sheet.SheetId <-  UInt32Value(1u)
      // Console.WriteLine(sheet.SheetId.Value)

      sheet.Name <-  StringValue("TestSheet")
      //Console.WriteLine(sheet.Name.Value)


      sheets.Append (sheet)

     // Console.WriteLine("Sheets: {0}", sheets.InnerXml.ToString())

      workbookpart.Workbook.Save()


      spreadsheetDocument.Close()

工作表已创建,但为空:

sheet.xml:

  <?xml version="1.0" encoding="utf-8" ?> 
  <x:worksheet xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main" />

workbook.xml:
  <?xml version="1.0" encoding="utf-8" ?> 
- <x:workbook xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
- <x:sheets>
  <x:sheet name="TestSheet" sheetId="1" r:id="R263eb6f245a2497e" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" /> 
  </x:sheets>
  </x:workbook>

1 个答案:

答案 0 :(得分:16)

问题非常微妙,在您调用Worksheet构造函数和Sheets.Append方法时。这两种方法都是重载的,可以使用seq<OpenXmlElement>或任意数量的单个OpenXmlElement(通过[<System.ParamArray>] / params数组。扭曲是OpenXmlElement类型本身实现了seq<OpenXmlElement>接口。

在C#中,当您调用new Worksheet(new SheetData())时,编译器的重载决策会选择第二个重载,隐式创建包含SheetData值的单元素数组。但是,在F#中,由于SheetData类实现了IEnumerable<OpenXmlElement>,因此选择了第一个重载,它通过枚举{{的内容来创建新的WorkSheet。 1}},这不是你想要的。

要解决此问题,您需要设置调用以便它们使用其他重载(下面的第一个示例)或显式创建单个序列(下面的第二个示例):

SheetData