在 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的主要内容,如果未能解决你的问题,请参考以下文章

C#中XML文档的读取编写方法?

C#动态生成Word文档并填充数据

在WORD2007中插入页码显示不了是为啥

Office Open XML文档怎么转换成word文档 2003的

C#读取word文档中的内容

用C#把word中的表格数据读取到xml文件