blob: f52982631b0f47f42de22fbd0fd56f53792baf4f [file] [log] [blame]
/*******************************************************************************
* You may amend and distribute as you like, but don't remove this header!
*
* EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
* See http://www.codeplex.com/EPPlus for details.
*
* Copyright (C) 2011 Jan Källman
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
* If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
*
* 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
* ******************************************************************************
* Jan Källman Initial Release 2011-01-01
* Jan Källman License changed GPL-->LGPL 2011-12-27
* Richard Tallent Fix escaping of quotes 2012-10-31
*******************************************************************************/
using System;
using System.Xml;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Globalization;
using OfficeOpenXml.Utils;
using OfficeOpenXml.FormulaParsing;
using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
using System.Drawing;
namespace OfficeOpenXml
{
#region Public Enum ExcelCalcMode
/// <summary>
/// How the application should calculate formulas in the workbook
/// </summary>
public enum ExcelCalcMode
{
/// <summary>
/// Indicates that calculations in the workbook are performed automatically when cell values change.
/// The application recalculates those cells that are dependent on other cells that contain changed values.
/// This mode of calculation helps to avoid unnecessary calculations.
/// </summary>
Automatic,
/// <summary>
/// Indicates tables be excluded during automatic calculation
/// </summary>
AutomaticNoTable,
/// <summary>
/// Indicates that calculations in the workbook be triggered manually by the user.
/// </summary>
Manual
}
#endregion
/// <summary>
/// Represents the Excel workbook and provides access to all the
/// document properties and worksheets within the workbook.
/// </summary>
public sealed class ExcelWorkbook : XmlHelper
{
internal class SharedStringItem
{
internal int pos;
internal string Text;
internal bool isRichText = false;
}
#region Private Properties
internal ExcelPackage _package;
private ExcelWorksheets _worksheets;
private OfficeProperties _properties;
private ExcelStyles _styles;
#endregion
#region ExcelWorkbook Constructor
/// <summary>
/// Creates a new instance of the ExcelWorkbook class.
/// </summary>
/// <param name="package">The parent package</param>
/// <param name="namespaceManager">NamespaceManager</param>
internal ExcelWorkbook(ExcelPackage package, XmlNamespaceManager namespaceManager) :
base(namespaceManager)
{
_package = package;
WorkbookUri = new Uri("/xl/workbook.xml", UriKind.Relative);
SharedStringsUri = new Uri("/xl/sharedStrings.xml", UriKind.Relative);
StylesUri = new Uri("/xl/styles.xml", UriKind.Relative);
_names = new ExcelNamedRangeCollection(this);
_namespaceManager = namespaceManager;
TopNode = WorkbookXml.DocumentElement;
SchemaNodeOrder = new string[] { "fileVersion", "fileSharing", "workbookPr", "workbookProtection", "bookViews", "sheets", "functionGroups", "functionPrototypes", "externalReferences", "definedNames", "calcPr", "oleSize", "customWorkbookViews", "pivotCaches", "smartTagPr", "smartTagTypes", "webPublishing", "fileRecoveryPr", };
FullCalcOnLoad = true; //Full calculation on load by default, for both new workbooks and templates.
GetSharedStrings();
}
#endregion
internal Dictionary<string, SharedStringItem> _sharedStrings = new Dictionary<string, SharedStringItem>(); //Used when reading cells.
internal List<SharedStringItem> _sharedStringsList = new List<SharedStringItem>(); //Used when reading cells.
internal ExcelNamedRangeCollection _names;
internal int _nextDrawingID = 0;
internal int _nextTableID = int.MinValue;
internal int _nextPivotTableID = int.MinValue;
internal XmlNamespaceManager _namespaceManager;
internal FormulaParser _formulaParser = null;
internal FormulaParserManager _parserManager;
internal CellStore<List<Token>> _formulaTokens;
/// <summary>
/// Read shared strings to list
/// </summary>
private void GetSharedStrings()
{
if (_package.Package.PartExists(SharedStringsUri))
{
var xml = _package.GetXmlFromUri(SharedStringsUri);
XmlNodeList nl = xml.SelectNodes("//d:sst/d:si", NameSpaceManager);
_sharedStringsList = new List<SharedStringItem>();
if (nl != null)
{
foreach (XmlNode node in nl)
{
XmlNode n = node.SelectSingleNode("d:t", NameSpaceManager);
if (n != null)
{
_sharedStringsList.Add(new SharedStringItem() { Text = ConvertUtil.ExcelDecodeString(n.InnerText) });
}
else
{
_sharedStringsList.Add(new SharedStringItem() { Text = node.InnerXml, isRichText = true });
}
}
}
//Delete the shared string part, it will be recreated when the package is saved.
foreach (var rel in Part.GetRelationships())
{
if (rel.TargetUri.OriginalString.EndsWith("sharedstrings.xml", StringComparison.InvariantCultureIgnoreCase))
{
Part.DeleteRelationship(rel.Id);
break;
}
}
_package.Package.DeletePart(SharedStringsUri); //Remove the part, it is recreated when saved.
}
}
internal void GetDefinedNames()
{
XmlNodeList nl = WorkbookXml.SelectNodes("//d:definedNames/d:definedName", NameSpaceManager);
if (nl != null)
{
foreach (XmlElement elem in nl)
{
string fullAddress = elem.InnerText;
int localSheetID;
ExcelWorksheet nameWorksheet;
if(!int.TryParse(elem.GetAttribute("localSheetId"), out localSheetID))
{
localSheetID = -1;
nameWorksheet=null;
}
else
{
nameWorksheet=Worksheets[localSheetID + 1];
}
var addressType = ExcelAddressBase.IsValid(fullAddress);
ExcelRangeBase range;
ExcelNamedRange namedRange;
if (fullAddress.IndexOf("[") == 0)
{
int start = fullAddress.IndexOf("[");
int end = fullAddress.IndexOf("]", start);
if (start >= 0 && end >= 0)
{
string externalIndex = fullAddress.Substring(start + 1, end - start - 1);
int index;
if (int.TryParse(externalIndex, out index))
{
if (index > 0 && index <= _externalReferences.Count)
{
fullAddress = fullAddress.Substring(0, start) + "[" + _externalReferences[index - 1] + "]" + fullAddress.Substring(end + 1);
}
}
}
}
if (addressType == ExcelAddressBase.AddressType.Invalid || addressType == ExcelAddressBase.AddressType.InternalName || addressType == ExcelAddressBase.AddressType.ExternalName || addressType==ExcelAddressBase.AddressType.Formula || addressType==ExcelAddressBase.AddressType.ExternalAddress) //A value or a formula
{
double value;
range = new ExcelRangeBase(this, nameWorksheet, elem.GetAttribute("name"), true);
if (nameWorksheet == null)
{
namedRange = _names.Add(elem.GetAttribute("name"), range);
}
else
{
namedRange = nameWorksheet.Names.Add(elem.GetAttribute("name"), range);
}
if (fullAddress.StartsWith("\"")) //String value
{
namedRange.NameValue = fullAddress.Substring(1,fullAddress.Length-2);
}
else if (double.TryParse(fullAddress, NumberStyles.Any, CultureInfo.InvariantCulture, out value))
{
namedRange.NameValue = value;
}
else
{
//if (addressType == ExcelAddressBase.AddressType.ExternalAddress || addressType == ExcelAddressBase.AddressType.ExternalName)
//{
// var r = new ExcelAddress(fullAddress);
// namedRange.NameFormula = '\'[' + r._wb
//}
//else
//{
namedRange.NameFormula = fullAddress;
//}
}
}
else
{
ExcelAddress addr = new ExcelAddress(fullAddress, _package, null);
if (localSheetID > -1)
{
if (string.IsNullOrEmpty(addr._ws))
{
namedRange = Worksheets[localSheetID + 1].Names.Add(elem.GetAttribute("name"), new ExcelRangeBase(this, Worksheets[localSheetID + 1], fullAddress, false));
}
else
{
namedRange = Worksheets[localSheetID + 1].Names.Add(elem.GetAttribute("name"), new ExcelRangeBase(this, Worksheets[addr._ws], fullAddress, false));
}
}
else
{
var ws = Worksheets[addr._ws];
namedRange = _names.Add(elem.GetAttribute("name"), new ExcelRangeBase(this, ws, fullAddress, false));
}
}
if (elem.GetAttribute("hidden") == "1" && namedRange != null) namedRange.IsNameHidden = true;
if(!string.IsNullOrEmpty(elem.GetAttribute("comment"))) namedRange.NameComment=elem.GetAttribute("comment");
}
}
}
#region Worksheets
/// <summary>
/// Provides access to all the worksheets in the workbook.
/// </summary>
public ExcelWorksheets Worksheets
{
get
{
if (_worksheets == null)
{
var sheetsNode = _workbookXml.DocumentElement.SelectSingleNode("d:sheets", _namespaceManager);
if (sheetsNode == null)
{
sheetsNode = CreateNode("d:sheets");
}
_worksheets = new ExcelWorksheets(_package, _namespaceManager, sheetsNode);
}
return (_worksheets);
}
}
#endregion
/// <summary>
/// Provides access to named ranges
/// </summary>
public ExcelNamedRangeCollection Names
{
get
{
return _names;
}
}
#region Workbook Properties
internal FormulaParser FormulaParser
{
get
{
if (_formulaParser == null)
{
_formulaParser = new FormulaParser(new EpplusExcelDataProvider(_package));
}
return _formulaParser;
}
}
public FormulaParserManager FormulaParserManager
{
get
{
if (_parserManager == null)
{
_parserManager = new FormulaParserManager(FormulaParser);
}
return _parserManager;
}
}
ExcelProtection _protection = null;
/// <summary>
/// Access properties to protect or unprotect a workbook
/// </summary>
public ExcelProtection Protection
{
get
{
if (_protection == null)
{
_protection = new ExcelProtection(NameSpaceManager, TopNode, this);
_protection.SchemaNodeOrder = SchemaNodeOrder;
}
return _protection;
}
}
ExcelWorkbookView _view = null;
/// <summary>
/// Access to workbook view properties
/// </summary>
public ExcelWorkbookView View
{
get
{
if (_view == null)
{
_view = new ExcelWorkbookView(NameSpaceManager, TopNode, this);
}
return _view;
}
}
/// <summary>
/// URI to the workbook inside the package
/// </summary>
internal Uri WorkbookUri { get; private set; }
/// <summary>
/// URI to the styles inside the package
/// </summary>
internal Uri StylesUri { get; private set; }
/// <summary>
/// URI to the shared strings inside the package
/// </summary>
internal Uri SharedStringsUri { get; private set; }
/// <summary>
/// Returns a reference to the workbook's part within the package
/// </summary>
internal Packaging.ZipPackagePart Part { get { return (_package.Package.GetPart(WorkbookUri)); } }
#region WorkbookXml
private XmlDocument _workbookXml;
/// <summary>
/// Provides access to the XML data representing the workbook in the package.
/// </summary>
public XmlDocument WorkbookXml
{
get
{
if (_workbookXml == null)
{
CreateWorkbookXml(_namespaceManager);
}
return (_workbookXml);
}
}
const string codeModuleNamePath = "d:workbookPr/@codeName";
internal string CodeModuleName
{
get
{
return GetXmlNodeString(codeModuleNamePath);
}
set
{
SetXmlNodeString(codeModuleNamePath,value);
}
}
internal void CodeNameChange(string value)
{
CodeModuleName = value;
}
const string date1904Path = "d:workbookPr/@date1904";
internal const double date1904Offset = 365.5 * 4; // offset to fix 1900 and 1904 differences, 4 OLE years
/// <summary>
/// The date systems used by Microsoft Excel can be based on one of two different dates. By default, a serial number of 1 in Microsoft Excel represents January 1, 1900.
/// The default for the serial number 1 can be changed to represent January 2, 1904.
/// This option was included in Microsoft Excel for Windows to make it compatible with Excel for the Macintosh, which defaults to January 2, 1904.
/// </summary>
public bool Date1904
{
get
{
return GetXmlNodeBool(date1904Path, false);
}
set
{
if (Date1904 != value)
{
// Like Excel when the option it's changed update it all cells with Date format
foreach (var item in Worksheets)
{
item.UpdateCellsWithDate1904Setting();
}
}
SetXmlNodeBool(date1904Path, value, false);
}
}
/// <summary>
/// Create or read the XML for the workbook.
/// </summary>
private void CreateWorkbookXml(XmlNamespaceManager namespaceManager)
{
if (_package.Package.PartExists(WorkbookUri))
_workbookXml = _package.GetXmlFromUri(WorkbookUri);
else
{
// create a new workbook part and add to the package
Packaging.ZipPackagePart partWorkbook = _package.Package.CreatePart(WorkbookUri, @"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml", _package.Compression);
// create the workbook
_workbookXml = new XmlDocument(namespaceManager.NameTable);
_workbookXml.PreserveWhitespace = ExcelPackage.preserveWhitespace;
// create the workbook element
XmlElement wbElem = _workbookXml.CreateElement("workbook", ExcelPackage.schemaMain);
// Add the relationships namespace
wbElem.SetAttribute("xmlns:r", ExcelPackage.schemaRelationships);
_workbookXml.AppendChild(wbElem);
// create the bookViews and workbooks element
XmlElement bookViews = _workbookXml.CreateElement("bookViews", ExcelPackage.schemaMain);
wbElem.AppendChild(bookViews);
XmlElement workbookView = _workbookXml.CreateElement("workbookView", ExcelPackage.schemaMain);
bookViews.AppendChild(workbookView);
// save it to the package
StreamWriter stream = new StreamWriter(partWorkbook.GetStream(FileMode.Create, FileAccess.Write));
_workbookXml.Save(stream);
//stream.Close();
}
}
#endregion
#region StylesXml
private XmlDocument _stylesXml;
/// <summary>
/// Provides access to the XML data representing the styles in the package.
/// </summary>
public XmlDocument StylesXml
{
get
{
if (_stylesXml == null)
{
if (_package.Package.PartExists(StylesUri))
_stylesXml = _package.GetXmlFromUri(StylesUri);
else
{
// create a new styles part and add to the package
Packaging.ZipPackagePart part = _package.Package.CreatePart(StylesUri, @"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml", _package.Compression);
// create the style sheet
StringBuilder xml = new StringBuilder("<styleSheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">");
xml.Append("<numFmts />");
xml.Append("<fonts count=\"1\"><font><sz val=\"11\" /><name val=\"Calibri\" /></font></fonts>");
xml.Append("<fills><fill><patternFill patternType=\"none\" /></fill><fill><patternFill patternType=\"gray125\" /></fill></fills>");
xml.Append("<borders><border><left /><right /><top /><bottom /><diagonal /></border></borders>");
xml.Append("<cellStyleXfs count=\"1\"><xf numFmtId=\"0\" fontId=\"0\" /></cellStyleXfs>");
xml.Append("<cellXfs count=\"1\"><xf numFmtId=\"0\" fontId=\"0\" xfId=\"0\" /></cellXfs>");
xml.Append("<cellStyles><cellStyle name=\"Normal\" xfId=\"0\" builtinId=\"0\" /></cellStyles>");
xml.Append("<dxfs count=\"0\" />");
xml.Append("</styleSheet>");
_stylesXml = new XmlDocument();
_stylesXml.LoadXml(xml.ToString());
//Save it to the package
StreamWriter stream = new StreamWriter(part.GetStream(FileMode.Create, FileAccess.Write));
_stylesXml.Save(stream);
//stream.Close();
// create the relationship between the workbook and the new shared strings part
_package.Workbook.Part.CreateRelationship(UriHelper.GetRelativeUri(WorkbookUri, StylesUri), Packaging.TargetMode.Internal, ExcelPackage.schemaRelationships + "/styles");
}
}
return (_stylesXml);
}
set
{
_stylesXml = value;
}
}
/// <summary>
/// Package styles collection. Used internally to access style data.
/// </summary>
public ExcelStyles Styles
{
get
{
if (_styles == null)
{
_styles = new ExcelStyles(NameSpaceManager, StylesXml, this);
}
return _styles;
}
}
#endregion
#region Office Document Properties
/// <summary>
/// The office document properties
/// </summary>
public OfficeProperties Properties
{
get
{
if (_properties == null)
{
// Create a NamespaceManager to handle the default namespace,
// and create a prefix for the default namespace:
_properties = new OfficeProperties(_package, NameSpaceManager);
}
return _properties;
}
}
#endregion
#region CalcMode
private string CALC_MODE_PATH = "d:calcPr/@calcMode";
/// <summary>
/// Calculation mode for the workbook.
/// </summary>
public ExcelCalcMode CalcMode
{
get
{
string calcMode = GetXmlNodeString(CALC_MODE_PATH);
switch (calcMode)
{
case "autoNoTable":
return ExcelCalcMode.AutomaticNoTable;
case "manual":
return ExcelCalcMode.Manual;
default:
return ExcelCalcMode.Automatic;
}
}
set
{
switch (value)
{
case ExcelCalcMode.AutomaticNoTable:
SetXmlNodeString(CALC_MODE_PATH, "autoNoTable") ;
break;
case ExcelCalcMode.Manual:
SetXmlNodeString(CALC_MODE_PATH, "manual");
break;
default:
SetXmlNodeString(CALC_MODE_PATH, "auto");
break;
}
}
#endregion
}
private const string FULL_CALC_ON_LOAD_PATH = "d:calcPr/@fullCalcOnLoad";
/// <summary>
/// Should Excel do a full calculation after the workbook has been loaded?
/// <remarks>This property is always true for both new workbooks and loaded templates(on load). If this is not the wanted behavior set this property to false.</remarks>
/// </summary>
public bool FullCalcOnLoad
{
get
{
return GetXmlNodeBool(FULL_CALC_ON_LOAD_PATH);
}
set
{
SetXmlNodeBool(FULL_CALC_ON_LOAD_PATH, value);
}
}
#endregion
#region Workbook Private Methods
#region Save // Workbook Save
/// <summary>
/// Saves the workbook and all its components to the package.
/// For internal use only!
/// </summary>
internal void Save() // Workbook Save
{
if (Worksheets.Count == 0)
throw new InvalidOperationException("The workbook must contain at least one worksheet");
DeleteCalcChain();
const string vbaPartUri = "/xl/vbaProject.bin";
if (!_package.Package.PartExists(new Uri(vbaPartUri, UriKind.Relative)))
{
if (Part.ContentType != ExcelPackage.contentTypeWorkbookDefault)
{
Part.ContentType = ExcelPackage.contentTypeWorkbookDefault;
}
}
else
{
if (Part.ContentType != ExcelPackage.contentTypeWorkbookMacroEnabled)
{
Part.ContentType = ExcelPackage.contentTypeWorkbookMacroEnabled;
}
}
UpdateDefinedNamesXml();
// save the workbook
if (_workbookXml != null)
{
_package.SavePart(WorkbookUri, _workbookXml);
}
// save the properties of the workbook
if (_properties != null)
{
_properties.Save();
}
// save the style sheet
Styles.UpdateXml();
_package.SavePart(StylesUri, _stylesXml);
// save all the open worksheets
var isProtected = Protection.LockWindows || Protection.LockStructure;
foreach (ExcelWorksheet worksheet in Worksheets)
{
if (isProtected && Protection.LockWindows)
{
worksheet.View.WindowProtection = true;
}
worksheet.Save();
worksheet.Part.SaveHandler = worksheet.SaveHandler;
}
var part = _package.Package.CreatePart(SharedStringsUri, ExcelPackage.contentTypeSharedString, _package.Compression);
part.SaveHandler = SaveSharedStringHandler;
Part.CreateRelationship(UriHelper.GetRelativeUri(WorkbookUri, SharedStringsUri), Packaging.TargetMode.Internal, ExcelPackage.schemaRelationships + "/sharedStrings");
//UpdateSharedStringsXml();
// Data validation
ValidateDataValidations();
}
private void DeleteCalcChain()
{
//Remove the calc chain if it exists.
Uri uriCalcChain = new Uri("/xl/calcChain.xml", UriKind.Relative);
if (_package.Package.PartExists(uriCalcChain))
{
Uri calcChain = new Uri("calcChain.xml", UriKind.Relative);
foreach (var relationship in _package.Workbook.Part.GetRelationships())
{
if (relationship.TargetUri == calcChain)
{
_package.Workbook.Part.DeleteRelationship(relationship.Id);
break;
}
}
// delete the calcChain part
_package.Package.DeletePart(uriCalcChain);
}
}
private void ValidateDataValidations()
{
foreach (var sheet in _package.Workbook.Worksheets)
{
if (!(sheet is ExcelChartsheet))
{
sheet.DataValidations.ValidateAll();
}
}
}
private void SaveSharedStringHandler(StreamWriter sw)
{
var cache = new StringBuilder();
cache.AppendFormat("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?><sst xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" count=\"{0}\" uniqueCount=\"{0}\">", _sharedStrings.Count);
foreach (string t in _sharedStrings.Keys)
{
SharedStringItem ssi = _sharedStrings[t];
if (ssi.isRichText)
{
cache.Append("<si>");
ConvertUtil.ExcelEncodeString(cache, t);
cache.Append("</si>");
}
else
{
if (t.Length > 0 && (t[0] == ' ' || t[t.Length - 1] == ' ' || t.Contains(" ") || t.Contains("\t") || t.Contains("\n") || t.Contains("\n"))) //Fixes issue 14849
{
cache.Append("<si><t xml:space=\"preserve\">");
}
else
{
cache.Append("<si><t>");
}
ConvertUtil.ExcelEncodeString(cache, ConvertUtil.ExcelEscapeString(t));
cache.Append("</t></si>");
}
if (cache.Length > 0x600000)
{
sw.Write(cache.ToString());
cache = new StringBuilder();
}
}
cache.Append("</sst>");
sw.Write(cache.ToString());
sw.Flush();
Part.CreateRelationship(UriHelper.GetRelativeUri(WorkbookUri, SharedStringsUri), Packaging.TargetMode.Internal, ExcelPackage.schemaRelationships + "/sharedStrings");
}
private void UpdateDefinedNamesXml()
{
try
{
XmlNode top = WorkbookXml.SelectSingleNode("//d:definedNames", NameSpaceManager);
if (!ExistsNames())
{
if (top != null) TopNode.RemoveChild(top);
return;
}
else
{
if (top == null)
{
CreateNode("d:definedNames");
top = WorkbookXml.SelectSingleNode("//d:definedNames", NameSpaceManager);
}
else
{
top.RemoveAll();
}
foreach (ExcelNamedRange name in _names)
{
XmlElement elem = WorkbookXml.CreateElement("definedName", ExcelPackage.schemaMain);
top.AppendChild(elem);
elem.SetAttribute("name", name.Name);
if (name.IsNameHidden) elem.SetAttribute("hidden", "1");
if (!string.IsNullOrEmpty(name.NameComment)) elem.SetAttribute("comment", name.NameComment);
SetNameElement(name, elem);
}
}
foreach (ExcelWorksheet ws in _worksheets)
{
if (!(ws is ExcelChartsheet))
{
foreach (ExcelNamedRange name in ws.Names)
{
XmlElement elem = WorkbookXml.CreateElement("definedName", ExcelPackage.schemaMain);
top.AppendChild(elem);
elem.SetAttribute("name", name.Name);
elem.SetAttribute("localSheetId", name.LocalSheetId.ToString());
if (name.IsNameHidden) elem.SetAttribute("hidden", "1");
if (!string.IsNullOrEmpty(name.NameComment)) elem.SetAttribute("comment", name.NameComment);
SetNameElement(name, elem);
}
}
}
}
catch (Exception ex)
{
throw new Exception("Internal error updating named ranges ",ex);
}
}
private void SetNameElement(ExcelNamedRange name, XmlElement elem)
{
if (name.IsName)
{
if (string.IsNullOrEmpty(name.NameFormula))
{
if ((name.NameValue.GetType().IsPrimitive || name.NameValue is double || name.NameValue is decimal))
{
elem.InnerText = Convert.ToDouble(name.NameValue, CultureInfo.InvariantCulture).ToString("R15", CultureInfo.InvariantCulture);
}
else if (name.NameValue is DateTime)
{
elem.InnerText = ((DateTime)name.NameValue).ToOADate().ToString(CultureInfo.InvariantCulture);
}
else
{
elem.InnerText = "\"" + name.NameValue.ToString() + "\"";
}
}
else
{
elem.InnerText = name.NameFormula;
}
}
else
{
elem.InnerText = name.FullAddressAbsolute;
}
}
/// <summary>
/// Is their any names in the workbook or in the sheets.
/// </summary>
/// <returns>?</returns>
private bool ExistsNames()
{
if (_names.Count == 0)
{
foreach (ExcelWorksheet ws in Worksheets)
{
if (ws is ExcelChartsheet) continue;
if(ws.Names.Count>0)
{
return true;
}
}
}
else
{
return true;
}
return false;
}
#endregion
#endregion
internal bool ExistsTableName(string Name)
{
foreach (var ws in Worksheets)
{
if(ws.Tables._tableNames.ContainsKey(Name))
{
return true;
}
}
return false;
}
internal bool ExistsPivotTableName(string Name)
{
foreach (var ws in Worksheets)
{
if (ws.PivotTables._pivotTableNames.ContainsKey(Name))
{
return true;
}
}
return false;
}
internal void AddPivotTable(string cacheID, Uri defUri)
{
CreateNode("d:pivotCaches");
XmlElement item = WorkbookXml.CreateElement("pivotCache", ExcelPackage.schemaMain);
item.SetAttribute("cacheId", cacheID);
var rel = Part.CreateRelationship(UriHelper.ResolvePartUri(WorkbookUri, defUri), Packaging.TargetMode.Internal, ExcelPackage.schemaRelationships + "/pivotCacheDefinition");
item.SetAttribute("id", ExcelPackage.schemaRelationships, rel.Id);
var pivotCaches = WorkbookXml.SelectSingleNode("//d:pivotCaches", NameSpaceManager);
pivotCaches.AppendChild(item);
}
internal List<string> _externalReferences = new List<string>();
//internal bool _isCalculated=false;
internal void GetExternalReferences()
{
XmlNodeList nl = WorkbookXml.SelectNodes("//d:externalReferences/d:externalReference", NameSpaceManager);
if (nl != null)
{
foreach (XmlElement elem in nl)
{
string rID = elem.GetAttribute("r:id");
var rel = Part.GetRelationship(rID);
var part = _package.Package.GetPart(UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri));
XmlDocument xmlExtRef = new XmlDocument();
LoadXmlSafe(xmlExtRef, part.GetStream());
XmlElement book=xmlExtRef.SelectSingleNode("//d:externalBook", NameSpaceManager) as XmlElement;
if(book!=null)
{
string rId_ExtRef = book.GetAttribute("r:id");
var rel_extRef = part.GetRelationship(rId_ExtRef);
if (rel_extRef != null)
{
_externalReferences.Add(rel_extRef.TargetUri.OriginalString);
}
}
}
}
}
internal void ReadAllTables()
{
if (_nextTableID > 0) return;
_nextTableID = 1;
_nextPivotTableID = 1;
foreach (var ws in Worksheets)
{
if (!(ws is ExcelChartsheet)) //Fixes 15273. Chartsheets should be ignored.
{
foreach (var tbl in ws.Tables)
{
if (tbl.Id >= _nextTableID)
{
_nextTableID = tbl.Id + 1;
}
}
foreach (var pt in ws.PivotTables)
{
if (pt.CacheID >= _nextPivotTableID)
{
_nextPivotTableID = pt.CacheID + 1;
}
}
}
}
}
} // end Workbook
}