Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 = 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();

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

like image 962
stephen776 Avatar asked Dec 12 '22 16:12

stephen776


2 Answers

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

like image 183
m0sa Avatar answered Dec 24 '22 17:12

m0sa


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!

like image 45
uggwar Avatar answered Dec 24 '22 16:12

uggwar