开发者

Manipulating Word 2007 Document XML in C#

I am trying to manipulate the XML of a Word 2007 document in C#. I have managed to find and manipulate the node that I want but now I can't seem to figure out how to save it back. Here is what I am trying:

// 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 = d开发者_StackOverflowoc.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();

I get the error 'Memory stream is not expandable'. Any ideas?


I would recommend that you use Open XML SDK instead of hacking the format by yourself.


Using OpenXML SDK 2.0, I do this:

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);
}

From this you could write a GetPartAsXmlDocument, do what you want with it, and then stream it back with SavePart(part, xmlString).

Hope this helps!


You should use the OpenXML SDK to work on docx files and not write your own wrapper.

  • 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


The problem appears to be doc.Save(partWrtr), which is built using newPkgprtData, which is built using pkgFile, which loads from a memory stream... Because you loaded from a memory stream it's trying to save the document back to that same memory stream. This leads to the error you are seeing.

Instead of saving it to the memory stream try saving it to a new file or to a new memory stream.


The short and simple answer to the issue with getting 'Memory stream is not expandable' is: Do not open the document from memoryStream. So in that respect the earlier answer is correct, simply open a file instead.

Opening from MemoryStream editing the document (in my experience) easy lead to 'Memory stream is not expandable'. I suppose the message appears when one do edits that requires the memory stream to expand. I have found that I can do some edits but not anything that add to the size. So, f.ex deleting a custom xml part is ok but adding one and some data is not.

So if you actually need to open a memory stream you must figure out how to open an expandable MemoryStream if you want to add to it. I have a need for this and hope to find a solution.

Stein-Tore Erdal

PS: just noticed the answer from "Jan 26 '11 at 15:18". Don't think that is the answer in all situations. I get the error when trying this:

     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.
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜