因應國發會推動ODF-CNS15251格式,所有有資料交換的電子文書格式,亦須逐漸改以ODF格式為主。 在ODF中,對應Excel的檔案格式是.ODS。
要讀入資料,流程大概是:
1.將檔案讀入寫到某暫存目錄
2.將該檔案資料流讀出來,解壓縮,提取當中的 content.xml
程式參考自Gunnar Peipman的範例。
http://gunnarpeipman.com/2012/08/reading-opendocument-spreadsheets-using-c/
3.利用Linq to XML 把當中的資料列、儲存格讀出來,轉換格式以供後續使用。
※範例中的Uploader方法只是為了上傳與取得檔名,請用您自己的程式替代,以免無法執行。
※範例最下方 還有一個 class 叫做 ODFParser,用來解析出ODF壓縮檔內的xml,
它用到ICSharpCode.SharpZipLib.Zip 這個套件,但是執行效率似乎不佳。
實作
一、前端表單
<form action="@Url.Action("TestImport")" method="post" enctype="multipart/form-data">
<input id="File" name="File" type="file" />
<input id="Submit1" type="submit" value="submit" />
</form>
二、在MVC的controller內實作此功能
前端表單Post給ActionResult TestImport,接收資料。在MVC內接收檔案需使用 HttpPostedFileBase類別接收檔案,不然不會動。
需要引入:
using System.IO;
using System.Xml.Linq;
using System.Text;
public ActionResult TestImport(HttpPostedFileBase file)
{
//檢查
if (file==null)
{
return View();
}
if (file.ContentLength ==0)
{
ViewBag.Message = "沒有收到檔案";
return View();
}
string filename = "";
string[] extlist = { ".ods" };
string ErrMessage = "";
//檔案寫入
Uploader up = new Uploader();
try
{
filename = up.UploadToDic(file, "c://Temp//", extlist, 6);
}
catch (Exception ex)
{
ErrMessage = ex.Message;
}
if (ErrMessage != "")
{
ViewBag.Message = ErrMessage;
return View();
}
else
{
ViewBag.Message = filename;
}
//檔案解析
string XMLText = "";
//檔案解析,呼叫解壓縮Libiary將資料解出
byte[] bfile;
bfile = null;
using (FileStream fs = new FileStream("c://Temp//" + filename, FileMode.Open))
{
bfile = new byte[fs.Length];
fs.Read(bfile, 0, bfile.Length);
//要加這一行,不然會出現 head EOF 的錯誤
fs.Position = 0;
XMLText = ODFParser.GetContentXml(fs);
//不需要刻意close
//fs.Flush();
//fs.Close();
}
//用Linq讀出最大筆數
int MaxRecords = 1500;
var doc = XDocument.Parse(XMLText);
var rows = doc.Descendants("{urn:oasis:names:tc:opendocument:xmlns:table:1.0}table-row").Skip(1).Take(MaxRecords);
StringBuilder total = new StringBuilder();
//逐列解析
foreach (var row in rows)
{
var cells = (from c in row.Descendants()
where c.Name == "{urn:oasis:names:tc:opendocument:xmlns:table:1.0}table-cell"
select c).ToList();
var count = cells.Count;
//處理空白列
if (cells.Count > 16)
{
StringBuilder sb = new StringBuilder();
for (var i = 0; i < count; i++)
{
var cell = cells[i];
string thisValue = cell.Value;
sb.Append(thisValue + ";");
}
total.Append(sb.ToString() + "<br>");
}
else {
break;
}
}
ViewBag.context = total.ToString();
return View();
}
解出XML,需要用到SharpZipLib這個套件。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.IO;
using System.Xml;
using System.Xml.Linq;
//引用SharpZipLib
using ICSharpCode.SharpZipLib.Zip;
public class ODFParser
{
/// <summary>
/// 解出ODS內的XML檔案
/// </summary>
/// <param name="fileStream"></param>
/// <returns></returns>
public static string GetContentXml(Stream fileStream)
{
var contentXml = "";
using (var zipInputStream = new ZipInputStream(fileStream))
{
ZipEntry contentEntry = null;
while ((contentEntry = zipInputStream.GetNextEntry()) != null)
{
if (!contentEntry.IsFile)
continue;
if (contentEntry.Name.ToLower() == "content.xml")
break;
}
if (contentEntry.Name.ToLower() != "content.xml")
{
throw new Exception("Missing content.xml");
}
var bytesResult = new byte[] { };
var bytes = new byte[2000];
var i = 0;
while ((i = zipInputStream.Read(bytes, 0, bytes.Length)) != 0)
{
var arrayLength = bytesResult.Length;
Array.Resize<byte>(ref bytesResult, arrayLength + i);
Array.Copy(bytes, 0, bytesResult, arrayLength, i);
}
contentXml = System.Text.Encoding.UTF8.GetString(bytesResult);
}
return contentXml;
}
}
沒有留言:
張貼留言