wordpress hit counter
Welcome to OpenXML Developer Sign in | Join | Help

View/edit WordprocessingML Properties

 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...

 

Published Friday, June 30, 2006 6:20 AM by SanjayKumarM
Filed Under: ,
Attachment(s): Samples.zip

Comments

 

jaderberg said:

I have been trying to implement this code just to extract the app.xml and core.xml files and so have written the code in VB.net up to "Code to read the XML Files and to write them back" however when i run the code i just get the app.xml and core.xml files but they are empty...any ideas why?
July 11, 2009 9:47 AM
Anonymous comments are disabled