diff --git a/EPPlus/ExcelWorksheet.cs b/EPPlus/ExcelWorksheet.cs index 12b29eb1..aaad5ad2 100644 --- a/EPPlus/ExcelWorksheet.cs +++ b/EPPlus/ExcelWorksheet.cs @@ -30,31 +30,32 @@ * Jan Källman Total rewrite 2010-03-01 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing; -using System.Globalization; -using System.IO; -using System.Security; -using System.Text; -using System.Text.RegularExpressions; -using System.Xml; +using OfficeOpenXml.Compatibility; using OfficeOpenXml.ConditionalFormatting; using OfficeOpenXml.DataValidation; using OfficeOpenXml.Drawing; using OfficeOpenXml.Drawing.Chart; using OfficeOpenXml.Drawing.Vml; +using OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; using OfficeOpenXml.FormulaParsing.LexicalAnalysis; using OfficeOpenXml.Packaging.Ionic.Zip; +using OfficeOpenXml.Sparkline; using OfficeOpenXml.Style.XmlAccess; using OfficeOpenXml.Table; using OfficeOpenXml.Table.PivotTable; using OfficeOpenXml.Utils; - +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Globalization; +using System.IO; using System.Linq; -using OfficeOpenXml.Compatibility; -using OfficeOpenXml.Sparkline; +using System.Security; +using System.Text; +using System.Text.RegularExpressions; +using System.Xml; +using RegexMatch = System.Text.RegularExpressions.Match; namespace OfficeOpenXml { @@ -371,6 +372,7 @@ internal void Clear(ExcelAddressBase Destination) private XmlDocument _worksheetXml; internal ExcelWorksheetView _sheetView; internal ExcelHeaderFooter _headerFooter; + private string _nsPrefix = ""; #endregion #region ExcelWorksheet Constructor /// @@ -1018,7 +1020,7 @@ private string GetWorkSheetXml(Stream stream, long start, long end, out Encoding char[] block; int pos; StringBuilder sb = new StringBuilder(); - Match startmMatch, endMatch; + RegexMatch startmMatch, endMatch; do { int size = stream.Length < BLOCKSIZE ? (int)stream.Length : BLOCKSIZE; @@ -1081,7 +1083,7 @@ private string GetWorkSheetXml(Stream stream, long start, long end, out Encoding } private void GetBlockPos(string xml, string tag, ref int start, ref int end) { - Match startmMatch, endMatch; + RegexMatch startmMatch, endMatch; startmMatch = Regex.Match(xml.Substring(start), string.Format("(<[^>]*{0}[^>]*>)", tag)); //"<[a-zA-Z:]*" + tag + "[?]*>"); if (!startmMatch.Success) //Not found @@ -1460,12 +1462,14 @@ private void LoadMergeCells(XmlReader xr) /// The writer private void UpdateMergedCells(StreamWriter sw) { - sw.Write(""); + sw.Write($"<{_nsPrefix}mergeCells>"); foreach (string address in _mergedCells) { - sw.Write("", address); + sw.Write($"<{_nsPrefix}mergeCell ref=\"{address}\" />"); + } - sw.Write(""); + sw.Write($""); + } /// /// Reads a row from the XML reader @@ -3433,6 +3437,16 @@ private static string GetTotalFunction(ExcelTableColumn col, string FunctionNum) private void SaveXml(Stream stream) { + // Ermittle den Namespace-Prefix aus dem Dokument + var worksheetNode = _worksheetXml.DocumentElement; + if (worksheetNode != null && !string.IsNullOrEmpty(worksheetNode.Prefix)) + { + _nsPrefix = worksheetNode.Prefix + ":"; + } + else + { + _nsPrefix = ""; + } //Create the nodes if they do not exist. StreamWriter sw = new StreamWriter(stream, System.Text.Encoding.UTF8, 65536); if (this is ExcelChartsheet) @@ -3442,7 +3456,7 @@ private void SaveXml(Stream stream) else { CreateNode("d:cols"); - CreateNode("d:sheetData"); + //CreateNode("d:sheetData"); CreateNode("d:mergeCells"); CreateNode("d:hyperlinks"); CreateNode("d:rowBreaks"); @@ -3533,13 +3547,13 @@ private void UpdateColBreaks(StreamWriter sw) var col=cse.Value._value as ExcelColumn; if (col != null && col.PageBreak) { - breaks.AppendFormat("", cse.Column); + breaks.Append($"<{_nsPrefix}brk id=\"{cse.Column}\" max=\"16383\" man=\"1\"/>"); count++; } } if (count > 0) { - sw.Write(string.Format("{1}", count, breaks.ToString())); + sw.Write($"<{_nsPrefix}colBreaks count=\"{count}\" manualBreakCount=\"{count}\">{breaks}"); } } @@ -3554,13 +3568,13 @@ private void UpdateRowBreaks(StreamWriter sw) var row=cse.Value._value as RowInternal; if (row != null && row.PageBreak) { - breaks.AppendFormat("", cse.Row); + breaks.Append($"<{_nsPrefix}brk id=\"{cse.Row}\" max=\"1048575\" man=\"1\"/>"); count++; } } if (count>0) { - sw.Write(string.Format("{1}", count, breaks.ToString())); + sw.Write($"<{_nsPrefix}rowBreaks count=\"{count}\" manualBreakCount=\"{count}\">{breaks}"); } } /// @@ -3574,13 +3588,13 @@ private void UpdateColumnData(StreamWriter sw) { if (first) { - sw.Write(""); + sw.Write($"<{_nsPrefix}cols>"); first = false; } var col = cse.Value._value as ExcelColumn; ExcelStyleCollection cellXfs = _package.Workbook.Styles.CellXfs; - sw.Write(" 0) - { - sw.Write(" outlineLevel=\"{0}\" ", col.OutlineLevel); + { + sw.Write($" outlineLevel=\"{col.OutlineLevel}\" "); if (col.Collapsed) { if (col.Hidden) @@ -3614,13 +3628,13 @@ private void UpdateColumnData(StreamWriter sw) var styleID = col.StyleID >= 0 ? cellXfs[col.StyleID].newID : col.StyleID; if (styleID > 0) { - sw.Write(" style=\"{0}\"", styleID); + sw.Write($" style=\"{styleID}\""); } sw.Write("/>"); } if (!first) { - sw.Write(""); + sw.Write($""); } } /// @@ -3636,7 +3650,7 @@ private void UpdateRowCellData(StreamWriter sw) var ss = _package.Workbook._sharedStrings; var styles = _package.Workbook.Styles; var cache = new StringBuilder(); - cache.Append(""); + cache.Append($"<{_nsPrefix}sheetData>"); FixSharedFormulas(); //Fixes Issue #32 @@ -3668,21 +3682,21 @@ private void UpdateRowCellData(StreamWriter sw) { if (f.IsArray) { - cache.AppendFormat("{3}{4}", cse.CellAddress, styleID < 0 ? 0 : styleID, f.Address, ConvertUtil.ExcelEscapeString(f.Formula), GetFormulaValue(v), GetCellType(v, true)); + cache.Append($"<{_nsPrefix}c r=\"{cse.CellAddress}\" s=\"{(styleID < 0 ? 0 : styleID)}\"{GetCellType(v, true)}><{_nsPrefix}f ref=\"{f.Address}\" t=\"array\">{ConvertUtil.ExcelEscapeString(f.Formula)}{GetFormulaValue(v)}"); } else { - cache.AppendFormat("{4}{5}", cse.CellAddress, styleID < 0 ? 0 : styleID, f.Address, sfId, ConvertUtil.ExcelEscapeString(f.Formula), GetFormulaValue(v), GetCellType(v, true)); + cache.Append($"<{_nsPrefix}c r=\"{cse.CellAddress}\" s=\"{(styleID < 0 ? 0 : styleID)}\"{GetCellType(v, true)}><{_nsPrefix}f ref=\"{f.Address}\" t=\"shared\" si=\"{sfId}\">{ConvertUtil.ExcelEscapeString(f.Formula)}{GetFormulaValue(v)}"); } } else if (f.IsArray) { - cache.AppendFormat("", cse.CellAddress, styleID < 0 ? 0 : styleID); + cache.Append($"<{_nsPrefix}c r=\"{cse.CellAddress}\" s=\"{(styleID < 0 ? 0 : styleID)}\"/>"); } else { - cache.AppendFormat("{3}", cse.CellAddress, styleID < 0 ? 0 : styleID, sfId, GetFormulaValue(v), GetCellType(v, true)); + cache.Append($"<{_nsPrefix}c r=\"{cse.CellAddress}\" s=\"{(styleID < 0 ? 0 : styleID)}\"{GetCellType(v, true)}><{_nsPrefix}f t=\"shared\" si=\"{sfId}\"/>{GetFormulaValue(v)}"); } } else @@ -3690,25 +3704,25 @@ private void UpdateRowCellData(StreamWriter sw) // We can also have a single cell array formula if (f.IsArray) { - cache.AppendFormat("{3}{4}", cse.CellAddress, styleID < 0 ? 0 : styleID, string.Format("{0}:{1}", f.Address, f.Address), ConvertUtil.ExcelEscapeString(f.Formula), GetFormulaValue(v), GetCellType(v, true)); + cache.Append($"<{_nsPrefix}c r=\"{cse.CellAddress}\" s=\"{(styleID < 0 ? 0 : styleID)}\"{GetCellType(v, true)}><{_nsPrefix}f ref=\"{f.Address}:{f.Address}\" t=\"array\">{ConvertUtil.ExcelEscapeString(f.Formula)}{GetFormulaValue(v)}"); } else { - cache.AppendFormat("", f.Address, styleID < 0 ? 0 : styleID, GetCellType(v, true)); - cache.AppendFormat("{0}{1}", ConvertUtil.ExcelEscapeString(f.Formula), GetFormulaValue(v)); + cache.Append($"<{_nsPrefix}c r=\"{f.Address}\" s=\"{(styleID < 0 ? 0 : styleID)}\"{GetCellType(v, true)}>"); + cache.Append($"<{_nsPrefix}f>{ConvertUtil.ExcelEscapeString(f.Formula)}{GetFormulaValue(v)}"); } } } else if (formula != null && formula.ToString() != "") { - cache.AppendFormat("", cse.CellAddress, styleID < 0 ? 0 : styleID, GetCellType(v, true)); - cache.AppendFormat("{0}{1}", ConvertUtil.ExcelEscapeString(formula.ToString()), GetFormulaValue(v)); + cache.Append($"<{_nsPrefix}c r=\"{cse.CellAddress}\" s=\"{(styleID < 0 ? 0 : styleID)}\"{GetCellType(v, true)}>"); + cache.Append($"<{_nsPrefix}f>{ConvertUtil.ExcelEscapeString(formula.ToString())}{GetFormulaValue(v)}"); } else { if (v == null && styleID > 0) { - cache.AppendFormat("", cse.CellAddress, styleID < 0 ? 0 : styleID); + cache.Append($"<{_nsPrefix}c r=\"{cse.CellAddress}\" s=\"{(styleID < 0 ? 0 : styleID)}\"/>"); } else if (v != null) { @@ -3725,8 +3739,8 @@ private void UpdateRowCellData(StreamWriter sw) if ((TypeCompat.IsPrimitive(v) || v is double || v is decimal || v is DateTime || v is TimeSpan)) { //string sv = GetValueForXml(v); - cache.AppendFormat("", cse.CellAddress, styleID < 0 ? 0 : styleID, GetCellType(v)); - cache.AppendFormat("{0}", GetFormulaValue(v)); + cache.Append($"<{_nsPrefix}c r=\"{cse.CellAddress}\" s=\"{(styleID < 0 ? 0 : styleID)}\"{GetCellType(v)}>"); + cache.Append($"{GetFormulaValue(v)}"); } else { @@ -3741,8 +3755,8 @@ private void UpdateRowCellData(StreamWriter sw) { ix = ss[vString].pos; } - cache.AppendFormat("", cse.CellAddress, styleID < 0 ? 0 : styleID); - cache.AppendFormat("{0}", ix); + cache.Append($"<{_nsPrefix}c r=\"{cse.CellAddress}\" s=\"{(styleID < 0 ? 0 : styleID)}\" t=\"s\">"); + cache.Append($"<{_nsPrefix}v>{ix}"); } } } @@ -3767,8 +3781,8 @@ private void UpdateRowCellData(StreamWriter sw) } columnStyles = null; - if (row != -1) cache.Append(""); - cache.Append(""); + if (row != -1) cache.Append($""); + cache.Append($""); sw.Write(cache.ToString()); sw.Flush(); } @@ -3856,7 +3870,7 @@ private object GetFormulaValue(object v) //{ if (v != null && v.ToString()!="") { - return "" + ConvertUtil.ExcelEscapeString(GetValueForXml(v)) + ""; //Fixes issue 15071 + return $"<{_nsPrefix}v>" + ConvertUtil.ExcelEscapeString(GetValueForXml(v)) + $""; //Fixes issue 15071 } else { @@ -3933,9 +3947,9 @@ private string GetValueForXml(object v) } private void WriteRow(StringBuilder cache, ExcelStyleCollection cellXfs, int prevRow, int row) { - if (prevRow != -1) cache.Append(""); + if (prevRow != -1) cache.Append($""); //ulong rowID = ExcelRow.GetRowID(SheetID, row); - cache.AppendFormat(" cellXf } if (currRow.Height >= 0) { - cache.AppendFormat(string.Format(CultureInfo.InvariantCulture, " ht=\"{0}\"", currRow.Height)); + cache.Append(string.Format(CultureInfo.InvariantCulture, " ht=\"{0}\"", currRow.Height)); if (currRow.CustomHeight) { cache.Append(" customHeight=\"1\""); @@ -3956,7 +3970,7 @@ private void WriteRow(StringBuilder cache, ExcelStyleCollection cellXf if (currRow.OutlineLevel > 0) { - cache.AppendFormat(" outlineLevel =\"{0}\"", currRow.OutlineLevel); + cache.Append($" outlineLevel=\"{currRow.OutlineLevel}\""); if (currRow.Collapsed) { if (currRow.Hidden) @@ -3977,15 +3991,15 @@ private void WriteRow(StringBuilder cache, ExcelStyleCollection cellXf var s = GetStyleInner(row, 0); if (s > 0) { - cache.AppendFormat(" s=\"{0}\" customFormat=\"1\"", cellXfs[s].newID); + cache.Append($" s=\"{cellXfs[s].newID}\" customFormat=\"1\""); } cache.Append(">"); } private void WriteRow(StreamWriter sw, ExcelStyleCollection cellXfs, int prevRow, int row) { - if (prevRow != -1) sw.Write(""); + if (prevRow != -1) sw.Write($""); //ulong rowID = ExcelRow.GetRowID(SheetID, row); - sw.Write(" cellXfs, i if (currRow.OutlineLevel > 0) { - sw.Write(" outlineLevel =\"{0}\"", currRow.OutlineLevel); + sw.Write($" outlineLevel=\"{currRow.OutlineLevel}\""); if (currRow.Collapsed) { if (currRow.Hidden) @@ -4027,7 +4041,7 @@ private void WriteRow(StreamWriter sw, ExcelStyleCollection cellXfs, i var s = GetStyleInner(row, 0); if (s > 0) { - sw.Write(" s=\"{0}\" customFormat=\"1\"", cellXfs[s].newID); + sw.Write($" s=\"{cellXfs[s].newID}\" customFormat=\"1\""); } sw.Write(">"); } @@ -4047,7 +4061,7 @@ private void UpdateHyperLinks(StreamWriter sw) var uri = _hyperLinks.GetValue(cse.Row, cse.Column); if (first && uri != null) { - sw.Write(""); + sw.Write($"<{_nsPrefix}hyperlinks>"); first = false; } @@ -4056,12 +4070,8 @@ private void UpdateHyperLinks(StreamWriter sw) if (uri is ExcelHyperLink && !string.IsNullOrEmpty((uri as ExcelHyperLink).ReferenceAddress)) { ExcelHyperLink hl = uri as ExcelHyperLink; - sw.Write("", - Cells[cse.Row, cse.Column, cse.Row + hl.RowSpann, cse.Column + hl.ColSpann].Address, - ExcelCellBase.GetFullAddress(SecurityElement.Escape(Name), SecurityElement.Escape(hl.ReferenceAddress)), - string.IsNullOrEmpty(hl.Display) ? "" : " display=\"" + SecurityElement.Escape(hl.Display) + "\"", - string.IsNullOrEmpty(hl.ToolTip) ? "" : " tooltip=\"" + SecurityElement.Escape(hl.ToolTip) + "\""); - } + sw.Write($"<{_nsPrefix}hyperlink ref=\"{Cells[cse.Row, cse.Column, cse.Row + hl.RowSpann, cse.Column + hl.ColSpann].Address}\" location=\"{ExcelCellBase.GetFullAddress(SecurityElement.Escape(Name), SecurityElement.Escape(hl.ReferenceAddress))}\"{(string.IsNullOrEmpty(hl.Display) ? "" : $" display=\"{SecurityElement.Escape(hl.Display)}\"")}{(string.IsNullOrEmpty(hl.ToolTip) ? "" : $" tooltip=\"{SecurityElement.Escape(hl.ToolTip)}\"")}/>"); + } else if( uri!=null) { string id; @@ -4081,17 +4091,15 @@ private void UpdateHyperLinks(StreamWriter sw) else { var relationship = Part.CreateRelationship(hyp, Packaging.TargetMode.External, ExcelPackage.schemaHyperlink); - if (uri is ExcelHyperLink) - { - ExcelHyperLink hl = uri as ExcelHyperLink; - sw.Write("", ExcelCellBase.GetAddress(cse.Row, cse.Column), relationship.Id, - string.IsNullOrEmpty(hl.Display) ? "" : " display=\"" + SecurityElement.Escape(hl.Display) + "\"", - string.IsNullOrEmpty(hl.ToolTip) ? "" : " tooltip=\"" + SecurityElement.Escape(hl.ToolTip) + "\""); - } - else - { - sw.Write("", ExcelCellBase.GetAddress(cse.Row, cse.Column), relationship.Id); - } + if (uri is ExcelHyperLink) + { + ExcelHyperLink hl = uri as ExcelHyperLink; + sw.Write($"<{_nsPrefix}hyperlink ref=\"{ExcelCellBase.GetAddress(cse.Row, cse.Column)}\"{(string.IsNullOrEmpty(hl.Display) ? "" : $" display=\"{SecurityElement.Escape(hl.Display)}\"")}{(string.IsNullOrEmpty(hl.ToolTip) ? "" : $" tooltip=\"{SecurityElement.Escape(hl.ToolTip)}\"")}" + $" r:id=\"{relationship.Id}\"/>"); + } + else + { + sw.Write($"<{_nsPrefix}hyperlink ref=\"{ExcelCellBase.GetAddress(cse.Row, cse.Column)}\" r:id=\"{relationship.Id}\"/>"); + } id = relationship.Id; } //cell.HyperLinkRId = id; @@ -4099,7 +4107,7 @@ private void UpdateHyperLinks(StreamWriter sw) } if (!first) { - sw.Write(""); + sw.Write($""); } } ///