The OpenXmlDocument Class
This example takes the plumbing code from Packages and Parts, refactors it a bit, and creates an object graph that will be easy to query using LINQ to XML. There are a few points to note about this code:
This blog is inactive.
New blog: EricWhite.com/blog
Blog TOC· To make reading the code as easy as possible, it was written in the spirit of a dynamic language, such as Python or Ruby. The Relationship class (implemented below) consists of as a set of read/write properties using the new C# 3.0 automatic properties syntax. We don’t really care that much that the properties are in some cases settable, when in fact maybe they should not be. After all, we’re going to write pure functional code that never mutates anything. Our main concern is using a syntax that is as lightweight as possible. We’ll see other examples of this approach later.
· The OpenXmlDocument class implements IDisposable, and in its Dispose method calls the Close method on the Package. IDisposable isn’t really in the spirit of pure, stateless functional programming, but since the Package class implements IDisposable, the correct approach for the OpenXmlDocument class is to also implement IDisposable. Besides, I’m not a purist! And there are times when imperative code is easier to write (and read) than pure FP declarative code.
· The CreateRelationshipList method contains a query that uses a PackageRelationshipCollection as its source, and projects a collection of Relationship objects. By projecting a new collection of our own type of objects, we’ll improve the readability of the code that uses this class, improve the IntelliSense experience, and provide a place to store stuff like our LINQ to XML tree (in an XDocument object).
· To simplify accessing child relationships for a PackagePart, the Relationship class below contains a List<Relationship> property that is initialized when a PackagePart contains a PackageRelationshipCollection.
· This code was compiled with the RTM version of Visual Studio 2008: C# 3.0 and .NET Framework 3.5.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.IO;
using System.IO.Packaging;
namespace Microsoft.Examples.LtxOpenXml
{
class Relationship
{
public string Id { get; set; }
public string RelationshipType { get; set; }
public string ContentType { get; set; }
public System.IO.Packaging.TargetMode TargetMode { get; set; }
public Uri SourceUri { get; set; }
public Uri TargetUri { get; set; }
public PackagePart PackagePart { get; set; }
public XDocument XDocument { get; set; }
public List<Relationship> Relationships { get; set; }
}
class OpenXmlDocument : IDisposable
{
// public
public string Name { get; set; }
public Package Package { get; set; }
public List<Relationship> Relationships { get; set; }
// private
private bool disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
Package.Close();
disposed = true;
}
}
private XDocument LoadXDocument(string relationshipType,
PackagePart part)
{
if (XmlContentTypes.Contains(part.ContentType))
return XDocument.Load(XmlReader.Create(part.GetStream()));
else
return null;
}
private List<Relationship> CreateRelationshipList(
PackageRelationshipCollection prc)
{
return (
from pr in prc
where pr.TargetMode == TargetMode.Internal
let uri = PackUriHelper.ResolvePartUri(
new Uri(pr.SourceUri.ToString(), UriKind.Relative),
pr.TargetUri)
let part = pr.Package.GetPart(uri)
let contentType = part.ContentType
let xdoc = LoadXDocument(pr.RelationshipType, part)
let partRelationshipList =
CreateRelationshipList(part.GetRelationships())
select new Relationship
{
Id = pr.Id,
RelationshipType = pr.RelationshipType,
TargetMode = pr.TargetMode,
ContentType = part.ContentType,
SourceUri = pr.SourceUri,
TargetUri = pr.TargetUri,
PackagePart = part,
XDocument = xdoc,
Relationships = partRelationshipList
}
).ToList();
}
public OpenXmlDocument(string name)
{
Name = name;
Package = Package.Open(Name, FileMode.Open, FileAccess.Read);
Relationships = CreateRelationshipList(
Package.GetRelationships());
}
public HashSet<string> XmlContentTypes = new HashSet<string>
{
"application/vnd.openxmlformats-officedocument.custom-properties+xml",
"application/vnd.openxmlformats-officedocument.customXmlProperties+xml",
"application/vnd.openxmlformats-officedocument.drawing+xml",
"application/vnd.openxmlformats-officedocument.drawingml.chart+xml",
"application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml",
"application/vnd.openxmlformats-officedocument.drawingml.diagramColors+xml",
"application/vnd.openxmlformats-officedocument.drawingml.diagramData+xml",
"application/vnd.openxmlformats-officedocument.drawingml.diagramLayout+xml",
"application/vnd.openxmlformats-officedocument.drawingml.diagramStyle+xml",
"application/vnd.openxmlformats-officedocument.extended-properties+xml",
"application/vnd.openxmlformats-officedocument.presentationml.commentAuthors+xml",
"application/vnd.openxmlformats-officedocument.presentationml.comments+xml",
"application/vnd.openxmlformats-officedocument.presentationml.handoutMaster+xml",
"application/vnd.openxmlformats-officedocument.presentationml.notesMaster+xml",
"application/vnd.openxmlformats-officedocument.presentationml.notesSlide+xml",
"application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml",
"application/vnd.openxmlformats-officedocument.presentationml.presentationProperties+xml",
"application/vnd.openxmlformats-officedocument.presentationml.slide+xml",
"application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml",
"application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml",
"application/vnd.openxmlformats-officedocument.presentationml.slideshow.main+xml",
"application/vnd.openxmlformats-officedocument.presentationml.slideUpdateInfo+xml",
"application/vnd.openxmlformats-officedocument.presentationml.tableStyles+xml",
"application/vnd.openxmlformats-officedocument.presentationml.tags+xml",
"application/vnd.openxmlformats-officedocument.presentationml.template.main+xml",
"application/vnd.openxmlformats-officedocument.presentationml.viewProps+xml",
"application/vnd.openxmlformats-officedocument.spreadsheetml.calcChain+xml",
"application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml",
"application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml",
"application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml",
"application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml",
"application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml",
"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml",
"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml",
"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml",
"application/vnd.openxmlformats-officedocument.spreadsheetml.queryTable+xml",
"application/vnd.openxmlformats-officedocument.spreadsheetml.revisionHeaders+xml",
"application/vnd.openxmlformats-officedocument.spreadsheetml.revisionLog+xml",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml",
"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
"application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml",
"application/vnd.openxmlformats-officedocument.spreadsheetml.tableSingleCells+xml",
"application/vnd.openxmlformats-officedocument.spreadsheetml.userNames+xml",
"application/vnd.openxmlformats-officedocument.spreadsheetml.volatileDependencies+xml",
"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml",
"application/vnd.openxmlformats-officedocument.theme+xml",
"application/vnd.openxmlformats-officedocument.themeOverride+xml",
"application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml",
"application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml",
"application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml",
"application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml",
"application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml",
"application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml",
"application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml",
"application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml",
"application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml",
"application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml",
"application/vnd.openxmlformats-package.core-properties+xml",
"application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml",
"application/xml"
};
}
}
Comments
Anonymous
December 10, 2007
I have news! I am leaving my current job documenting XML technologies (primarily LINQ to XML), and takingAnonymous
December 10, 2007
Given my focus on LINQ to XML over the last couple of years, I have to say that LINQ to XML and OpenAnonymous
March 31, 2008
Theseresourceisforpreparingtheproject,supervisedbyMONOandGOOGLESUMMERCODE2008,Converti...Anonymous
March 31, 2008
These resource is for preparing the project ,supervised by MONO and GOOGLE SUMMER CODE 2008,ConvertingAnonymous
May 13, 2008
Hi, I need ur help. I am unable to dispose XDocument . My requirement is very simple, simple reading and writing to xml file using xdocument. pls provide your inputs to how to proceed.Anonymous
May 14, 2008
XDocument doesn't implement IDisposable. Take a look at the documentation. This topic shows how to load an XDocument from a file: http://msdn.microsoft.com/en-us/library/bb343181.aspx This topic shows how to save it back to a file: http://msdn.microsoft.com/en-us/library/bb345830.aspx Also, take a look at the LINQ to XML Programming Guide: http://msdn.microsoft.com/en-us/library/bb387087.aspxAnonymous
May 14, 2008
Many a Thanks for ur reply. My issue is i have to keep writing xml file through web application, so it wil b written by as many users. If i don;t close or dispose, it says, it is being used by other process.Anonymous
May 19, 2008
This example takes the plumbing code from Packages and Parts , refactors it a bit, and creates an object graph that will be easy to query using LINQ to XML. There are a few points to note about this code: · To make reading the code as easy as possible