OpenXML 替换word模板中的标签
最近的项目(MOSS项目)需要,用户需要根据word模板生成相关的word文档,具体需求是根据infopath表单中的内容和相关的模板生成一份word文档
着手做之前想想要是用word api操作的话,后台进程,多用户并发操作等等问题
看来还是用openxml来操作比较好,于是找了找资料,实现了这小小的功能
现在把代码贴出来跟大家分享下
使用openxml技术时,首先需要引用windowsbase.dll
部分常量


const string documentRelationshipType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
const string strUri = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
static List<string> bookmarkText;
string bookmarkName;
该方法是将模板中所有标签都取出,并放到一个datatable中


void bindTable(string fileName)
{
dt = new DataTable();
dt.Columns.Add("标签", typeof(string));
dt.Columns.Add("内容", typeof(string));
DataRow dr;
Stream strm = null;
PackagePart documentPart;
Package package;
using (SPSite site = new SPSite("http://ascentn-moss:8686/"))
{
SPWeb web = site.OpenWeb();
strm = web.GetFile(fileName).OpenBinaryStream();
documentPart = null;
package = Package.Open(strm, FileMode.Open, FileAccess.ReadWrite);
//FileStream fs = new FileStream(fileName, FileMode.OpenOrCreate);
//PackagePart documentPart = null;
//Package package = Package.Open(fileName, FileMode.Open, FileAccess.ReadWrite);
//MessageBox.Show(strm.Length.ToString());
// Package package = Package.Open(strm, FileMode.Open, FileAccess.ReadWrite);
foreach (System.IO.Packaging.PackageRelationship documentRelationship in package.GetRelationshipsByType(documentRelationshipType))
{
NameTable nt = new NameTable();
XmlNamespaceManager nsManager = new XmlNamespaceManager(nt);
nsManager.AddNamespace("w", strUri);
Uri documentUri = PackUriHelper.ResolvePartUri(new Uri("/", UriKind.Relative), documentRelationship.TargetUri);
documentPart = package.GetPart(documentUri);
XmlDocument xdoc = new XmlDocument();
xdoc.Load(documentPart.GetStream());
XmlNodeList nodeList = xdoc.SelectNodes("//w:bookmarkStart", nsManager);
foreach (XmlNode node in nodeList)
{
dr = dt.NewRow();
if (node.NextSibling.Name.ToString() == "w:bookmarkEnd")
{
bookmarkText = new List<string>();
bookmarkName = node.Attributes["w:name"].Value;
bookmarkText.Add(" ");
dr[0] = bookmarkName;
//dataGridView
}
else
{
bookmarkName = node.Attributes["w:name"].Value;
dr[0] = bookmarkName;
string bookmarkId = node.Attributes["w:id"].Value;
bookmarkText = new List<string>();
XmlNode nextParentNode = node.ParentNode;
XmlNode nodeIterate = node.NextSibling;
while (nodeIterate.Name.ToString() != "w:bookmarkEnd")
{
if (nodeIterate.Name.ToString() == "w:r")
bookmarkText.Add(nodeIterate.InnerText);
nodeIterate = nodeIterate.NextSibling;
if (nodeIterate == null)
{
if (nextParentNode.NextSibling.Attributes.Count != 0)
{
if ((nextParentNode.NextSibling.Attributes["w:id"].Value == bookmarkId))
{
nodeIterate = nextParentNode.NextSibling;
}
}
else
{
nextParentNode = nextParentNode.NextSibling;
nodeIterate = nextParentNode.FirstChild;
bookmarkText.Add('\n' + nodeIterate.InnerText);
}
}
}
//dic.Add(bookmarkName, bookmarkText);
}
dt.Rows.Add(dr);
}
}
package.Close();
}
}
接下来需要做的是用infopath中的相关节点去逐个替换标签内容


#region 处理标签
string spUrl = (string)ds["SPServer"];
APWS.Service apws = new APWS.Service();
apws.Url = spUrl + "/spsws/Service.asmx";
apws.Credentials = WFSystem.GetSystemUserCredential();
System.IO.MemoryStream fileStream = new System.IO.MemoryStream();
string newfilename = string.Empty;
if(fileLocation.EndsWith("/"))
newfilename = fileLocation + fileName + template.Substring(template.LastIndexOf('.'));
else
newfilename = fileLocation +"/"+ fileName + template.Substring(template.LastIndexOf('.'));
apws.SPCopyFile(template, newfilename);
fileStream.Write(apws.SPOpenBinary(newfilename), 0, apws.SPGetFileLenght(newfilename));
originalDocPackage = Package.Open(fileStream, FileMode.Open, FileAccess.ReadWrite);
foreach (PackageRelationship relationship in originalDocPackage.GetRelationshipsByType(documentRelationshipType))
{
Uri documentUri = PackUriHelper.ResolvePartUri(new Uri("/", UriKind.Relative), relationship.TargetUri);
originalDocumentPart = originalDocPackage.GetPart(documentUri);
break;
}
originalXmlDocument = new XmlDocument();
originalXmlDocument.Load(originalDocumentPart.GetStream());
NameTable nt = new NameTable();
XmlNamespaceManager xmlNamespaceManager = new XmlNamespaceManager(nt);
xmlNamespaceManager.AddNamespace("w", strUri);
#region 多个书签循环检索
XmlNodeList bookmarknodeList = originalXmlDocument.SelectNodes("//w:bookmarkStart", xmlNamespaceManager);
XmlNodeList bookmarknodeEndList = originalXmlDocument.SelectNodes("//w:bookmarkEnd", xmlNamespaceManager);
XmlNode parentNodeOfBookMark;
foreach (XmlNode xmlnode in bookmarknodeList)
{
foreach (string columnName in hvalues.Keys)
{
if (xmlnode.Attributes["w:name"].Value == columnName)
{
if (xmlnode.NextSibling.Name == "w:r")
{
xmlnode.NextSibling.RemoveChild(xmlnode.NextSibling.LastChild);
XmlElement textElement = originalXmlDocument.CreateElement("w:t", strUri);
xmlnode.NextSibling.AppendChild(textElement);
XmlNode textNode = originalXmlDocument.CreateNode(XmlNodeType.Text, "w:t", strUri);
if(hvalues[columnName].ToString().EndsWith("T00:00:00"))
textNode.Value = hvalues[columnName].ToString().Substring(0,hvalues[columnName].ToString().IndexOf('T'));
else
textNode.Value = hvalues[columnName].ToString();
textElement.AppendChild(textNode);
}
}
}
parentNodeOfBookMark = xmlnode.ParentNode;
parentNodeOfBookMark.RemoveChild(xmlnode);
}
foreach (XmlNode xmlnode in bookmarknodeEndList)
{
parentNodeOfBookMark = xmlnode.ParentNode;
parentNodeOfBookMark.RemoveChild(xmlnode);
}
#endregion
//save document
originalXmlDocument.Save(originalDocumentPart.GetStream(FileMode.Create, FileAccess.Write));
byte[] bs = fileStream.ToArray();
apws.SPSaveBinary(newfilename, bs);
originalDocPackage.Close();
#endregion
以上只是贴出了其中主要的代码
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述