The OpenXmlDocument, WordprocessingML, and SpreadsheetML Classes (Dec 19, 2007)

This page presents a new version of the OpenXmlDocument, WordprocessingML, and SpreadsheetML classes.

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

Blog TOC

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 string Name { get; set; }
public Package Package { get; set; }
public List<Relationship> Relationships { get; set; }
public XNamespace RelationshipNamespace =
"https://schemas.openxmlformats.org/officeDocument/2006/relationships";

        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.sheet.main+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"
};
}

    class WordprocessingML : OpenXmlDocument
{
public class Comment
{
public int Id { get; set; }
public string Text { get; set; }
public string Author { get; set; }
public Paragraph Parent { get; set; }
public Comment(Paragraph parent) { Parent = parent; }
}

        public class Paragraph
{
public XElement ParagraphElement { get; set; }
public string StyleName { get; set; }
public string Text { get; set; }
public IEnumerable<Comment> Comments()
{
XNamespace w = Parent.WordprocessingMLNamespace;
XElement p = ParagraphElement;

                var commentIds = p
.Elements(w + "commentRangeStart")
.Attributes(w + "id")
.Select(c => (int)c);

                return
commentIds
.Select(i =>
new Comment(this)
{
Id = i,
Author =
Parent.CommentsRelationship.XDocument
.Root
.Elements(w + "comment")
.Where(c => (int)c.Attribute(w + "id") == i)
.First()
.Attribute(w + "author")
.Value,
Text =
Parent.CommentsRelationship.XDocument
.Root
.Elements(w + "comment")
.Where(c => (int)c.Attribute(w + "id") == i)
.First()
.Descendants(w + "p")
.Select(run => run
.Descendants(w + "t")
.StringConcatenate(e => (string)e)
+ "n")
.Aggregate(new StringBuilder(), (sb, v) => sb.Append(v), sb => sb.ToString())
.Trim()
}
);
}
public WordprocessingML Parent { get; set; }
public Paragraph(WordprocessingML parent) { Parent = parent; }
}

        public const string DocumentRelationshipType =
"https://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
public const string StylesRelationshipType =
"https://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
public const string CommentsRelationshipType =
"https://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
public XNamespace WordprocessingMLNamespace =
"https://schemas.openxmlformats.org/wordprocessingml/2006/main";

        public Relationship DocumentRelationship { get; set; }
public Relationship StylesRelationship { get; set; }
public Relationship CommentsRelationship { get; set; }

        public WordprocessingML(string name)
: base(name)
{
DocumentRelationship =
(
from dr in this.Relationships
where dr.RelationshipType == DocumentRelationshipType
select dr