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>
答案 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