在 C# 中操作 Word 2007 文档 XML

发布于 2024-10-14 08:02:14 字数 1553 浏览 2 评论 0原文

我正在尝试用 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();

我收到错误“内存流不可扩展”。有什么想法吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

盛夏尉蓝 2024-10-21 08:02:14

我建议您使用 Open XML SDK 而不是黑客攻击格式自己定。

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

无需解释 2024-10-21 08:02:14

使用 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) 将其流式传输回来。

希望这有帮助!

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!

仙女 2024-10-21 08:02:14

问题似乎是 doc.Save(partWrtr) ,它是使用 newPkgprtData 构建的,而 newPkgprtData 是使用 pkgFile 构建的,它从内存流加载...因为您从内存流加载,所以它试图将文档保存回相同的位置内存流。这会导致您看到的错误。

不要将其保存到内存流,而是尝试将其保存到新文件或新内存流。

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.

浅暮の光 2024-10-21 08:02:14

对于“内存流不可扩展”问题的简短回答是:
不要从内存流中打开文档。
因此,在这方面,早期的答案是正确的,只需打开一个文件即可。

从 MemoryStream 打开编辑文档(根据我的经验)很容易导致“内存流不可扩展”。
我想当进行需要扩展内存流的编辑时会出现该消息。
我发现我可以做一些编辑,但不能做任何增加尺寸的事情。
因此,f.ex 删除自定义 xml 部分是可以的,但添加一个和一些数据则不行。

因此,如果您确实需要打开内存流,则必须弄清楚如何打开可扩展的 MemoryStream(如果您想向其中添加内容)。
我有这个需求,希望能找到解决方案。

Stein-Tore Erdal

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.

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.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文