最近的項目(MOSS項目)需要,用戶需要根據word模板生成相關的word文檔,具體需求是根據infopath 表單中的內容和相關的模板生成一份word文檔
著手做之前想想要是用word api操作的話,後台進程,多用戶並發操作等等問題
看來還是用openxml來操作比較好,於是找了找資料,實現了這小小的功能
現在把代碼貼出來跟大家分享下
使用openxml技術時,首先需要引用windowsbase.dll
部分常量
const string documentRelationshipType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument&quo t;;
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
以上只是貼出了其中主要的代碼
本文配套源碼:http://www.bianceng.net/dotnet/201212/808.htm