C#調(diào)用OpenXml操作word文檔的基本用法介紹
使用圖形類Drawing不僅可以將圖片保存到word文檔,還能將圖表、表格等數(shù)據(jù)保存到word文檔,關(guān)鍵就在于其子類型GraphicData支持關(guān)聯(lián)多種類型的圖形數(shù)據(jù),本文記錄以嵌入式布局方式向word中插入圖表的基本用法。
主要代碼如下所示:
using A = DocumentFormat.OpenXml.Drawing;
using C=DocumentFormat.OpenXml.Drawing.Charts;
using DW = DocumentFormat.OpenXml.Drawing.Wordprocessing;
if(cbInsertChart.Checked)
{
ChartPart chartPart = mainPart.AddNewPart<ChartPart>();
string chartPartId = mainPart.GetIdOfPart(chartPart);
Drawing drawing = CreateChartDrawing(chartPartId, chartPart);
run.Append(drawing);
}
public Drawing CreateChartDrawing(string relationshipId, ChartPart chartPart)
{
var chartSpace = new C.ChartSpace();
chartSpace.AddNamespaceDeclaration("c", "http://schemas.openxmlformats.org/drawingml/2006/chart");
chartSpace.AddNamespaceDeclaration("r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships");
chartSpace.AppendChild(new C.EditingLanguage { Val = "zh-CN" });
var chart = new C.Chart();
chart.AppendChild(new C.AutoTitleDeleted { Val = true });
var plotArea = new C.PlotArea();
var barChart = new C.BarChart(
new C.BarDirection { Val = C.BarDirectionValues.Column },
new C.BarGrouping { Val = C.BarGroupingValues.Clustered },
new C.VaryColors { Val = true }
);
var series = new C.BarChartSeries(
new C.Index { Val = 0 },
new C.Order { Val = 0 },
new C.SeriesText(new C.NumericValue("測試數(shù)據(jù)"))
);
series.AppendChild(new C.CategoryAxisData(
new C.StringLiteral(
new C.PointCount { Val = 4 },
new C.StringPoint { Index = 0, NumericValue = new C.NumericValue("A") },
new C.StringPoint { Index = 1, NumericValue = new C.NumericValue("B") },
new C.StringPoint { Index = 2, NumericValue = new C.NumericValue("C") },
new C.StringPoint { Index = 3, NumericValue = new C.NumericValue("D") }
)
));
series.AppendChild(new C.Values(
new C.NumberLiteral(
new C.PointCount { Val = 4 },
new C.NumericPoint { Index = 0, NumericValue = new C.NumericValue("10") },
new C.NumericPoint { Index = 1, NumericValue = new C.NumericValue("20") },
new C.NumericPoint { Index = 2, NumericValue = new C.NumericValue("30") },
new C.NumericPoint { Index = 3, NumericValue = new C.NumericValue("40") }
)
));
barChart.AppendChild(series);
// 坐標軸
var catAxis = new C.CategoryAxis(
new C.AxisId { Val = 100 },
new C.Scaling(new C.Orientation { Val = C.OrientationValues.MinMax }),
new C.AxisPosition { Val = C.AxisPositionValues.Bottom },
new C.CrossingAxis { Val = 200 },
new C.Crosses { Val = C.CrossesValues.AutoZero },
new C.TickLabelPosition { Val = C.TickLabelPositionValues.NextTo }
);
var valAxis = new C.ValueAxis(
new C.AxisId { Val = 200 },
new C.Scaling(new C.Orientation { Val = C.OrientationValues.MinMax }),
new C.AxisPosition { Val = C.AxisPositionValues.Left },
new C.CrossingAxis { Val = 100 },
new C.Crosses { Val = C.CrossesValues.AutoZero },
new C.TickLabelPosition { Val = C.TickLabelPositionValues.NextTo },
new C.MajorTickMark { Val = C.TickMarkValues.None },
new C.MinorTickMark { Val = C.TickMarkValues.None }
);
// 讓BarChart引用坐標軸ID
barChart.AppendChild(new C.AxisId { Val = 100 });
barChart.AppendChild(new C.AxisId { Val = 200 });
plotArea.Append(barChart, catAxis, valAxis);
chart.Append(plotArea);
chartSpace.AppendChild(chart);
chartSpace.Save(chartPart);
return new Drawing(
new DW.Inline(
new DW.Extent { Cx = 6000000, Cy = 4000000 },
new DW.EffectExtent { LeftEdge = 0L, TopEdge = 0L, RightEdge = 0L, BottomEdge = 0L },
new DW.DocProperties { Id = 1, Name = "Chart 1" },
new DW.NonVisualGraphicFrameDrawingProperties(
new A.GraphicFrameLocks { NoChangeAspect = true }
),
new A.Graphic(
new A.GraphicData(
new C.ChartReference { Id = relationshipId }
)
{ Uri = "http://schemas.openxmlformats.org/drawingml/2006/chart" }
)
)
);
}
下面的截圖是程序運行效果及word文檔的內(nèi)容截圖。


知識擴展:
使用 Microsoft 官方提供的 Open XML SDK,我們可以直接在 C# 代碼中創(chuàng)建和修改 Word (.docx) 文件,整個過程不依賴本地安裝的 Microsoft Office 軟件,非常適合在服務(wù)器環(huán)境或需要自動化批量處理文檔的場景中使用。
核心概念:Open XML SDK 如何表示 Word 文檔?
在開始編寫代碼之前,先了解一下 Open XML SDK 中三個最基本的概念,這會幫助你更好地理解后續(xù)的代碼。
| 核心元素 | 作用 | 類比 | 如何操作? |
|---|---|---|---|
| 段落 (Paragraph) | 代表文檔中的一個段落,是文本的基本容器 | 像是搭積木時的“塊” | 通常需要配合 ParagraphProperties 來設(shè)置樣式。 |
| 文本運行 (Run) | Run 是 Paragraph 內(nèi)部的子元素,表示一段具有相同格式的連續(xù)文本。 | 一塊積木上可能有不同的顏色,Run 就像給這塊積木的某個部分涂上特定的顏色。 | 想要改變字體、大小、顏色,都是操作 Run 的屬性,而不是直接去改文本本身。 |
| 文本 (Text) | Run 內(nèi)部真正的文本載體 | 積木本身 | 文本內(nèi)容就是這個類構(gòu)造函數(shù)里傳進去的字符串。 |
理解了這三個核心元素間的層級關(guān)系(Paragraph -> Run -> Text),就能明白如何構(gòu)建文檔的基本內(nèi)容了。
快速上手:從安裝開始
準備環(huán)境: 首先創(chuàng)建一個 C# 項目(控制臺應(yīng)用、Web API 等均可)。
安裝核心庫: 在 Visual Studio 中使用 NuGet 包管理器,搜索并安裝 DocumentFormat.OpenXml。
引入命名空間: 在需要操作 Word 的代碼文件頂部,添加以下 using 語句。
using DocumentFormat.OpenXml; using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Wordprocessing; using System.Text.RegularExpressions;
文檔基本操作:打開、創(chuàng)建與保存
Open XML SDK 的核心是 WordprocessingDocument 類,它代表了一個完整的 Word 文檔包。
打開現(xiàn)有文檔進行編輯:使用 Open() 方法,第二個參數(shù)設(shè)為 true 表示以讀/寫模式打開文件。
// 打開文檔路徑下文件進行編輯(使用 using 確保資源自動釋放)
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(@"C:\test.docx", true))
{
// 檢查文檔對象是否為空,避免后續(xù)操作出錯
if (wordDoc == null) throw new ArgumentNullException(nameof(wordDoc));
// ... 在此處進行編輯操作
}創(chuàng)建一個新文檔:使用 Create() 方法,此時需要顯式創(chuàng)建主文檔部件。
// 創(chuàng)建一個全新的 Word 文檔
using (WordprocessingDocument wordDoc = WordprocessingDocument.Create(@"C:\new.docx", WordprocessingDocumentType.Document))
{
// 新文檔必須手動添加主文檔部件,否則 Word 無法打開[reference:10]
MainDocumentPart mainPart = wordDoc.AddMainDocumentPart();
// 初始化文檔結(jié)構(gòu):Document -> Body
mainPart.Document = new Document();
mainPart.Document.Body = new Body();
// ... 在此處向 Body 中添加內(nèi)容
}注意:using 語句會自動處理資源的釋放和文檔的保存。如果一個新創(chuàng)建的文檔沒有添加 MainDocumentPart,Word 在打開時會提示文件損壞。
文本操作:添加與格式化
掌握了上面的基礎(chǔ),就可以嘗試向文檔中添加內(nèi)容了。
添加普通文本段落
// 獲取文檔的 Body 對象
Body body = wordDoc.MainDocumentPart.Document.Body;
// 創(chuàng)建一個新段落,必須顯式包含 Run 和 Text 子元素[reference:14]
Paragraph newParagraph = new Paragraph(
new ParagraphProperties(), // 段落屬性(如對齊方式)
new Run(
new Text("這是新添加的文本內(nèi)容。")
)
);
// 將新段落追加到 Body 末尾
body.AppendChild(newParagraph);注意:Open XML 中構(gòu)造段落的正確方式是 Paragraph 內(nèi)必須包含至少一個 Run 元素,Run 內(nèi)必須包含 Text 元素,缺一不可。
添加帶格式的文本(加粗、顏色等)格式設(shè)置作用于 Run 層級,通過 RunProperties 類來實現(xiàn)。
// 創(chuàng)建一個帶格式的文本運行
Run formattedRun = new Run();
// 1. 設(shè)置運行屬性
RunProperties runProperties = new RunProperties();
runProperties.Bold = new Bold() { Val = true }; // 加粗
runProperties.Color = new Color() { Val = "FF0000" }; // 紅色
runProperties.FontSize = new FontSize() { Val = "28" }; // 字號(28 相當于 14 號)
formattedRun.AppendChild(runProperties);
// 2. 添加文本內(nèi)容
formattedRun.AppendChild(new Text("這是加粗、紅色的文本。"));表格操作:創(chuàng)建簡單表格
在 Open XML SDK 中,操作表格需要更嚴謹?shù)刈裱短捉Y(jié)構(gòu)。其最簡結(jié)構(gòu)如下:
Body -> Paragraph -> Table -> TableRow -> TableCell -> Paragraph -> Run -> Text
// 創(chuàng)建一個 3 行 2 列的簡單表格
Table table = new Table();
// 1. 添加表格屬性(例如設(shè)置寬度)
TableProperties tblProp = new TableProperties();
TableWidth tableWidth = new TableWidth() { Width = "5000", Type = TableWidthUnitValues.Dxa };
tblProp.AppendChild(tableWidth);
table.AppendChild(tblProp);
for (int i = 0; i < 3; i++)
{
TableRow row = new TableRow();
for (int j = 0; j < 2; j++)
{
TableCell cell = new TableCell();
// **注意**:每個 TableCell 必須包含至少一個 Paragraph 才能顯示內(nèi)容[reference:17]
cell.AppendChild(new Paragraph(new Run(new Text($"第{i+1}行, 第{j+1}列"))));
row.AppendChild(cell);
}
table.AppendChild(row);
}
// 將表格添加到 Body 中
wordDoc.MainDocumentPart.Document.Body.AppendChild(table);注意:上文示例中包含更完整的表格樣式(如邊框)設(shè)置,以及合并單元格的實現(xiàn)方式。
圖片操作:插入圖片到文檔
插入圖片是稍顯復(fù)雜的操作,因為它涉及在包中添加新的部件。
// 插入圖片的完整過程
// 1. 添加圖片部件
// 使用絕對路徑讀取圖片文件流[reference:19]
using (FileStream fs = new FileStream(@"C:\test.png", FileMode.Open))
{
// AddImagePart 時指定的 ImagePartType 必須嚴格匹配圖片文件類型[reference:20]
ImagePart imagePart = wordDoc.MainDocumentPart.AddImagePart(ImagePartType.Png);
imagePart.FeedData(fs);
string imagePartId = wordDoc.MainDocumentPart.GetIdOfPart(imagePart);
// 2. 在文檔正文中創(chuàng)建引用圖片的 XML 結(jié)構(gòu)
// 此處構(gòu)造 Drawing 元素的相關(guān)代碼較長,具體可參考官方文檔,實現(xiàn)相對復(fù)雜
}注意:插入圖片時,圖片文件路徑必須是運行時能訪問到的絕對路徑。完整的 Drawing 元素代碼較復(fù)雜,建議參考官方詳細示例。
讀取操作:提取文檔內(nèi)容
Open XML SDK 同樣適用于需要從 Word 文檔中提取信息的場景。
/// <summary>
/// 遍歷文檔所有段落,讀取其純文本內(nèi)容
/// </summary>
public static List<string> ReadAllParagraphs(string filePath)
{
List<string> allTexts = new List<string>();
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(filePath, false)) // 第二個參數(shù)為 false 表示只讀
{
Body body = wordDoc.MainDocumentPart.Document.Body;
// 遍歷 Body 下所有 Paragraph 元素
foreach (Paragraph para in body.Elements<Paragraph>())
{
// 獲取該段落內(nèi)所有 Run 下的 Text 元素的文本并拼接
string paragraphText = string.Join("", para.Descendants<Text>().Select(t => t.Text));
if (!string.IsNullOrWhiteSpace(paragraphText))
{
allTexts.Add(paragraphText);
}
}
}
return allTexts;
}注意:對于含有多級表格或復(fù)雜嵌套結(jié)構(gòu)的文檔,可能需要使用遞歸或更精確定位的方式來提取特定區(qū)域的文本。
到此這篇關(guān)于C#調(diào)用OpenXml操作word文檔的基本用法介紹的文章就介紹到這了,更多相關(guān)C# OpenXml操作word內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺析C#中數(shù)組,ArrayList與List對象的區(qū)別
在C#中,當我們想要存儲一組對象的時候,就會想到用數(shù)組,ArrayList,List這三個對象了。那么這三者到底有什么樣的區(qū)別呢2013-07-07
C#中實現(xiàn)輸入漢字獲取其拼音(漢字轉(zhuǎn)拼音)的2種方法
這篇文章主要介紹了C#中實現(xiàn)輸入漢字獲取其拼音(漢字轉(zhuǎn)拼音)的2種方法,本文分別給出了使用微軟語言包、手動編碼實現(xiàn)兩種實現(xiàn)方式,需要的朋友可以參考下2015-01-01

