YNICTE/packages/OfficeOpenXml.Core.ExcelPac.../src/OfficeOpenXml.Core.ExcelPac.../ExcelPackage.cs

329 lines
11 KiB
C#

/*
* You may amend and distribute as you like, but don't remove this header!
*
* ExcelPackage provides server-side generation of Excel 2007 spreadsheets.
* See http://www.codeplex.com/ExcelPackage for details.
*
* Copyright 2007 © Dr John Tunnicliffe
* mailto:dr.john.tunnicliffe@btinternet.com
* All rights reserved.
*
* ExcelPackage is an Open Source project provided under the
* GNU General Public License (GPL) as published by the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* The GNU General Public License can be viewed at http://www.opensource.org/licenses/gpl-license.php
* If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
*
* The code for this project may be used and redistributed by any means PROVIDING it is
* not sold for profit without the author's written consent, and providing that this notice
* and the author's name and all copyright notices remain intact.
*
* All code and executables are provided "as is" with no warranty either express or implied.
* The author accepts no liability for any damage or loss of business that this product may cause.
*/
/*
* Code change notes:
*
* Author Change Date
* ******************************************************************************
* John Tunnicliffe Initial Release 01-Jan-2007
* ******************************************************************************
*/
using System;
using System.IO;
using System.IO.Packaging;
using System.Xml.Linq;
namespace OfficeOpenXml.Core.ExcelPackage
{
/// <summary>
/// Represents an Excel 2007 XLSX file package. Opens the file and provides access
/// to all the components (workbook, worksheets, properties etc.).
/// </summary>
public class ExcelPackage : IDisposable
{
#region Properties
/// <summary>
/// Provides access to the main schema used by all Excel components
/// </summary>
protected internal static XNamespace schemaMain = @"http://schemas.openxmlformats.org/spreadsheetml/2006/main";
/// <summary>
/// Provides access to the relationship schema
/// </summary>
protected internal static XNamespace schemaRelationships = @"http://schemas.openxmlformats.org/officeDocument/2006/relationships";
private Package _package;
private string _outputFolderPath;
private ExcelWorkbook _workbook;
#endregion
#region ExcelPackage Constructors
/// <summary>
/// Creates a new instance of ExcelPackage based on an underlying storage stream.
/// Pass an OfficeCryptoStream to support encrypted (password-protected) Excel files.
/// </summary>
/// <param name="packageStream">If stream is empty, new package is created, otherwise
/// it is opened by reading from the stream.</param>
public ExcelPackage(Stream packageStream)
{
if (packageStream.Length > 0)
{
// open the existing package
_package = Package.Open(packageStream, FileMode.Open, FileAccess.ReadWrite);
}
else
{
// create a new package and add the main workbook.xml part
_package = Package.Open(packageStream, FileMode.Create);
InitializeNewPackage();
}
}
/// <summary>
/// Creates a new instance of the ExcelPackage class based on a existing file or creates a new file.
/// </summary>
/// <param name="newFile">If newFile exists, it is opened. Otherwise it is created from scratch.</param>
public ExcelPackage(FileInfo newFile)
{
_outputFolderPath = newFile.DirectoryName;
if (newFile.Exists)
{
// open the existing package
_package = Package.Open(newFile.FullName, FileMode.Open, FileAccess.ReadWrite);
}
else
{
// create a new package and add the main workbook.xml part
_package = Package.Open(newFile.FullName, FileMode.Create, FileAccess.ReadWrite);
InitializeNewPackage();
}
}
private void InitializeNewPackage()
{
if (_package == null) { throw new Exception("Package is null."); }
// save a temporary part to create the default application/xml content type
Uri uriDefaultContentType = new Uri("/default.xml", UriKind.Relative);
PackagePart partTemp = _package.CreatePart(uriDefaultContentType, "application/xml", CompressionOption.Normal);
XDocument workbook = Workbook.WorkbookXml; // this will create the workbook xml in the package
// create the relationship to the main part
_package.CreateRelationship(Workbook.WorkbookUri, TargetMode.Internal, schemaRelationships.NamespaceName + "/officeDocument");
// remove the temporary part that created the default xml content type
_package.DeletePart(uriDefaultContentType);
}
/// <summary>
/// Creates a new instance of the ExcelPackage class based on a existing template.
/// WARNING: If newFile exists, it is deleted!
/// </summary>
/// <param name="newFile">The name of the Excel file to be created</param>
/// <param name="template">The name of the Excel template to use as the basis of the new Excel file</param>
public ExcelPackage(FileInfo newFile, FileInfo template)
{
_outputFolderPath = newFile.DirectoryName;
if (template.Exists)
{
if (newFile.Exists)
{
try
{
newFile.Delete();
}
catch (Exception ex)
{
throw new Exception("ExcelPackage Error: Target file already exists and is locked.", ex);
}
}
newFile = template.CopyTo(newFile.FullName);
newFile.IsReadOnly = false;
_package = Package.Open(newFile.FullName, FileMode.Open, FileAccess.ReadWrite);
}
else
throw new Exception("ExcelPackage Error: Passed invalid TemplatePath to Excel Template");
}
#endregion
#region Public Properties
/// <summary>
/// Setting DebugMode to true will cause the Save method to write the
/// raw XML components to the same folder as the output Excel file
/// </summary>
public bool DebugMode = false;
/// <summary>
/// Returns a reference to the file package
/// </summary>
public Package Package => _package;
/// <summary>
/// Returns a reference to the workbook component within the package.
/// All worksheets and cells can be accessed through the workbook.
/// </summary>
public ExcelWorkbook Workbook
{
get
{
if (_workbook == null)
_workbook = new ExcelWorkbook(this);
return (_workbook);
}
}
#endregion
#region WriteDebugFile
/// <summary>
/// Writes a debug file to the output folder, but only if DebugMode = true
/// </summary>
/// <param name="xmlDoc">The XmlDocument to save to the file system</param>
/// <param name="subFolder">The subfolder in which the file is to be saved</param>
/// <param name="FileName">The name of the file to save.</param>
protected internal void WriteDebugFile(XDocument xmlDoc, string subFolder, string FileName)
{
if (DebugMode)
{
DirectoryInfo dir = new DirectoryInfo(_outputFolderPath + "/" + subFolder);
if (!dir.Exists)
dir.Create();
FileInfo file = new FileInfo(_outputFolderPath + "/" + subFolder + "/" + FileName);
if (file.Exists)
{
file.IsReadOnly = false;
file.Delete();
}
using (var fs = new FileStream(file.FullName, FileMode.OpenOrCreate))
{
xmlDoc.Save(fs);
}
}
}
#endregion
///// <summary>
///// Returns the Uri to a parent part (e.g. workbook.xml)
///// </summary>
///// <param name="Relationship">The relationship the </param>
///// <returns></returns>
//protected internal Uri GetMainUri(string Relationship)
//{
// Uri uriMain = null;
// // Get the Uri to the main part
// Uri uriParent = new Uri("/", UriKind.Relative);
// PackageRelationship relationship = GetMainRelationship(Relationship);
// if (relationship != null)
// uriMain = PackUriHelper.ResolvePartUri(uriParent, relationship.TargetUri);
// return (uriMain);
//}
///// <summary>
/////
///// </summary>
///// <param name="Relationship"></param>
///// <returns></returns>
//protected internal PackageRelationship GetMainRelationship(string Relationship)
//{
// PackageRelationship relMain = null;
// foreach (PackageRelationship relationship in _package.GetRelationshipsByType(schemaRelationships + "/" + Relationship))
// {
// relMain = relationship;
// break; // There should only be one main part
// }
// return (relMain);
//}
#region GetSharedUri
/// <summary>
/// Obtains the Uri to a shared part (e.g. sharedstrings.xml)
/// </summary>
/// <param name="uriParent">Uri to the parent component</param>
/// <param name="Relationship">The relationship to the parent component</param>
/// <returns>The Uri to a shared part</returns>
protected internal Uri GetSharedUri(Uri uriParent, string Relationship)
{
Uri uriShared = null;
PackagePart partParent = _package.GetPart(uriParent);
// Get the Uri to the shared part
foreach (System.IO.Packaging.PackageRelationship relationship in partParent.GetRelationshipsByType(schemaRelationships + "/" + Relationship))
{
uriShared = PackUriHelper.ResolvePartUri(uriParent, relationship.TargetUri);
break; // There should only be one shared resource
}
return (uriShared);
}
#endregion
#region AddSchemaAttribute
///// <summary>
///// Adds additional schema attributes to the root element
///// </summary>
///// <param name="root">The root element</param>
///// <param name="schema">The schema to apply</param>
//protected internal static void AddSchemaAttribute(XmlElement root, string schema)
//{
// var nsAttribute = root.OwnerDocument.CreateAttribute("xmlns");
// nsAttribute.Value = schema;
// root.Attributes.Append(nsAttribute);
//}
#endregion
#region SavePart
/// <summary>
/// Saves the XmlDocument into the package at the specified Uri.
/// </summary>
/// <param name="uriPart">The Uri of the component</param>
/// <param name="xmlPart">The XmlDocument to save</param>
protected internal void SavePart(Uri uriPart, XDocument xmlPart)
{
PackagePart partPack = _package.GetPart(uriPart);
xmlPart.Save(partPack.GetStream(FileMode.Create, FileAccess.Write));
}
#endregion
#region Dispose
/// <summary>
/// Closes the package.
/// </summary>
public void Dispose()
{
_package.Close();
}
#endregion
#region Save // ExcelPackage save
/// <summary>
/// Saves all the components back into the package.
/// This method recursively calls the Save method on all sub-components.
/// </summary>
public void Save()
{
Workbook.Save();
}
#endregion
#region GetXmlFromUri
/// <summary>
/// Obtains the XmlDocument from the package referenced by the Uri
/// </summary>
/// <param name="uriPart">The Uri to the component</param>
/// <returns>The XmlDocument of the component</returns>
protected internal XDocument GetXmlFromUri(Uri uriPart)
{
var packPart = _package.GetPart(uriPart);
return XDocument.Load(packPart.GetStream());
}
#endregion
}
}