2011-04-18 149 views
7

OpenXml文檔中的CreateSpreadsheetWorkbook示例方法確實直接轉換爲F#。問題似乎是Sheets對象的Append方法。該代碼執行時沒有錯誤,但生成的xlsx文件缺少應添加的內部Xml,並且Excel無法讀取該文件。我懷疑問題源於功能F#結構轉換爲System.Collections類型,但我沒有直接的證據。無法在F#中使用OpenXml追加工作表(FSharp)

我在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

您可以發佈您的代碼?解壓縮時,xlsx中包含的是什麼?該表格是否已創建,但爲空?是否添加了任何refences? – Nobody 2011-04-18 12:36:07

+2

看起來您使用的是此MSDN頁面中的示例代碼:http://msdn.microsoft.com/en-us/library/ff478153.aspx。我真的懷疑這是F#的一個問題 - 你的代碼看起來不錯,但是你可能在MSDN上找到了一個錯誤的例子。看看你是否可以在C#項目中逐字使用示例代碼,你會得到不同的結果嗎? – Juliet 2011-04-18 14:30:53

+0

感謝kvb。演員工作。我已經在Sheets和Sheet對象上試過了這個,但是我從來沒有想到SheetData對象是可疑的。再次感謝。 – 2011-04-18 20:54:12

回答

16

的問題是非常微妙的,並且在您撥打Worksheet構造函數和Sheets.Append方法。這兩種方法都過載,可以採用seq<OpenXmlElement>或任意數量的個人OpenXmlElement(通過[<System.ParamArray>]/params陣列)。其難點在於OpenXmlElement類型本身實現了seq<OpenXmlElement>接口。

在C#中,當您調用new Worksheet(new SheetData())時,編譯器的重載決議選取第二個重載,隱式創建一個包含SheetData值的單元素數組。但是,在F#中,因爲SheetData類實現了IEnumerable<OpenXmlElement>,所以選擇了第一個過載,它通過枚舉SheetData內容來創建新的WorkSheet,這不是您想要的。

要解決這個問題,你需要設置你的電話,讓他​​們用其他的過載(下面第一個例子)或明確創建一個單獨序列(下圖2爲例):

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

+1:哦哇,這是晦澀:) – Juliet 2011-04-18 19:52:26

+1

+1:謝謝。這真的幫了我很大的忙,我在DocumentFormat.OpenXml的MSDN上繼續使用這個例子,並且看不出有什麼問題! – Goody 2015-06-01 09:10:07