none
Programmatically change the name of an office document (OpenXml, of course) RRS feed

  • Question

  • I'm new to using OpenXml to manipulate and change documents, and this may be a dumb question, but.....

    I'm using a "Template.pptx" file stored in a SharePoint library and what I want to do is use this template to produce new pptx files, however I need to make sure the new file has a different, programmatically-set name.  So, how do you change the name of an OpenXml "Package" and/or root Document (PresentationDocument, in this case).

    I do see the "Package.PackageProperties.Title" property, but this seems to be a metadata field (comparable to the OOB Item ContentType Title column in SharePoint), and not the actual file name.  Also, there is the Name property of the SPFile object, but this is read only.

    I don't see something this simple being so hard, but I don't see anywhere in the documentation or API a simple settable method for the name of the file/package.

    Thanks!

    Thursday, February 17, 2011 7:33 PM

Answers

  • I finally figured out how to do this using Linq:

    //All this in one method, but normally broken out, etc.
    protected void SaveFile()
    {
       //Pull Office Doc Template file (in this case a PowerPoint Template) from SP lists
       string templateFilePath = GetSubSiteUrl("Test", "Templates/District Briefing Master.pptx");
       SPList lstRepository = SPContext.Current.Web.Lists["District Briefings"];
       SPList lstTemplate = SPContext.Current.Web.Webs["Test"].Lists["Templates"];
       SPFile pptTemplate = lstTemplate.Items[0].File;
     
       //Convert PowerPoint file into Byte array
       Byte[] byteTemplate = pptTemplate.OpenBinary();
    
       using (MemoryStream mem = new MemoryStream())
       {
         mem.Write(TemplateBytes, 0, (int)TemplateBytes.Length);
    
         //Using System.IO.Packaging, open up the PowerPoint's underlying Open Office Package, using the MemoryStream
         using (Package pkg = Package.Open(mem, FileMode.Open, FileAccess.ReadWrite))
         {
            //Identify relevant Schema references for Open Office document Part (in this case, the Core Properties Part)
            //schema reference for core properties in docProps\core.xml
            const string schemaCoreProperties = "http://schemas.openxmlformats.org/package/2006/metadata/core-properties";
            //schema reference for 'dc' (document core?) properties in docProps\core.xml
            const string schemaDCProperties = "http://purl.org/dc/elements/1.1/";
            //schema reference for 'dcterms' (document core terms?) properties in docProps\core.xml
            const string schemaDCTermProperties = "http://purl.org/dc/terms/";
    
            //Instantiate the PresentationDocument Part (Root Parent Part of a PowerPoint Open Office Document)
    	   using (PresentationDocument ppt = PresentationDocument.Open(mem, true))
            {
              //Set XNamespaces for use in Linq Query
              XNamespace cp = schemaCoreProperties;
              XNamespace dc = schemaDCProperties;
              XNamespace dcterms = schemaDCTermProperties;
    
    		 //Get the child Part, in this case the CoreFilePropertiesPart, of a PowerPoint file as an XDocument
              XDocument xCoreDoc = GetXDocument(ppt.CoreFilePropertiesPart);
    
              //Use Linq query to pull out "title" element
              IEnumerable<XElement> xe = 
                 from el in xCoreDoc.Descendants(dc + "title") 
                 select el;
    
              //Technically, there is only one "title" element, but using foreach loop as example
              foreach (XElement el in xe)
                 el.Value = this.TextBox1.Text; //"Test Title New";
    
              //Save the updated xml Part as an XDocument
              SaveXDocument(ppt.CoreFilePropertiesPart);
            }
         }
       
         pkg.Close();
    
         //save the document back into a new SharePoint list, different from the one the Template came from
         string strSite = "http://sptestdev/";
         string lib = "District Briefings";
         using (SPSite site = new SPSite(strSite))
         {
            using (SPWeb web = site.OpenWeb())
            {
              SPFolder fldr = web.Folders[lib];
              //Change this to use FileStream?
              SPFile file = fldr.Files.Add(strSite + lib + "/District_X.pptx", mem, true);
              file.Update();
            }
         }
       }
    }
    
    
    //Convert an OpenXml Office doc Part into Linq XDocument
    public XDocument GetXDocument(OpenXmlPart part)
    {
       XDocument xdoc = part.Annotation<XDocument>();
    
       if (xdoc != null)
         return xdoc;
    
       using (StreamReader xr = new StreamReader(part.GetStream()))
         xdoc = XDocument.Load(xr);
    
       part.AddAnnotation(xdoc);
       return xdoc;
    }
    
    //Save update to OpenXml Office doc Part using Linq XDocument
    public void SaveXDocument(OpenXmlPart part)
    {
       XDocument xdoc = GetXDocument(part);
       
       if (xdoc != null)
       {
         using (XmlWriter xw = XmlWriter.Create(part.GetStream(FileMode.Create, FileAccess.Write)))
         {
           xdoc.Save(xw);
         }
       }
    }
     
     
     
    
    
    

    Turns out using Linq works wonders, can locate and update just about anything in these OpenXml doc files.

    Thanks for the tips.

    • Marked as answer by sdfsda Monday, February 21, 2011 5:29 PM
    Monday, February 21, 2011 5:29 PM

All replies

  • Hello sdfsda, 

    Thanks for posting. I am trying to involve someone familiar with this topic to further look at this issue. There might be some time delay. Appreciate your patience. Thank you for your understanding and have a nice weekend.


    Bessie Zhao [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Friday, February 18, 2011 9:56 AM
  • I have found that you can make a copy of the file and give it a new name when adding to a Library, but what I still don't see how to do it by renaming the file itself.

     

    Friday, February 18, 2011 7:50 PM
  • Hello sdfsda,

    You can change the title element of the core.xml in docProps but that doesn't carry through when you repackage the .pptx.

    You reference the presentation part, which is located at <root>...<file name>\ppt\presentation.xml. It is a part of the package, and has no 'name' or 'title' element

    Your query says you want to programmatically change the name of the file which is the package of parts. The System.IO.Packaging libary of .NET 4.0 does not provide a method to do that. Instead, you need to use

    System.IO.File.Move()

    You specify the old and new filenames. If the old and new files are on the same physical disk, the file is renamed. Otherwise, it is physically moved (copy made in new location, then - if that was successful - the old file deleted).

    An example:
    System.IO.File.Move(@"C:\From.txt", @"C:\TO.txt");

    or, verbose method:
    File.Copy(oldFileName, NewFileName);
    But if you don't want to delete the old file, skip this call
    File.Delete(oldFileName);

    The SharePoint library needs to upload the new <New File Name>.pptx

    When you are through making copies of the original file you'll need to save it back to the SharePoint library to unlock it.

    Friday, February 18, 2011 7:57 PM
    Moderator
  • I finally figured out how to do this using Linq:

    //All this in one method, but normally broken out, etc.
    protected void SaveFile()
    {
       //Pull Office Doc Template file (in this case a PowerPoint Template) from SP lists
       string templateFilePath = GetSubSiteUrl("Test", "Templates/District Briefing Master.pptx");
       SPList lstRepository = SPContext.Current.Web.Lists["District Briefings"];
       SPList lstTemplate = SPContext.Current.Web.Webs["Test"].Lists["Templates"];
       SPFile pptTemplate = lstTemplate.Items[0].File;
     
       //Convert PowerPoint file into Byte array
       Byte[] byteTemplate = pptTemplate.OpenBinary();
    
       using (MemoryStream mem = new MemoryStream())
       {
         mem.Write(TemplateBytes, 0, (int)TemplateBytes.Length);
    
         //Using System.IO.Packaging, open up the PowerPoint's underlying Open Office Package, using the MemoryStream
         using (Package pkg = Package.Open(mem, FileMode.Open, FileAccess.ReadWrite))
         {
            //Identify relevant Schema references for Open Office document Part (in this case, the Core Properties Part)
            //schema reference for core properties in docProps\core.xml
            const string schemaCoreProperties = "http://schemas.openxmlformats.org/package/2006/metadata/core-properties";
            //schema reference for 'dc' (document core?) properties in docProps\core.xml
            const string schemaDCProperties = "http://purl.org/dc/elements/1.1/";
            //schema reference for 'dcterms' (document core terms?) properties in docProps\core.xml
            const string schemaDCTermProperties = "http://purl.org/dc/terms/";
    
            //Instantiate the PresentationDocument Part (Root Parent Part of a PowerPoint Open Office Document)
    	   using (PresentationDocument ppt = PresentationDocument.Open(mem, true))
            {
              //Set XNamespaces for use in Linq Query
              XNamespace cp = schemaCoreProperties;
              XNamespace dc = schemaDCProperties;
              XNamespace dcterms = schemaDCTermProperties;
    
    		 //Get the child Part, in this case the CoreFilePropertiesPart, of a PowerPoint file as an XDocument
              XDocument xCoreDoc = GetXDocument(ppt.CoreFilePropertiesPart);
    
              //Use Linq query to pull out "title" element
              IEnumerable<XElement> xe = 
                 from el in xCoreDoc.Descendants(dc + "title") 
                 select el;
    
              //Technically, there is only one "title" element, but using foreach loop as example
              foreach (XElement el in xe)
                 el.Value = this.TextBox1.Text; //"Test Title New";
    
              //Save the updated xml Part as an XDocument
              SaveXDocument(ppt.CoreFilePropertiesPart);
            }
         }
       
         pkg.Close();
    
         //save the document back into a new SharePoint list, different from the one the Template came from
         string strSite = "http://sptestdev/";
         string lib = "District Briefings";
         using (SPSite site = new SPSite(strSite))
         {
            using (SPWeb web = site.OpenWeb())
            {
              SPFolder fldr = web.Folders[lib];
              //Change this to use FileStream?
              SPFile file = fldr.Files.Add(strSite + lib + "/District_X.pptx", mem, true);
              file.Update();
            }
         }
       }
    }
    
    
    //Convert an OpenXml Office doc Part into Linq XDocument
    public XDocument GetXDocument(OpenXmlPart part)
    {
       XDocument xdoc = part.Annotation<XDocument>();
    
       if (xdoc != null)
         return xdoc;
    
       using (StreamReader xr = new StreamReader(part.GetStream()))
         xdoc = XDocument.Load(xr);
    
       part.AddAnnotation(xdoc);
       return xdoc;
    }
    
    //Save update to OpenXml Office doc Part using Linq XDocument
    public void SaveXDocument(OpenXmlPart part)
    {
       XDocument xdoc = GetXDocument(part);
       
       if (xdoc != null)
       {
         using (XmlWriter xw = XmlWriter.Create(part.GetStream(FileMode.Create, FileAccess.Write)))
         {
           xdoc.Save(xw);
         }
       }
    }
     
     
     
    
    
    

    Turns out using Linq works wonders, can locate and update just about anything in these OpenXml doc files.

    Thanks for the tips.

    • Marked as answer by sdfsda Monday, February 21, 2011 5:29 PM
    Monday, February 21, 2011 5:29 PM