当使用VSTO 2012来操作MS Word文档时,我看到该文档具有“WordOpenXML”字符串属性,该属性是构成.docx包的所有文件的XML表示,在保存时将保存到磁盘Word文档为.docx。
我想将此字符串转换为内存中的等效System.IO.Packaging.Package对象 。
SO question here非常相似。事实上,OP甚至在他的问题中提到“记忆中”。但是,给出的答案涉及使用System.IO.Packaging.ZipPackage.Open
方法将Package保存到磁盘。我不想将Package保存到磁盘,然后必须使用WordprocessingDocument.Open()
方法再次打开它。相反,我希望一切都在内存中完成,而根本不涉及文件系统。
我看到WordprocessingDocument.Open()
有一个带有Stream的重载。但是,我不确定如何从WordOpenXML字符串中准备这样的Stream,尽管我怀疑上面提到的帖子给出了很多答案。
答案 0 :(得分:4)
您可以使用此方法从WordOpenXml字符串中获取内存流:
/// <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;
}