關於Docx套版列印功能程式 轉貼

  • 1904
  • 0

轉載自黑暗執行緒:https://blog.darkthread.net/blog/openxml-template-parser 個人學習紀錄

前幾天又有網友問起【雛型】Docx套版列印功能試作的程式範例。

當時文章發佈後,網友ABC, alan也問過何時釋出的問題。當時的考量是,我完成的只是PoC(Proof of Concept),尚非經實務驗證可行的解決方案,況且當下專案正式上線在即(文章中寧可用較簡陋的1.0正式版,也不要用2.0 CTP可見一斑),很快就可以檢驗這個做法的彈性及可靠度,等通過考驗再公佈也不遲。無奈,世事多變化,研究出套版方法沒多久,User調整了作業流程規劃,系統不再需要自行套版產生docx... orz 而後來,在其他專案也沒能再遇到實際上場的機會。就這樣,多年下來,這套做法一直維持在PoC階段,只能終年長坐冷板凳,抑鬱不得志,每日藉酒澆愁...

適逢網友再問起,就決定把當時的PoC程式分享出來,供需要參考的朋友自行取用。但必須聲明,這個版本只是PoC,沒實際上過戰場,也跟懶人包不同,在程式考量周延性或完整度上可能仍有欠缺,大家在應用時可想像成是小麥種子,而不是烤好的麵包。也很歡迎有將它實際應用在專案上的朋友能回饋分享自己裁種、收割、烘焙的心得~

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DocumentFormat.OpenXml.Packaging;
using System.IO;
 
namespace Darkthread.OpenXml
{
    /// <summary>
    /// Ver 1.0 By Jeffrey Lee, 2009-07-29
    /// </summary>
    public class DocxHelper
    {
        /// <summary>
        /// Replace the parser tags in docx document
        /// </summary>
        /// <param name="oxp">OpenXmlPart object</param>
        /// <param name="dct">Dictionary contains parser tags to replace</param>
        private static void parse(OpenXmlPart oxp, Dictionary<string, string> dct)
        {
            string xmlString = null;
            using (StreamReader sr = new StreamReader(oxp.GetStream()))
            { xmlString = sr.ReadToEnd(); }
            foreach (string key in dct.Keys)
                xmlString = xmlString.Replace("[$" + key + "$]", dct[key]);
            using (StreamWriter sw = new StreamWriter(oxp.GetStream(FileMode.Create)))
            { sw.Write(xmlString); }
        }
 
        /// <summary>
        /// Parse template file and replace all parser tags, return the binary content of
        /// new docx file.
        /// </summary>
        /// <param name="templateFile">template file path</param>
        /// <param name="dct">a Dictionary containing parser tags and values</param>
        /// <returns></returns>
        public static byte[] MakeDocx(string templateFile, Dictionary<string, string> dct)
        {
            string tempFile = Path.GetTempPath() + ".docx";
            File.Copy(templateFile, tempFile);
 
            using (WordprocessingDocument wd = WordprocessingDocument.Open(
                tempFile, true))
            {
                //Replace document body
                parse(wd.MainDocumentPart, dct);
                foreach (HeaderPart hp in wd.MainDocumentPart.HeaderParts)
                    parse(hp, dct);
                foreach (FooterPart fp in wd.MainDocumentPart.FooterParts)
                    parse(fp, dct);
            }
            byte[] buff = File.ReadAllBytes(tempFile);
            File.Delete(tempFile);
            return buff;
        }
 
    }
}

PS: 雖然當時程式是配合SDK 1.0寫的,經實測這段程式可配合Open XML Format SDK 2.0運作無誤,專案要參照DocumentFormat.OpenXml以及WindowsBase,即可順利編譯、執行。