不靠GridView,動態匯出Word檔

不靠GridView,動態匯出Word檔

今天遇到了必須將資料匯出成doc檔

上網查了很久,但大多數的資料都是靠GridView來完成匯出的動作

不然就是使用元件來做,搜尋了老半天,突然看到藍色小舖這篇文章

http://www.blueshop.com.tw/board/show.asp?subcde=BRD20071029161539W2I

雖然跟我要用的word沒啥關係,但突然有了靈感,要是word也能存成xml檔

我再利用replace換掉我要的資料,那不就有辦法動態產生了嗎?

馬上開始紀錄今天的心得。

首先先開一個word檔,最好是有表格的,完成之後才會感動

105467d7db1044d596f4dbb4e1db0aaa

內容大概是這樣,然後另存新檔為Xml

8884b639cd14491a93ff1d6a7c670cc3

存完檔之後,用一個好一點的編輯器打開稍微看一下(拜託請不要用記事本,看了眼睛會花)

我用vs2010開,還可以排個版,看起來比較順眼

6ac3a0e80f484c06959b1107da430c36

打開後可以看到就是一堆tag加屬性,內容也不用太在乎,反正我不care。

知道檔案格式之後,再回到本來的word檔,把我們預計要替換掉的文字,更換一下(最好換成不會重複的)

我把內容改成這樣

c2c605880a36460d87c4e2c26076c325

存檔之後,再開XML來看,搜尋"動態Language” 檢查一下有沒有正確

 

ba1f7c114bf349e5993e2b15cc216908

很好,這次沒有錯。

但我今天下午在試驗的時候,有時候明明是同一句話,卻會分成兩個階層的tag,這時候只好

手動自己修正xml檔囉。還好階層都滿明確的(因為有排版過),所以也不會很難。

準備工作完成之後,開始寫Code

觀念很簡單,就是讀這隻Xml檔,然後用replace換掉我們要換的文字,再寫出成doc就好

首先開個新table,欄位及資料如下

14d5b5a1fc374f6996373f629cdea625

接著開始寫Code

        {


            Response.Clear();
            Response.AddHeader("content-disposition", "attachment;filename=test.doc");//test是word的檔名
            Response.ContentEncoding = System.Text.Encoding.GetEncoding("utf-8");     //編碼utf-8
            Response.ContentType = "application/vnd.ms-word";                         //讓瀏覽器知道是word檔
            Response.Charset = "";

            string myDoc = "";
            StreamReader sr = new StreamReader(Server.MapPath("~/App_Data/sample.xml"));//檔案放在App_Data裡面
            
            myDoc = sr.ReadToEnd();      //從頭讀到尾

            sr.Close();

            //下面開始抓資料

            MyDataContext db = new MyDataContext();
            var data = db.ExportWords.FirstOrDefault();

            if (data != null)
            {
                //將抓到的資料,替換掉我們剛剛設的文字
                myDoc = myDoc.Replace("動態Language", data.Language);
                myDoc = myDoc.Replace("動態Read", data.LanguageRead);
                myDoc = myDoc.Replace("動態Write", data.LanguageWrite);
                myDoc = myDoc.Replace("動態Speak", data.LanguageSpeak);
                myDoc = myDoc.Replace("動態Listen", data.LanguageListen);
               
            }
            //寫出
            Response.Write(myDoc);
            Response.End();

            return View();
        }

簡單吧,完成之後執行,就是下載doc檔,打開內容就已經更換掉囉

1cf9fc8580d644318de85f9c2f614b24

dad6976e0a11432fb5920011d1a23758

這樣就達到我的目的啦,但...如果要多筆的話怎麼辦呢?

這時候又要去看一下Xml檔,去觀察一下xml的階層關係,

找出重複的地方剪下存到另一個檔案(我是存成repeat.txt,要注意的是,記得編碼存成utf-8)

,原來的地方用另一段話取代

repeat.txt

9332e900634d450c904a782798b9c344

 

原來的xml的地方,我用"!重複的部分!" 取代

sample.xml

abf0431f05064a708c97dafd733d4163

 

接下來的Code,就是先讀剛剛另外存的重複的檔,跑迴圈替換掉內容,再用字串相加

        {
            MyDataContext db = new MyDataContext();
            var data = db.ExportWords;

            Response.Clear();
            Response.AddHeader("content-disposition", "attachment;filename=test.doc");//word檔名
            Response.ContentEncoding = System.Text.Encoding.GetEncoding("utf-8");
            Response.ContentType = "application/vnd.ms-word";
            Response.Charset = "";

            string myXML = "";
            string myText = "";

            StreamReader srXML = new StreamReader(Server.MapPath("~/App_Data/sample.xml"));
            myXML = srXML.ReadToEnd();
            srXML.Close();

            //讀出剛剛建立的text,裡頭放等等要重複利用的xml
            StreamReader srText = new StreamReader(Server.MapPath("~/App_Data/repeat.txt"));
            myText = srText.ReadToEnd();
            srText.Close();


            if (data != null)
            {
                StringBuilder 最後要替代掉的字串 = new StringBuilder();

                foreach (var item in data)
                {
                    //先把讀出的xml複製一份,接著開始改
                    string tempdata = myText;
                    tempdata = tempdata.Replace("動態Language", item.Language);
                    tempdata = tempdata.Replace("動態Read", item.LanguageRead);
                    tempdata = tempdata.Replace("動態Write", item.LanguageWrite);
                    tempdata = tempdata.Replace("動態Speak", item.LanguageSpeak);
                    tempdata = tempdata.Replace("動態Listen", item.LanguageListen);
                    //改完加到最後的字串裡面
                    最後要替代掉的字串.Append(tempdata);

                }
                //最後替代掉最一開始的那個xml檔"!重複的部分!"
                myXML = myXML.Replace("!重複的部分!" , 最後要替代掉的字串.ToString());

            }
            Response.Write(myXML);
            Response.End();

            return RedirectToAction("Index");

        }

完成之後看看結果。

7017f74dc39d49c2bdc7f6849ebd70aa

這樣就成功啦! 是不是超簡單。就是簡單的讀檔,替換,寫出而已。

也許我用的是比較笨的方法,聽同事說,轉存成html也可以,我剛試了一下,果然沒錯

而且看html的階層跟屬性更清楚。

用這個方法,要替換圖片應該也做得到,明天再來試試看!