【问题标题】:How to convert the WordOpenXML property into a System.IO.Packaging.Package?如何将 WordOpenXML 属性转换为 System.IO.Packaging.Package?
【发布时间】:2025-12-02 18:55:02
【问题描述】:

我一直在尝试使用 Visual Studio 2008 在 C# 中构建 Outlook 2010 插件。我能够从 Microsoft.Office.Interop.Outlook.Inspector 对象获取 Microsoft.Office.Interop.Word.DocumentClass 对象,该对象代表当前正在编辑的电子邮件。我知道这个DocumentClass 也用于其他各种环境(通常用于 Microsoft Word 扩展,这不足为奇)。

该类有一个名为WordOpenXML 的属性很有帮助,它似乎是构成.docx 包的所有文件的XML 表示,当将此Word 文档保存为.docx 时将保存到磁盘。

此属性非常有用的一种方法是,如果它可以在内存中转换为System.IO.Packaging.Package 对象; IE。反序列化它。有谁知道是否有一种简单的方法可以做到这一点,还是我需要编写一些 XML 解析代码来手动完成?

【问题讨论】:

  • Jez,如果你已经回答了自己的问题,为什么还要赏金?
  • 我在放赏金后想通了。 :-)
  • 啊,明白了。是的,我打算建议在 msdn 上查看 eric white 的旧站点,我想我记得在那里看到了解决方案。很高兴看到它已经弄清楚并记录在案以供将来参考。
  • 作为旁注,DocumentFormat.OpenXmlFromFlatOpcStringToFlatOpcDocument 方法

标签: c# visual-studio outlook ms-word add-in


【解决方案1】:

我最终修改了我在网上找到的一些代码,以创建一个将WordOpenXML 转换为保存到磁盘的包的方法:

using System;
using System.Xml;
using System.Xml.XPath;
using System.Text;
using System.IO;
using System.IO.Packaging;

// [...]
// Call like this: createPackageFromWordOpenXML(wordEditor.WordOpenXML, @"C:\outputFiles\testOut.docx");

/// <summary>
/// Creates a ZIP package (ie. Word's .docx format) from a WordOpenXML string, which is saved to the file at the path specified.
/// </summary>
/// <param name="wordOpenXML">The WordOpenXML string to get the ZIP package data from.</param>
/// <param name="filePath">The path of the file to save the ZIP package to.</param>
private void createPackageFromWordOpenXML(string wordOpenXML, string filePath)
{
    string packageXmlns = "http://schemas.microsoft.com/office/2006/xmlPackage";
    Package newPkg = System.IO.Packaging.ZipPackage.Open(filePath, FileMode.Create);

    try
    {
        XPathDocument xpDocument = new XPathDocument(new StringReader(wordOpenXML));
        XPathNavigator xpNavigator = xpDocument.CreateNavigator();

        XmlNamespaceManager nsManager = new XmlNamespaceManager(xpNavigator.NameTable);
        nsManager.AddNamespace("pkg", packageXmlns);
        XPathNodeIterator xpIterator = xpNavigator.Select("//pkg:part", nsManager);

        while (xpIterator.MoveNext())
        {
            Uri partUri = new Uri(xpIterator.Current.GetAttribute("name", packageXmlns), UriKind.Relative);

            PackagePart pkgPart = newPkg.CreatePart(partUri, xpIterator.Current.GetAttribute("contentType", packageXmlns));

            // Set this package part's contents to this XML node's inner XML, sans its surrounding xmlData element.
            string strInnerXml = xpIterator.Current.InnerXml
                .Replace("<pkg:xmlData xmlns:pkg=\"" + packageXmlns + "\">", "")
                .Replace("</pkg:xmlData>", "");
            byte[] buffer = Encoding.UTF8.GetBytes(strInnerXml);
            pkgPart.GetStream().Write(buffer, 0, buffer.Length);
        }

        newPkg.Flush();
    }
    finally
    {
        newPkg.Close();
    }
}

【讨论】:

    【解决方案2】:

    我将它转换为 VB.NET 并添加了一个处理二进制附件的部分。感谢您的出色工作!

    Public Sub createDocXFromWordOpenXML(ByRef sWordOpenXML As String, ByVal sfilePath As String)
      Dim sPackageXMLNS As String = "http://schemas.microsoft.com/office/2006/xmlPackage"
      Dim docxPkg As Package
      Dim xPathDoc As XPathDocument
      Dim xpNav As XPathNavigator
      Dim xNSMgnr As XmlNamespaceManager
      Dim xpPntr As XPathNodeIterator
      Dim partURI As Uri
      Dim pkgPart As PackagePart
      Dim sInnerXML As String
      Dim bytBuffer As Byte()
    
      docxPkg = System.IO.Packaging.ZipPackage.Open(sfilePath, FileMode.Create)
    
      Try
    
        xPathDoc = New XPathDocument(New StringReader(sWordOpenXML))
        xpNav = xPathDoc.CreateNavigator()
    
        xNSMgnr = New XmlNamespaceManager(xpNav.NameTable)
        xNSMgnr.AddNamespace("pkg", sPackageXMLNS)
        xpPntr = xpNav.Select("//pkg:part", xNSMgnr)
    
        While xpPntr.MoveNext()
          partURI = New Uri(xpPntr.Current.GetAttribute("name", sPackageXMLNS), UriKind.Relative)
    
          pkgPart = docxPkg.CreatePart(partURI, xpPntr.Current.GetAttribute("contentType", sPackageXMLNS))
    
          sInnerXML = xpPntr.Current.InnerXml
    
          Select Case True
            Case sInnerXML.Contains("xmlData")
              sInnerXML = sInnerXML.Replace("<pkg:xmlData xmlns:pkg=""" & sPackageXMLNS & """>", String.Empty)
              sInnerXML = sInnerXML.Replace("</pkg:xmlData>", String.Empty)
    
              bytBuffer = Encoding.UTF8.GetBytes(sInnerXML)
              pkgPart.GetStream().Write(bytBuffer, 0, bytBuffer.Length)
            Case sInnerXML.Contains("binaryData")
              sInnerXML = sInnerXML.Replace("<pkg:binaryData xmlns:pkg=""" & sPackageXMLNS & """>", String.Empty)
              sInnerXML = sInnerXML.Replace("</pkg:binaryData>", String.Empty)
    
              bytBuffer = Convert.FromBase64String(sInnerXML)
              pkgPart.GetStream().Write(bytBuffer, 0, bytBuffer.Length)
          End Select
    
    
        End While
    
        docxPkg.Flush()
    
      Catch ex As Exception
        Throw
      Finally
        docxPkg.Close()
      End Try
    End Sub
    

    【讨论】: