如何将WordOpenXML属性转换为System.IO.Packaging.Package?

时间:2011-09-30 09:27:39

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

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

该类有一个名为WordOpenXML的属性,它似乎是构成.docx包的所有文件的XML表示形式,当将该Word文档另存为{时,该文件将保存到磁盘中{1}}。

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

2 个答案:

答案 0 :(得分:5)

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

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

答案 1 :(得分: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