Converting from 'WordOpenXML' to In-Memory System.IO.Packaging.Package

一笑奈何 提交于 2019-12-22 12:08:14

问题


When using VSTO 2012 to manipulate an MS Word Document, I see that the document has a WordOpenXML string property, which is an XML representation of all the files constituting the .docx package which would be saved to disk when saving this Word document as a .docx.

I want to convert this string to an equivalent System.IO.Packaging.Package object in-memory.

The SO question here is very similar. Indeed, the OP even mentions 'in memory' in his question. However, the answers given involve saving the Package to disk using the System.IO.Packaging.ZipPackage.Open() method. I do not want to save the Package to disk and then have to open it again using the WordprocessingDocument.Open() method. Rather, I want everything to be done in memory and not involve the file system at all.

I see that WordprocessingDocument.Open() has an overload that takes a Stream. However, I'm not sure how I would prepare such a Stream from the WordOpenXML string, although I suspect the post referenced above gives much of the answer.


回答1:


You can use this method to get an in memory stream from the WordOpenXml string:

/// <summary>
    /// Returns a System.IO.Packaging.Package stream for the given word open XML.
    /// </summary>
    /// <param name="wordOpenXML">The word open XML.</param>
    /// <returns></returns>
    public static MemoryStream GetPackageStreamFromWordOpenXML(string wordOpenXML)
    {
        XDocument doc = XDocument.Parse(wordOpenXML);
        XNamespace pkg =
           "http://schemas.microsoft.com/office/2006/xmlPackage";
        XNamespace rel =
            "http://schemas.openxmlformats.org/package/2006/relationships";
        Package InmemoryPackage = null;
        MemoryStream memStream = new MemoryStream();
        using (InmemoryPackage = Package.Open(memStream, FileMode.Create))
        {
            // add all parts (but not relationships)
            foreach (var xmlPart in doc.Root
                .Elements()
                .Where(p =>
                    (string)p.Attribute(pkg + "contentType") !=
                    "application/vnd.openxmlformats-package.relationships+xml"))
            {
                string name = (string)xmlPart.Attribute(pkg + "name");
                string contentType = (string)xmlPart.Attribute(pkg + "contentType");
                if (contentType.EndsWith("xml"))
                {
                    Uri u = new Uri(name, UriKind.Relative);
                    PackagePart part = InmemoryPackage.CreatePart(u, contentType,
                        CompressionOption.SuperFast);
                    using (Stream str = part.GetStream(FileMode.Create))
                    using (XmlWriter xmlWriter = XmlWriter.Create(str))
                        xmlPart.Element(pkg + "xmlData")
                            .Elements()
                            .First()
                            .WriteTo(xmlWriter);
                }
                else
                {
                    Uri u = new Uri(name, UriKind.Relative);
                    PackagePart part = InmemoryPackage.CreatePart(u, contentType,
                        CompressionOption.SuperFast);
                    using (Stream str = part.GetStream(FileMode.Create))
                    using (BinaryWriter binaryWriter = new BinaryWriter(str))
                    {
                        string base64StringInChunks =
                       (string)xmlPart.Element(pkg + "binaryData");
                        char[] base64CharArray = base64StringInChunks
                            .Where(c => c != '\r' && c != '\n').ToArray();
                        byte[] byteArray =
                            System.Convert.FromBase64CharArray(base64CharArray,
                            0, base64CharArray.Length);
                        binaryWriter.Write(byteArray);
                    }
                }
            }
            foreach (var xmlPart in doc.Root.Elements())
            {
                string name = (string)xmlPart.Attribute(pkg + "name");
                string contentType = (string)xmlPart.Attribute(pkg + "contentType");
                if (contentType ==
                    "application/vnd.openxmlformats-package.relationships+xml")
                {
                    // add the package level relationships
                    if (name == "/_rels/.rels")
                    {
                        foreach (XElement xmlRel in
                            xmlPart.Descendants(rel + "Relationship"))
                        {
                            string id = (string)xmlRel.Attribute("Id");
                            string type = (string)xmlRel.Attribute("Type");
                            string target = (string)xmlRel.Attribute("Target");
                            string targetMode =
                                (string)xmlRel.Attribute("TargetMode");
                            if (targetMode == "External")
                                InmemoryPackage.CreateRelationship(
                                    new Uri(target, UriKind.Absolute),
                                    TargetMode.External, type, id);
                            else
                                InmemoryPackage.CreateRelationship(
                                    new Uri(target, UriKind.Relative),
                                    TargetMode.Internal, type, id);
                        }
                    }
                    else
                    // add part level relationships
                    {
                        string directory = name.Substring(0, name.IndexOf("/_rels"));
                        string relsFilename = name.Substring(name.LastIndexOf('/'));
                        string filename =
                            relsFilename.Substring(0, relsFilename.IndexOf(".rels"));
                        PackagePart fromPart = InmemoryPackage.GetPart(
                            new Uri(directory + filename, UriKind.Relative));
                        foreach (XElement xmlRel in
                            xmlPart.Descendants(rel + "Relationship"))
                        {
                            string id = (string)xmlRel.Attribute("Id");
                            string type = (string)xmlRel.Attribute("Type");
                            string target = (string)xmlRel.Attribute("Target");
                            string targetMode =
                                (string)xmlRel.Attribute("TargetMode");
                            if (targetMode == "External")
                                fromPart.CreateRelationship(
                                    new Uri(target, UriKind.Absolute),
                                    TargetMode.External, type, id);
                            else
                                fromPart.CreateRelationship(
                                    new Uri(target, UriKind.Relative),
                                    TargetMode.Internal, type, id);
                        }
                    }
                }
            }
            InmemoryPackage.Flush();
        }
        return memStream;
    }


来源:https://stackoverflow.com/questions/17971677/converting-from-wordopenxml-to-in-memory-system-io-packaging-package

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!