Setting WordML Properties
This article explains how to read and edit the properties of a WordprocessingML document programmatically, without using an editor (such as Word 2007). The properties are edited using .NET classes, including the System.IO.Packaging API in .NET 3.0 (formerly known as WinFX).
The properties exposed include both application-centric (like Application type, number of Lines, Words etc.) and core-centric (Creator, Created Date, Modified Date) properties. Note that "core" properties are associated with all Open XML documents, while "application" properties are those properties only associated with a specific type of Open XML document (WordprocessingML in this case).
The XML documents ‘docProps/app.xml’ and ‘docProps/core.xml’ describe the properties of the Word document.
Contents of app.xml

Contents of core.xml

To read the Application and Core centric properties,the parts of the document selected,i.e. the app.xml and core.xml files must be extracted.
The following code is to extract the Application and Core files
Code to Extract Package Parts
To display the properties in the UI,the package parts of the word document are extracted into a folder(here named as Target,which is created in ‘bin’) from which the xml files,app.xml and core.xml are read.
This part of code recognises the parts,i.e app.xml and core.xml, that are to be extracted
public static void ExtractPackageParts(string packagePath, string targetDirectory)
{
// Create a new Target directory. If the Target directory
// exists, first delete it and then create a new empty one.
DirectoryInfo directoryInfo = new DirectoryInfo(targetDirectory);
if (directoryInfo.Exists)
directoryInfo.Delete(true);
directoryInfo.Create();
using (Package packageExtract =Package.Open(packagePath, FileMode.Open, FileAccess.Read))
{
PackagePart documentPart = null;
Uri uriDocumentTarget = null;
foreach(PackageRelationship relationship in packageExtract.GetRelationships())
{
// Resolve the Relationship Target Uri
// so the Document Part can be retrieved.
uriDocumentTarget=PackUriHelper.ResolvePartUri(new Uri("/", UriKind.Relative), relationship.TargetUri);
//considering that only app.xml and core.xml are to be extracted
if (uriDocumentTarget.ToString()=="/docProps/app.xml"|| uriDocumentTarget.ToString() == "/docProps/core.xml")
{
// Open the Document Part, write the contents to a file.
documentPart = packageExtract.GetPart(uriDocumentTarget);
// to extract the document.xml
extractPart(documentPart, targetDirectory);
}// end of if statement
}
Uri uriMainRel=new Uri("/_rels/.rels", UriKind.Relative);
PackagePart relationPart = packageExtract.GetPart(uriMainRel);
extractPart(relationPart, targetDirectory); // extracts app.xml and core.xml into the target directory
}// end:using(Package package) - Close & dispose package.
Code written to extract the parts
public void extractPart(PackagePart packagePart, string targetDirectory)
{
// Create a string with the full path to the target directory.
string currentDirectory = Directory.GetCurrentDirectory();
string pathToTarget = currentDirectory + @"\" + targetDirectory;
// Remove leading slash from the Part Uri,
// and make a new Uri from the result
string stringPart = packagePart.Uri.ToString().TrimStart('/');
Uri partUri = new Uri(stringPart, UriKind.Relative);
Uri somePath = new Uri(pathToTarget, UriKind.Absolute);
// Create a full Uri to the Part based on the Package Uri
Uri uriFullPartPath = new Uri(new Uri(pathToTarget, UriKind.Absolute), partUri);
// The variable pathValStr holds the path of the target directory created
pathValStr = somePath.ToString().Substring(8);//work around,deleting 1st 8 chr of-file:///
// Create the necessary Directories based on the Full Part Path
Directory.CreateDirectory(Path.GetDirectoryName(uriFullPartPath.LocalPath));
// Create the file with the Part content
using(FileStream fileStream = new FileStream( uriFullPartPath.LocalPath , FileMode.Create))
{
CopyStream(packagePart.GetStream(), fileStream);
}// end:using(FileStream fileStream) - Close & dispose fileStream.
}// end:extractPart()
This part of code is written to write the part at byte level
public static void CopyStream(Stream source, Stream target)
{
const int bufSize = 0x1000;
byte[] buf = new byte[bufSize];
int bytesRead = 0;
while ((bytesRead = source.Read(buf, 0, bufSize)) > 0)
target.Write(buf,0,(int)bytesRead);
}
Code to read the XML Files and to write them back
On click of ‘Properties’ control on the top left corner of the window, disable all the textboxes. Using a text reader, read the XML files, app.xml and core.xml and load the textboxes with the corresponding values, as shown below
reader = new XmlTextReader(appPath);
reader.Read();
// Can be a call to Read
reader.ReadStartElement("Properties");
// Can be a call to Read
templateInfo.Text = reader.ReadElementString("Template");
b = reader.ReadToFollowing("Words");
if (b)
wordsInfo.Text = reader.ReadElementString("Words");
charactersInfo.Text = reader.ReadElementString("Characters");
applicationInfo.Text=reader.ReadElementString("Application");
b = reader.ReadToFollowing("Lines");
if (b)
linesinfo.Text = reader.ReadElementString("Lines");
reader.Close();
//reading core file
reader = new XmlTextReader(corePath);
reader.Read();
// Can be a call to Read
reader.ReadStartElement("cp:coreProperties");
// Can be a call to Read
titleInfo.Text = reader.ReadElementString("dc:title");
subjectInfo.Text = reader.ReadElementString("dc:subject");
creatorInfo.Text = reader.ReadElementString("dc:creator");
keywordsInfo.Text = reader.ReadElementString("cp:keywords"); descriptionInfo.Text=reader.ReadElementString ("dc:description" );
b = reader.ReadToFollowing("dcterms:created");
if (b)
{
DateTime createdtime = DateTime.Parse(reader. ReadElementString("dcterms:created"));
createdTimeInfo.Text=createdtime.ToUniversalTime(). ToString();
}
b = reader.ReadToFollowing("dcterms:modified");
if (b)
{
DateTime modtime=DateTime.Parse(reader.ReadElementString ("dcterms:modified"));
modifiedInfo.Text = modtime.ToUniversalTime().ToString();
}
reader.Close();
On click of button OK, the contents of textboxes are written back into the XML files, using a text writer, and the XML files are packed back as the part of word document package
//get the contents of the nodes that have corresponding editable fields in the Properties UI
XmlNode oldCreator=doc.DocumentElement.SelectSingleNode("//dc:creator" ,nsmanager);
XmlNode oldTitle = doc.DocumentElement.SelectSingleNode("//dc:title" ,nsmanager);
XmlNode oldSubject=doc.DocumentElement.SelectSingleNode("//dc:subject" ,nsmanager);
XmlNode oldKeywords=doc.DocumentElement.SelectSingleNode ("//cp:keywords" , nsmanager);
XmlNode oldDescription=doc.DocumentElement.SelectSingleNode ("//dc:description", nsmanager);
XmlElement root = doc.DocumentElement;
// Create the nodes that would now hold the new text values
XmlNode newCreator = doc.CreateElement("dc:creator",namespacedc );
newCreator.InnerXml = creatorInfo .Text;
XmlNode newTitle = doc.CreateElement("dc:title", namespacedc );
newTitle.InnerXml = titleInfo.Text;
XmlNode newSubject = doc.CreateElement("dc:subject", namespacedc );
newSubject.InnerXml = subjectInfo.Text;
XmlNode newKeywords = doc.CreateElement("cp:keywords", namespacecp );
newKeywords.InnerXml = keywordsInfo.Text;
XmlNode newDescription =doc.CreateElement("dc:description", namespacedc);
newDescription.InnerXml = descriptionInfo.Text;
// insert the values enterd into the editable fields into xml file
root.ReplaceChild(newTitle,oldTitle);
root.ReplaceChild(newSubject,oldSubject);
root.ReplaceChild(newKeywords, oldKeywords);
root.ReplaceChild( newDescription,oldDescription);
root.ReplaceChild(newCreator, oldCreator);
reader.Close();
// save back the file,core.xml
XmlTextWriter writer=new XmlTextWriter(corePath, System.Text.Encoding .UTF8
doc.Save(writer)
writer.Flush();
writer.Close();
Code to Repack the XML files back into the word document
package = Package.Open(docFileName);
Uri delUri = new Uri("/docProps/core.xml", UriKind.Relative);
package.DeletePart(delUri); // delete the existing XML file to replace it with the new file
package.DeleteRelationship("rId2");
Uri uriApp = new Uri("/docProps/core.xml", UriKind.Relative);
PackagePart partCore = package.CreatePart(uriApp, "application/vnd.openxmlformats-package.core-properties+xml");
StreamWriter partWrtCore = new StreamWriter(partCore.GetStream(FileMode.Create, FileAccess.ReadWrite));
XmlDocument newDocCore = new XmlDocument();
newDocCore.Load(packPath);
newDocCore.Save(partWrtCore);
partWrtCore.Close();
package.Flush();
//-- Step 4 - Create the relationship file
uriApp = new Uri("/docProps/core.xml", UriKind.Relative);
// PackageRelationship
rel = package.CreateRelationship(uriApp, TargetMode.Internal, "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties", "rId2");
package.Flush();
//-- Step 5- Close the document.
package.Close();
Steps to be followed to edit the properties of selected word document
STEP 1:
Click on Properties, the control present on the top left corner. The user is asked to select a document

STEP 2:
The properties of the file selected are displayed.


STEP 3:
On editing, click OK, to update the properties
STEP 4:
To view the properties of the word document
Left Click on to the File button, as shown

Select Finish>Properties

The properties are as displayed

Hope this article helps getting started...