在 C# 中操作 Word 2007 文档 XML
Posted
技术标签:
【中文标题】在 C# 中操作 Word 2007 文档 XML【英文标题】:Manipulating Word 2007 Document XML in C# 【发布时间】:2011-06-15 04:30:52 【问题描述】:我正在尝试在 C# 中操作 Word 2007 文档的 XML。我已经设法找到并操作了我想要的节点,但现在我似乎无法弄清楚如何将它保存回来。这是我正在尝试的:
// Open the document from memoryStream
Package pkgFile = Package.Open(memoryStream, FileMode.Open, FileAccess.ReadWrite);
PackageRelationshipCollection pkgrcOfficeDocument = pkgFile.GetRelationshipsByType(strRelRoot);
foreach (PackageRelationship pkgr in pkgrcOfficeDocument)
if (pkgr.SourceUri.OriginalString == "/")
Uri uriData = new Uri("/word/document.xml", UriKind.Relative);
PackagePart pkgprtData = pkgFile.GetPart(uriData);
XmlDocument doc = new XmlDocument();
doc.Load(pkgprtData.GetStream());
NameTable nt = new NameTable();
XmlNamespaceManager nsManager = new XmlNamespaceManager(nt);
nsManager.AddNamespace("w", nsUri);
XmlNodeList nodes = doc.SelectNodes("//w:body/w:p/w:r/w:t", nsManager);
foreach (XmlNode node in nodes)
if (node.InnerText == "TextToChange")
node.InnerText = "success";
if (pkgFile.PartExists(uriData))
// Delete template "/customXML/item1.xml" part
pkgFile.DeletePart(uriData);
PackagePart newPkgprtData = pkgFile.CreatePart(uriData, "application/xml");
StreamWriter partWrtr = new StreamWriter(newPkgprtData.GetStream(FileMode.Create, FileAccess.Write));
doc.Save(partWrtr);
partWrtr.Close();
pkgFile.Close();
我收到错误消息“内存流不可扩展”。有什么想法吗?
【问题讨论】:
想知道是否有更好的方法来做到这一点...... 【参考方案1】:我建议您使用Open XML SDK 而不是自己破解格式。
【讨论】:
【参考方案2】:使用 OpenXML SDK 2.0,我这样做:
public void SearchAndReplace(Dictionary<string, string> tokens)
using (WordprocessingDocument doc = WordprocessingDocument.Open(_filename, true))
ProcessDocument(doc, tokens);
private string GetPartAsString(OpenXmlPart part)
string text = String.Empty;
using (StreamReader sr = new StreamReader(part.GetStream()))
text = sr.ReadToEnd();
return text;
private void SavePart(OpenXmlPart part, string text)
using (StreamWriter sw = new StreamWriter(part.GetStream(FileMode.Create)))
sw.Write(text);
private void ProcessDocument(WordprocessingDocument doc, Dictionary<string, string> tokenDict)
ProcessPart(doc.MainDocumentPart, tokenDict);
foreach (var part in doc.MainDocumentPart.HeaderParts)
ProcessPart(part, tokenDict);
foreach (var part in doc.MainDocumentPart.FooterParts)
ProcessPart(part, tokenDict);
private void ProcessPart(OpenXmlPart part, Dictionary<string, string> tokenDict)
string docText = GetPartAsString(part);
foreach (var keyval in tokenDict)
Regex expr = new Regex(_starttag + keyval.Key + _endtag);
docText = expr.Replace(docText, keyval.Value);
SavePart(part, docText);
从此您可以编写一个 GetPartAsXmlDocument,用它做您想做的事,然后使用 SavePart(part, xmlString) 将其流回。
希望这会有所帮助!
【讨论】:
【参考方案3】:您应该使用 OpenXML SDK 来处理 docx 文件,而不是编写自己的包装器。
Getting Started with the Open XML SDK 2.0 for Microsoft Office Introducing the Office (2007) Open XML File Formats How to: Manipulate Office Open XML Formats Documents Manipulate Docx with C# without Microsoft Word installed with OpenXML SDK【讨论】:
【参考方案4】:问题似乎是 doc.Save(partWrtr),它是使用 newPkgprtData 构建的,它是使用 pkgFile 构建的,它从内存流中加载...因为您是从内存流中加载的,所以它试图将文档保存回来到同一个内存流。这会导致您看到的错误。
不要将其保存到内存流中,而是尝试将其保存到新文件或新的内存流中。
【讨论】:
这些是我的想法...知道我应该怎么做吗? MemoryStream msSave = new MemoryStream(); doc.Save(msSave); 也许更好,因为您在 asp.net 中: doc.Save(Response.OutputStream) 会将其直接写入 HTTP 响应流。【参考方案5】:获得“内存流不可扩展”问题的简短答案是: 不要从 memoryStream 打开文档。 所以在这方面,前面的答案是正确的,只需打开一个文件。
从 MemoryStream 打开编辑文档(根据我的经验)很容易导致“内存流不可扩展”。 我想当进行需要扩展内存流的编辑时会出现该消息。 我发现我可以做一些编辑,但不能做任何增加尺寸的事情。 因此,f.ex 删除自定义 xml 部分是可以的,但添加一个和一些数据则不行。
所以如果你真的需要打开一个内存流,你必须弄清楚如何打开一个可扩展的 MemoryStream,如果你想添加它。 我有这个需求,希望能找到解决办法。
斯坦-托尔·埃达尔
PS:刚刚注意到“2011 年 1 月 26 日 15:18”的答案。 不要认为这是所有情况下的答案。 尝试此操作时出现错误:
var ms = new MemoryStream(bytes);
using (WordprocessingDocument wd = WordprocessingDocument.Open(ms, true))
...
using (MemoryStream msData = new MemoryStream())
xdoc.Save(msData);
msData.Position = 0;
ourCxp.FeedData(msData); // Memory stream is not expandable.
【讨论】:
以上是关于在 C# 中操作 Word 2007 文档 XML的主要内容,如果未能解决你的问题,请参考以下文章