2016/7/26

匯入ODS格式的資料 (C# / ODF)



因應國發會推動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;
    }


}


沒有留言:

張貼留言