diff --git a/ClosedXML/ClosedXML.csproj b/ClosedXML/ClosedXML.csproj index 12bf76a..fc22ffe 100644 --- a/ClosedXML/ClosedXML.csproj +++ b/ClosedXML/ClosedXML.csproj @@ -22,7 +22,7 @@ false bin\Debug\ DEBUG;TRACE - NET4 + NET4;TRACE;DEBUG prompt 4 1591 @@ -32,7 +32,7 @@ true bin\Release\ TRACE - NET4 + NET4;TRACE prompt 4 bin\Release\ClosedXML.xml diff --git a/ClosedXML/Excel/XLWorkbook.cs b/ClosedXML/Excel/XLWorkbook.cs index ac31b4e..3cfe9ef 100644 --- a/ClosedXML/Excel/XLWorkbook.cs +++ b/ClosedXML/Excel/XLWorkbook.cs @@ -175,7 +175,7 @@ private readonly Dictionary _stylesByStyle = new Dictionary(); public XLEventTracking EventTracking { get; set; } - + internal Int32 GetStyleId(IXLStyle style) { Int32 cached; @@ -411,16 +411,28 @@ /// public void Save() { +#if DEBUG + Save(true); +#else + Save(false); +#endif + } + + /// + /// Saves the current workbook and optionally performs validation + /// + public void Save(bool validate) + { checkForWorksheetsPresent(); if (_loadSource == XLLoadSource.New) throw new Exception("This is a new file, please use one of the SaveAs methods."); if (_loadSource == XLLoadSource.Stream) { - CreatePackage(_originalStream, false, _spreadsheetDocumentType); + CreatePackage(_originalStream, false, _spreadsheetDocumentType, validate); } else - CreatePackage(_originalFile, _spreadsheetDocumentType); + CreatePackage(_originalFile, _spreadsheetDocumentType, validate); } /// @@ -428,6 +440,18 @@ /// public void SaveAs(String file) { +#if DEBUG + SaveAs(file, true); +#else + SaveAs(file, false); +#endif + } + + /// + /// Saves the current workbook to a file and optionally validates it. + /// + public void SaveAs(String file, Boolean validate) + { checkForWorksheetsPresent(); PathHelper.CreateDirectory(Path.GetDirectoryName(file)); if (_loadSource == XLLoadSource.New) @@ -435,14 +459,14 @@ if (File.Exists(file)) File.Delete(file); - CreatePackage(file, GetSpreadsheetDocumentType(file)); + CreatePackage(file, GetSpreadsheetDocumentType(file), validate); } else if (_loadSource == XLLoadSource.File) { if (String.Compare(_originalFile.Trim(), file.Trim(), true) != 0) File.Copy(_originalFile, file, true); - CreatePackage(file, GetSpreadsheetDocumentType(file)); + CreatePackage(file, GetSpreadsheetDocumentType(file), validate); } else if (_loadSource == XLLoadSource.Stream) { @@ -452,7 +476,7 @@ { CopyStream(_originalStream, fileStream); //fileStream.Position = 0; - CreatePackage(fileStream, false, _spreadsheetDocumentType); + CreatePackage(fileStream, false, _spreadsheetDocumentType, validate); fileStream.Close(); } } @@ -481,6 +505,18 @@ /// public void SaveAs(Stream stream) { +#if DEBUG + SaveAs(stream, true); +#else + SaveAs(stream, false); +#endif + } + + /// + /// Saves the current workbook to a stream and optionally validates it. + /// + public void SaveAs(Stream stream, Boolean validate) + { checkForWorksheetsPresent(); if (_loadSource == XLLoadSource.New) { @@ -491,13 +527,13 @@ if (stream.CanRead && stream.CanSeek && stream.CanWrite) { // all is fine the package can be created in a direct way - CreatePackage(stream, true, _spreadsheetDocumentType); + CreatePackage(stream, true, _spreadsheetDocumentType, validate); } else { // the harder way MemoryStream ms = new MemoryStream(); - CreatePackage(ms, true, _spreadsheetDocumentType); + CreatePackage(ms, true, _spreadsheetDocumentType, validate); // not really nessesary, because I changed CopyStream too. // but for better understanding and if somebody in the future // provide an changed version of CopyStream @@ -512,7 +548,7 @@ CopyStream(fileStream, stream); fileStream.Close(); } - CreatePackage(stream, false, _spreadsheetDocumentType); + CreatePackage(stream, false, _spreadsheetDocumentType, validate); } else if (_loadSource == XLLoadSource.Stream) { @@ -520,7 +556,7 @@ if (_originalStream != stream) CopyStream(_originalStream, stream); - CreatePackage(stream, false, _spreadsheetDocumentType); + CreatePackage(stream, false, _spreadsheetDocumentType, validate); } } @@ -589,24 +625,24 @@ return columns; } - #region Fields +#region Fields private readonly XLLoadSource _loadSource = XLLoadSource.New; private readonly String _originalFile; private readonly Stream _originalStream; - #endregion +#endregion - #region Constructor +#region Constructor - + /// /// Creates a new Excel workbook. /// public XLWorkbook() :this(XLEventTracking.Enabled) { - + } public XLWorkbook(XLEventTracking eventTracking) @@ -665,7 +701,7 @@ /// The stream to open. public XLWorkbook(Stream stream):this(stream, XLEventTracking.Enabled) { - + } public XLWorkbook(Stream stream, XLEventTracking eventTracking) @@ -676,9 +712,9 @@ Load(stream); } - #endregion +#endregion - #region Nested type: UnsupportedSheet +#region Nested type: UnsupportedSheet internal sealed class UnsupportedSheet { @@ -687,7 +723,7 @@ public Int32 Position; } - #endregion +#endregion public IXLCell Cell(String namedCell) { @@ -814,4 +850,4 @@ LockWindows = LockWindows; } } -} \ No newline at end of file +} diff --git a/ClosedXML/Excel/XLWorkbook_Save.cs b/ClosedXML/Excel/XLWorkbook_Save.cs index c6084d6..2e69e73 100644 --- a/ClosedXML/Excel/XLWorkbook_Save.cs +++ b/ClosedXML/Excel/XLWorkbook_Save.cs @@ -10,6 +10,7 @@ using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Spreadsheet; using DocumentFormat.OpenXml.VariantTypes; +using DocumentFormat.OpenXml.Validation; using DocumentFormat.OpenXml.Vml.Office; using DocumentFormat.OpenXml.Vml.Spreadsheet; using Vml = DocumentFormat.OpenXml.Vml; @@ -42,7 +43,6 @@ using RunProperties = DocumentFormat.OpenXml.Spreadsheet.RunProperties; using VerticalTextAlignment = DocumentFormat.OpenXml.Spreadsheet.VerticalTextAlignment; - namespace ClosedXML.Excel { public partial class XLWorkbook @@ -79,7 +79,19 @@ } } - private void CreatePackage(String filePath, SpreadsheetDocumentType spreadsheetDocumentType) + private bool Validate(SpreadsheetDocument package) + { + var validator = new OpenXmlValidator(); + var errors = validator.Validate(package); + if (errors.Any()) + { + var message = string.Join("\r\n", errors.Select(e => string.Format("{0} in {1}", e.Description, e.Path.XPath)).ToArray()); + throw new ApplicationException(message); + } + return true; + } + + private void CreatePackage(String filePath, SpreadsheetDocumentType spreadsheetDocumentType, bool validate) { PathHelper.CreateDirectory(Path.GetDirectoryName(filePath)); var package = File.Exists(filePath) @@ -89,11 +101,11 @@ using (package) { CreateParts(package); - //package.Close(); + if (validate) Validate(package); } } - private void CreatePackage(Stream stream, bool newStream, SpreadsheetDocumentType spreadsheetDocumentType) + private void CreatePackage(Stream stream, bool newStream, SpreadsheetDocumentType spreadsheetDocumentType, bool validate) { var package = newStream ? SpreadsheetDocument.Create(stream, spreadsheetDocumentType) @@ -102,7 +114,7 @@ using (package) { CreateParts(package); - //package.Close(); + if (validate) Validate(package); } } @@ -159,8 +171,8 @@ } } - // Get the CalculationChainPart - //Note: An instance of this part type contains an ordered set of references to all cells in all worksheets in the + // Get the CalculationChainPart + //Note: An instance of this part type contains an ordered set of references to all cells in all worksheets in the //workbook whose value is calculated from any formula CalculationChainPart calChainPart; @@ -194,7 +206,7 @@ var workbookPart = document.WorkbookPart ?? document.AddWorkbookPart(); var worksheets = WorksheetsInternal; - + var partsToRemove = workbookPart.Parts.Where(s => worksheets.Deleted.Contains(s.RelationshipId)).ToList(); @@ -538,7 +550,7 @@ { workbook.WorkbookProtection = null; } - + if (workbook.BookViews == null) workbook.BookViews = new BookViews(); @@ -4064,7 +4076,7 @@ } worksheetPart.Worksheet.InsertAfter(conditionalFormatting, previousElement); previousElement = conditionalFormatting; - cm.SetElement(XLWSContentManager.XLWSContents.ConditionalFormatting, conditionalFormatting); + cm.SetElement(XLWSContentManager.XLWSContents.ConditionalFormatting, conditionalFormatting); } } @@ -4636,4 +4648,4 @@ #endregion } -} \ No newline at end of file +}