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

标签 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()

工作表已创建,但为空:

工作表.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>

最佳答案

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

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

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

worksheetPart.Worksheet <- new Worksheet(new SheetData() :> OpenXmlElement)
...
sheets.Append([sheet :> OpenXmlElement])

关于f# - 无法使用带有 F# (FSharp) 的 OpenXml 附加工作表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5702939/

相关文章:

f# - FsCheck DataGen 为空

c# - F# 等效于 C# 'object' 关键字

f# - 是否可以在 F# 中转发可选参数

c# - 如何在 EPPlus 中对行/列进行分组

c# - 必须在非通用静态类中定义扩展方法 - 从文档中提取 XML

f# - 使用 FAKE,有没有办法获取整个构建日志?

vb.net - Ms Word Addin 中的isolatedStorageException

c# - 如何从 Excel 2010 为所有三个日期兼容性设置生成 SpreasheetML 示例?

html - 富文本格式是否已弃用?

f# - 使用 json.net 和包含 @ 符号的 json 属性反序列化为 F# 类型