Transforming Flat OPC Format to Open XML Documents

Transforming Open XML documents using XSLT is an interesting scenario, but before we can do so, we need to convert the Open XML document into the Flat OPC format.  We then perform the XSLT transform, producing a new file in the Flat OPC format, and then convert back to Open XML (OPC) format.  This post is one in a series of four posts that present this approach to transforming Open XML documents using XSLT.  The four posts are:

Transforming Open XML Documents using XSLT

Presents an overview of the transformation process of Open XML documents using XSLT, and why this is important.  Also presents the ‘Hello World’ XSLT transform of an Open XML document.

Transforming Open XML Documents to Flat OPC Format

This post describes the process of conversion of an Open XML (OPC) document into a Flat OPC document, and presents the C# function, OpcToFlat.

Transforming Flat OPC Format to Open XML Documents (This Post)

This post describes the process of conversion of a Flat OPC file back to an Open XML document, and presents the C# function, FlatToOpc.

The Flat OPC Format

Presents a description and examples of the Flat OPC format.

About the Code

This blog is inactive.
New blog: EricWhite.com/blog

Blog TOCThe code presented in this post uses LINQ to XML and System.IO.Packaging to perform the conversion from Flat OPC to an Open XML (OPC) document.

The signature of the function to convert from an Open XML document to Flat OPC is:

static void FlatToOpc(XDocument doc, string docxPath)

You pass in an XDocument object and the path to the new Open XML document.  The method creates an Open XML document at the specified path.

The code to convert a base 64 string to binary uses the System.Convert.FromBase64CharArray method.  Before converting the string to binary, the code strips the new lines that were added when producing the Flat OPC file.

Here is the code to perform the transform (also attached):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.IO;
using System.IO.Packaging;
using System.Xml;
using System.Xml.Schema;

class Program
{
static void FlatToOpc(XDocument doc, string docxPath)
{
XNamespace pkg =
"https://schemas.microsoft.com/office/2006/xmlPackage";
XNamespace rel =
"https://schemas.openxmlformats.org/package/2006/relationships";

using (Package package = Package.Open(docxPath, 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 = package.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 = package.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")
package.CreateRelationship(
new Uri(target, UriKind.Absolute),
TargetMode.External, type, id);
else
package.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 = package.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);
}
}
}
}
}
}

static void Main(string[] args)
{
XDocument doc;
doc = XDocument.Load("Test.xml");
FlatToOpc(doc, "Test-new.docx");
doc = XDocument.Load("Test2.xml");
FlatToOpc(doc, "Test2-new.pptx");
}
}

FlatToOpc.zip