OpenXML操作word
OpenXML概述
项目中经常需要操作word,之前的方式是采用COM接口,这个接口很不稳定,经常报错。现在开始采用OpenXML。OpenXML(OOXML)是微软在Office 2007中提出的一种新的文档格式,Office 2007中的Word、Excel、PowerPoint默认均采用OpenXML格式 。
OpenXml相对于用MS提供的COM组件来生成WORD,有如下优势:
1.相对于MS 的COM组件,因为版本带来的不兼容问题,及各种会生成WORD半途会崩溃的问题.
2.对比填满一张30多页的WORD来说(包含图,表等),用COM组件来生成会占用20秒,Openxml1秒.
3.MS Word软件太贵了,你的客户装的是开源WORD,如LibreOffice,OpenOffice.这样你就只能用Openxml生成的WORD文档,各种支持MS Word都能打开,避免客户机器上安装MS Word.
4.代码简单。用OpenXML开发word简直太方便了!!!
要做OpenXML的开发,需要了解OpenXML的基本结构。

Open XML SDK 2.0 tool
因为OpenXML的结构比较复杂,开始开发时往往不好入门,摸不清其结构。微软很贴心的提供了一个工具,Open XML SDK Productivity Tool for Microsoft Office。
下载地址
这个工具可以打开任意一个docx的文档,然后Reflect Code,得到整个文档代码,之后怎么操作直接看代码就好了,真是太方便了。
另外这个工具也提供了文档,不清楚的可以查一下文档。
代码示例
我参考上面的工具,写了一个简单的操作word的帮助类。
using System.Collections.Generic;
using System.IO;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using AA = DocumentFormat.OpenXml.Drawing;
using DW = DocumentFormat.OpenXml.Drawing.Wordprocessing;
using PIC = DocumentFormat.OpenXml.Drawing.Pictures;
namespace Wisdombud.Office
{
public static class OpenXmlUtil
{
/// <summary>
/// 按书签替换图片
/// </summary>
/// <param name="filePath"></param>
/// <param name="picPath"></param>
/// <param name="bm"></param>
/// <param name="x">宽度厘米</param>
/// <param name="y">高度厘米</param>
/// <param name="type"></param>
public static void ReplaceBMPicture(string filePath, string picPath, string bm)
{
RemoveBookMarkContent(filePath, bm);
InsertBMPicture(filePath, picPath, bm);
}
/// <summary>
/// 按书签替换图片
/// </summary>
/// <param name="filePath"></param>
/// <param name="picPath"></param>
/// <param name="bm"></param>
/// <param name="x">宽度厘米</param>
/// <param name="y">高度厘米</param>
/// <param name="type"></param>
public static void ReplaceBMPicture(string filePath, string picPath, string bm, long x, ImagePartType type)
{
RemoveBookMarkContent(filePath, bm);
InsertBMPicture(filePath, picPath, bm, x, type);
}
/// <summary>
/// 按书签替换图片
/// </summary>
/// <param name="filePath"></param>
/// <param name="picPath"></param>
/// <param name="bm"></param>
/// <param name="x">宽度厘米</param>
/// <param name="y">高度厘米</param>
/// <param name="type"></param>
public static void ReplaceBMPicture(string filePath, string picPath, string bm, long x, long y, ImagePartType type)
{
RemoveBookMarkContent(filePath, bm);
InsertBMPicture(filePath, picPath, bm, x, y, type);
}
/// <summary>
/// 按书签插入图片
/// </summary>
/// <param name="filePath"></param>
/// <param name="picPath"></param>
/// <param name="bm"></param>
/// <param name="x">宽度厘米</param>
/// <param name="y">高度厘米</param>
/// <param name="type"></param>
public static void InsertBMPicture(string filePath, string picPath, string bm, long x, ImagePartType type)
{
long y = 0;
using (System.Drawing.Bitmap objPic = new System.Drawing.Bitmap(picPath))
{
y = (x * objPic.Height) / objPic.Width;
}
InsertBMPicture(filePath, picPath, bm, x, y, type);
}
/// <summary>
/// 按书签插入图片
/// </summary>
/// <param name="filePath"></param>
/// <param name="picPath"></param>
/// <param name="bm"></param>
/// <param name="x">宽度厘米</param>
/// <param name="y">高度厘米</param>
/// <param name="type"></param>
public static void InsertBMPicture(string filePath, string picPath, string bm, long x, long y, ImagePartType type)
{
using (WordprocessingDocument doc =
WordprocessingDocument.Open(filePath, true))
{
MainDocumentPart mainPart = doc.MainDocumentPart;
BookmarkStart bmStart = findBookMarkStart(doc, bm);
if (bmStart == null)
{
return;
}
ImagePart imagePart = mainPart.AddImagePart(type);
using (FileStream stream = new FileStream(picPath, FileMode.Open))
{
imagePart.FeedData(stream);
}
long cx = 360000L * x;//360000L = 1厘米
long cy = 360000L * y;
Run r = AddImageToBody(doc, mainPart.GetIdOfPart(imagePart), cx, cy);
bmStart.Parent.InsertAfter<Run>(r, bmStart);
mainPart.Document.Save();
}
}
/// <summary>
/// 按书签插入图片。默认15厘米,JPG
/// </summary>
/// <param name="filePath"></param>
/// <param name="picPath"></param>
/// <param name="bm"></param>
public static void InsertBMPicture(string filePath, string picPath, string bm)
{
InsertBMPicture(filePath, picPath, bm, 15, 15, ImagePartType.Jpeg);
}
/// <summary>
/// 查找书签
/// </summary>
/// <param name="doc"></param>
/// <param name="bmName"></param>
/// <returns></returns>
private static BookmarkStart findBookMarkStart(WordprocessingDocument doc, string bmName)
{
foreach (var footer in doc.MainDocumentPart.FooterParts)
{
foreach (var inst in footer.Footer.Descendants<BookmarkStart>())
{
if (inst.Name == bmName)
{
return inst;
}
}
}
foreach (var header in doc.MainDocumentPart.HeaderParts)
{
foreach (var inst in header.Header.Descendants<BookmarkStart>())
{
if (inst.Name == bmName)
{
return inst;
}
}
}
foreach (var inst in doc.MainDocumentPart.RootElement.Descendants<BookmarkStart>())
{
if (inst is BookmarkStart)
{
if (inst.Name == bmName)
{
return inst;
}
}
}
return null;
}
/// <summary>
/// 查找书签
/// </summary>
/// <param name="doc"></param>
/// <param name="bmName"></param>
/// <returns></returns>
private static List<BookmarkStart> findAllBookMarkStart(WordprocessingDocument doc)
{
List<BookmarkStart> ret = new List<BookmarkStart>();
foreach (var footer in doc.MainDocumentPart.FooterParts)
{
ret.AddRange(footer.Footer.Descendants<BookmarkStart>());
}
foreach (var header in doc.MainDocumentPart.HeaderParts)
{
ret.AddRange(header.Header.Descendants<BookmarkStart>());
}
ret.AddRange(doc.MainDocumentPart.RootElement.Descendants<BookmarkStart>());
return ret;
}
/// <summary>
/// 查找书签
/// </summary>
/// <param name="doc"></param>
/// <param name="bmName"></param>
/// <returns></returns>
private static List<BookmarkEnd> findAllBookMarkEnd(WordprocessingDocument doc)
{
List<BookmarkEnd> ret = new List<BookmarkEnd>();
foreach (var footer in doc.MainDocumentPart.FooterParts)
{
ret.AddRange(footer.Footer.Descendants<BookmarkEnd>());
}
foreach (var header in doc.MainDocumentPart.HeaderParts)
{
ret.AddRange(header.Header.Descendants<BookmarkEnd>());
}
ret.AddRange(doc.MainDocumentPart.RootElement.Descendants<BookmarkEnd>());
return ret;
}
/// <summary>
/// 查找书签END
/// </summary>
/// <param name="doc"></param>
/// <param name="bmName"></param>
/// <returns></returns>
private static BookmarkEnd findBookMarkEnd(WordprocessingDocument doc, string id)
{
foreach (var footer in doc.MainDocumentPart.FooterParts)
{
foreach (var inst in footer.Footer.Descendants<BookmarkEnd>())
{
if (inst.Id == id)
{
return inst;
}
}
}
foreach (var header in doc.MainDocumentPart.HeaderParts)
{
foreach (var inst in header.Header.Descendants<BookmarkEnd>())
{
if (inst.Id == id)
{
return inst;
}
}
}
foreach (var inst in doc.MainDocumentPart.RootElement.Descendants<BookmarkEnd>())
{
if (inst.Id == id)
{
return inst;
}
}
return null;
}
private static Run AddImageToBody(WordprocessingDocument wordDoc, string relationshipId, long cx, long cy)
{
return new Run(new Drawing(
new DW.Inline(
new DW.Extent() { Cx = cx, Cy = cy },
new DW.EffectExtent()
{
LeftEdge = 0L,
TopEdge = 0L,
RightEdge = 0L,
BottomEdge = 0L
},
new DW.DocProperties()
{
Id = (UInt32Value)1U,
Name = "Picture 1"
},
new DW.NonVisualGraphicFrameDrawingProperties(
new AA.GraphicFrameLocks() { NoChangeAspect = true }),
new AA.Graphic(
new AA.GraphicData(
new PIC.Picture(
new PIC.NonVisualPictureProperties(
new PIC.NonVisualDrawingProperties()
{
Id = (UInt32Value)0U,
Name = "New Bitmap Image.jpg"
},
new PIC.NonVisualPictureDrawingProperties()),
new PIC.BlipFill(
new AA.Blip(
new AA.BlipExtensionList(
new AA.BlipExtension()
{
Uri =
"{28A0092B-C50C-407E-A947-70E740481C1C}"
})
)
{
Embed = relationshipId,
CompressionState =
AA.BlipCompressionValues.Print
},
new AA.Stretch(
new AA.FillRectangle())),
new PIC.ShapeProperties(
new AA.Transform2D(
new AA.Offset() { X = 0L, Y = 0L },
new AA.Extents() { Cx = 990000L, Cy = 792000L }),
new AA.PresetGeometry(
new AA.AdjustValueList()
) { Preset = AA.ShapeTypeValues.Rectangle }))
) { Uri = "http://schemas.openxmlformats.org/drawingml/2006/picture" })
)
{
DistanceFromTop = (UInt32Value)0U,
DistanceFromBottom = (UInt32Value)0U,
DistanceFromLeft = (UInt32Value)0U,
DistanceFromRight = (UInt32Value)0U,
EditId = "50D07946"
}));
// Append the reference to body, the element should be in a Run.
// wordDoc.MainDocumentPart.Document.Body.AppendChild(new Paragraph(new Run(element)));
}
public static void DeleteRange(string filePath, string stringStart, string stringStop, int way)
{
using (WordprocessingDocument doc = WordprocessingDocument.Open(filePath, true))
{
List<OpenXmlElement> list = RangeFind(doc, stringStart, stringStop, way);
foreach (var inst in list)
{
inst.Remove();
}
}
}
/// <summary>
/// 1 标记1结束到标记2开始;2 标记1结束到标记2结束;3 标记1开始到标记2结束; 4 标记1开始到标记2开始;
/// trimhuiche 如果为true,则考虑回车;否则不考虑回车。
/// chzhao@wisdombud.com
/// </summary>
/// <param name="stringStart"></param>
/// <param name="stringStop"></param>
/// <param name="way"></param>
public static List<OpenXmlElement> RangeFind(WordprocessingDocument doc, string stringStart, string stringStop, int way)
{
List<OpenXmlElement> ret = new List<OpenXmlElement>();
bool add = false;
foreach (var inst in doc.MainDocumentPart.Document.Body.Elements())
{
if (way == 1)
{
if (inst.InnerText.Contains(stringStop))
{
add = false;
}
if (add)
{
ret.Add(inst.CloneNode(true));
}
if (inst.InnerText == stringStart)
{
add = true;
}
}
else if (way == 2)
{
if (add)
{
ret.Add(inst.CloneNode(true));
}
if (inst.InnerText == stringStart)
{
add = true;
}
if (inst.InnerText.Contains(stringStop))
{
add = false;
}
}
else if (way == 3)
{
if (inst.InnerText == stringStart)
{
add = true;
}
if (add)
{
ret.Add(inst.CloneNode(true));
}
if (inst.InnerText.Contains(stringStop))
{
add = false;
}
}
else if (way == 4)
{
if (inst.InnerText == stringStart)
{
add = true;
}
if (inst.InnerText.Contains(stringStop))
{
add = false;
}
if (add)
{
ret.Add(inst.CloneNode(true));
}
}
}
return ret;
}
/// <summary>
/// 修改书签
/// </summary>
/// <param name="filePath">word文档</param>
/// <param name="bmName">书签名字</param>
/// <param name="text">替换的文本</param>
public static void ModifyBM(string filePath, string bmName, string text)
{
using (WordprocessingDocument doc = WordprocessingDocument.Open(filePath, true))
{
BookmarkStart bmStart = findBookMarkStart(doc, bmName);
Run bookmarkText = bmStart.NextSibling<Run>();
if (bookmarkText != null)
{
Text t = bookmarkText.GetFirstChild<Text>();
if (t != null)
{
t.Text = text;
}
}
}
}
/// <summary>
/// 删除书签内容
/// </summary>
/// <param name="bookmark"></param>
public static void RemoveBookMarkContent(string filePath, string bmName)
{
using (WordprocessingDocument doc = WordprocessingDocument.Open(filePath, true))
{
BookmarkStart bmStart = findBookMarkStart(doc, bmName);
BookmarkEnd bmEnd = findBookMarkEnd(doc, bmStart.Id);
while (true)
{
var run = bmStart.NextSibling();
if (run == null)
{
break;
}
if (run is BookmarkEnd && (BookmarkEnd)run == bmEnd)
{
break;
}
run.Remove();
}
}
}
/// <summary>
/// 重命名书签,在书签前面加前缀
/// </summary>
/// <param name="filePath"></param>
/// <param name="prefix">前缀</param>
public static void RenameBookMark(string filePath, string prefix)
{
using (WordprocessingDocument doc = WordprocessingDocument.Open(filePath, true))
{
foreach (var inst in findAllBookMarkStart(doc))
{
inst.Name = prefix + inst.Name;
}
}
}
/// <summary>
/// 重命名书签
/// </summary>
/// <param name="filePath"></param>
/// <param name="oldName"></param>
/// <param name="newName"></param>
public static void RenameBookMark(string filePath, string oldName, string newName)
{
using (WordprocessingDocument doc = WordprocessingDocument.Open(filePath, true))
{
var bm = findBookMarkStart(doc, oldName);
bm.Name = newName;
}
}
/// <summary>
/// 删除书签
/// </summary>
/// <param name="bookmark"></param>
public static void RemoveBookMark(string filePath, string bmName)
{
using (WordprocessingDocument doc = WordprocessingDocument.Open(filePath, true))
{
var bmStart = findBookMarkStart(doc, bmName);
if (bmStart == null)
{
return;
}
var bmEnd = findBookMarkEnd(doc, bmStart.Id);
bmStart.Remove();
bmEnd.Remove();
}
}
/// <summary>
/// 合并文档
/// </summary>
/// <param name="finalFile"></param>
/// <param name="files"></param>
public static void Combine(string finalFile, List<string> files)
{
if (files.Count < 2)
{
return;
}
File.Copy(files[0], finalFile, true);
using (WordprocessingDocument doc = WordprocessingDocument.Open(finalFile, true))
{
Body b = doc.MainDocumentPart.Document.Body;
for (int i = 1; i < files.Count; i++)
{
using (WordprocessingDocument doc1 = WordprocessingDocument.Open(files[i], true))
{
foreach (var inst in doc1.MainDocumentPart.Document.Body.Elements())
{
b.Append(inst.CloneNode(true));
}
}
}
}
}
}
}
OpenXML操作word的更多相关文章
- OpenXml操作Word的一些操作总结.
OpenXml操作Word的一些操作总结. OpenXml相对于用MS提供的COM组件来生成WORD,有如下优势: 1.相对于MS 的COM组件,因为版本带来的不兼容问题,及各种会生成WORD半途会崩 ...
- OpenXml操作Word的一些操作总结.无word组件生成word.
OpenXml相对于用MS提供的COM组件来生成WORD,有如下优势: 1.相对于MS 的COM组件,因为版本带来的不兼容问题,及各种会生成WORD半途会崩溃的问题. 2.对比填满一张30多页的WOR ...
- OpenXml操作Word的一些操作总结. - 天天不在
OpenXml相对于用MS提供的COM组件来生成WORD,有如下优势: 1.相对于MS 的COM组件,因为版本带来的不兼容问题,及各种会生成WORD半途会崩溃的问题. 2.对比填满一张30多页的WOR ...
- OpenXml操作Word的一些操作总结.无word组件生成word.(转)
http://www.cnblogs.com/zhouxin/p/3174936.html OpenXml相对于用MS提供的COM组件来生成WORD,有如下优势: 1.相对于MS 的COM组件,因为版 ...
- Python操作Word与Excel并打包
安装模块 # Word操作库 pip install docx # Excel操作库 pip install openpyxl # 打包exe工具 pip install pyinstaller Wo ...
- python操作word入门
1.安装pywin32 http://sourceforge.net/projects/pywin32 在files里去找适合你的python版本.截止此文,最新版本是pywin32-219快捷路径: ...
- C#中操作Word(1)—— word对象模型介绍
一.开发环境布置 C#中添加对Word的支持,只需添加对Microsoft.Office.Interop.Word的命名空间,如下图所示,右键点击“引用”,在弹出的“添加引用”对话框中选中COM标签页 ...
- C#操作Word的超详细总结
本文中用C#来操作Word,包括: 创建Word: 插入文字,选择文字,编辑文字的字号.粗细.颜色.下划线等: 设置段落的首行缩进.行距: 设置页面页边距和纸张大小: 设置页眉.页码: 插入图片,设置 ...
- C#操作word模板插入文字、图片及表格详细步骤
c#操作word模板插入文字.图片及表格 1.建立word模板文件 person.dot用书签 标示相关字段的填充位置 2.建立web应用程序 加入Microsoft.Office.Interop.W ...
随机推荐
- Cookie操作类 实现记住用户名和密码的功能
import java.util.Hashtable;import java.util.Iterator;import java.util.Set;import javax.servlet.http. ...
- UVa 575 Skew Binary 歪斜二进制
呵呵,这个翻译还是很直白的嘛,大家意会就好. 第一次看到这个高大上题目还是有点小害怕的,还好题没有做过深的文章. 只要按照规则转化成十进制就好了,而且题目本身也说了最大不超过一个int的范围(2^31 ...
- 迁移应用数据库到MySQL Database on Azure
by Rong Yu 有用户问怎么把他们应用的数据库迁移到MySQL Database on Azure上,有哪些方式,有没有需要注意的地方.今天我们来概括介绍一下迁移应用数据库到MySQL Data ...
- Oracle 11gR2用gpnp profile存放ASM的spfile路径
从Oracle 11gR2开始,GI集成了ASM,OCR/VOTEDISK也存放在ASM磁盘组了(11gR2以前需要存放于裸设备中),同时ASM的功能较10g也有很大增强. 我们先引入一个问题:11g ...
- 前端程序员:月薪 5K 到 5 万,我干了啥(转)
转自:http://www.imooc.com/article/4110 前端程序员:月薪 5K 到 5 万,我干了啥前端开发工作已经变的越来越复杂,仅仅是想罗列一份前端开发的学习列表就已经是一件艰巨 ...
- MySQL基础之第18章 性能优化
18.1.优化简介 SHOW STATUS LIKE ‘value’;connections 连接数uptime 启动 ...
- hdu 5444 Elven Postman(根据先序遍历和中序遍历求后序遍历)2015 ACM/ICPC Asia Regional Changchun Online
很坑的一道题,读了半天才读懂题,手忙脚乱的写完(套上模板+修改模板),然后RE到死…… 题意: 题面上告诉了我们这是一棵二叉树,然后告诉了我们它的先序遍历,然后,没了……没了! 反复读题,终于在偶然间 ...
- C# "error CS1729: 'XXClass' does not contain a constructor that takes 0 arguments"的解决方案
出现这种错误的原因时,没有在子类的构造函数中指出仅有带参构造函数的父类的构造参数. 具体来讲就是: 当子类要重用父类的构造函数时, C# 语法通常会在子类构造函数后面调用 : base( para_t ...
- VB6.0编程笔记——(2)开发环境准备&学习前导入
工欲善其事必先利其器,着手开始学习写代码之前,我们需要先准备好需要用到的工具.这篇文章会教大家部署好环境,同时会告知前期我们需要知道的一点内容(可以不用特别理解,只要记住用法就行,后续会深入展开介绍) ...
- cocos2dx 2.x 版本+Windows+ADT Bundle 配置
昨天解决了cocos2dx 3.x版本+Windows+ADT Bundle的配置,今天来解决cocos2dx 2.x版本的配置. 整体来说,2.x的配置相对麻烦一点,不过一旦解决了,就一路畅通无阻了 ...