試了用OpenXML SDK讀取docx中的表格內容,發現挺直覺易用的。基本上取得文件的Body後,透過Elements<T>可以取得Table、TableRow、TableCell等組成,從TableCell中找出Paragraph再取其InnerText,就可得到儲存格的內容。

簡單示範如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DocumentFormat.OpenXml.Wordprocessing;
using DocumentFormat.OpenXml.Packaging;
 
namespace OpenXMLSDK
{
    class Program
    {
        static void Main(string[] args)
        {
            using (WordprocessingDocument doc
                = WordprocessingDocument.Open(
                @"C:\Users\l\Documents\BCG.docx", false))
            {
                //取出第一個Table
                Table tbl = 
                    doc.MainDocumentPart.Document.Body
                    .Elements<Table>().First();
                //取得TableRow陣列
                var rows = tbl.Elements<TableRow>().ToArray();
                for (int i = 0; i < rows.Length; i++)
                {
                    //取得TableRow的TableCell陣列
                    var cells = rows[i].Elements<TableCell>()
                                .ToArray();
                    //顯示每列的內容
                    for (int j = 0; j < cells.Length; j++)
                        Console.WriteLine("Row:{0} Cell:{1} Value={2}",
                            i, j,
                            cells[j].Elements<Paragraph>().First().InnerText);
                }
            }
            Console.Read();
        }
    }
}

執行結果:

Row:0 Cell:0 Value=問題兒童
Row:0 Cell:1 Value=明星
Row:1 Cell:0 Value=落水狗
Row:1 Cell:1 Value=金牛

覺得透過Elements<T>來找Table階層還不夠直覺,所以試著用Extension Method再改良一下,生出GetTables(), GetTableRows(), GetTableCells(), GetTableCellContent()五個Method,取代原本的Elements<T>寫法:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DocumentFormat.OpenXml.Wordprocessing;
using DocumentFormat.OpenXml.Packaging;
 
namespace OpenXMLSDK
{
    class Program
    {
        static void Main(string[] args)
        {
            using (WordprocessingDocument doc
                = WordprocessingDocument.Open(
                @"C:\Users\l\Documents\BCG.docx", false))
            {
                //取出第一個Table
                Table tbl =
                    doc.MainDocumentPart.Document.Body
                    .GetTables()[0];
                //取得TableRow陣列
                var rows = tbl.GetTableRows();
                for (int i = 0; i < rows.Length; i++)
                {
                    //取得TableRow的TableCell陣列
                    var cells = rows[i].GetTableCells();
                    //顯示每列的內容
                    for (int j = 0; j < cells.Length; j++)
                        Console.WriteLine("Row:{0} Cell:{1} Value={2}",
                            i, j,
                            cells[j].GetTableCellContent());
                }
            }
            Console.Read();
        }
    }
 
    public static class DocxTableExt
    {
        public static Table[] GetTables(this Body body) {
            return body.Elements<Table>().ToArray();
        }
        public static TableRow[] GetTableRows(this Table tbl)
        {
            return tbl.Elements<TableRow>().ToArray();
        }
        public static TableCell[] GetTableCells(this TableRow tr)
        {
            return tr.Elements<TableCell>().ToArray();
        }
        public static string GetTableCellContent(this TableCell td)
        {
            return string.Join("\n",
                td.Elements<Paragraph>().Select(o => o.InnerText).ToArray());
        }
    }
}

以前整合Word文件多是透過VBA Word巨集,總覺得放著C#跟.NET Library不用,回頭用Visual Basic讓人心情鬱悶。OpenXML SDK的出現,提供了一個很有效率的新選擇,大家不妨試試。


Comments

# by DeltaCat

可惜,只能是 OFFICE 2007 及更高版本. 但是,目前普及的还是 OFFICE2003啊

# by Ian

Hi 黑暗大: 請教您一個問題 我有個docx檔 以Document.Body.Elements<Text>是否無法直接取得在Body裡<w:t>的所有Text內容,必須依階層一層層取得呢?

Post a comment