[NWD] More EPPlus improvements.
- Revamp save code to avoid memory copies
- Remove more unnecessary code for mutating sheets
- General cleanup
Change-Id: I9faf6c7cc94a50600076bd42ac456ba6f96cd407
Reviewed-on: https://gnocchi-internal-review.git.corp.google.com/c/third_party/epplus/+/208000
Reviewed-by: Hughes Hilton <hugheshilton@google.com>
diff --git a/EPPlus/CellStore.cs b/EPPlus/CellStore.cs
index a00f890..684cf3b 100644
--- a/EPPlus/CellStore.cs
+++ b/EPPlus/CellStore.cs
@@ -51,16 +51,7 @@
}
internal class ColumnIndex : IndexBase {
- internal IndexBase _searchIx = new();
-
- public ColumnIndex() {
- _pages = new PageIndex[CellStore<int>._pagesPerColumnMin];
- PageCount = 0;
- }
-
- ~ColumnIndex() {
- _pages = null;
- }
+ private readonly IndexBase _searchIx = new();
internal int GetPosition(int row) {
var page = (short)(row >> CellStore<int>._pageBits);
@@ -150,20 +141,12 @@
return -1;
}
- internal int FindNext(int page) {
- var p = GetPosition(page);
- if (p < 0) {
- return ~p;
- }
- return p;
- }
-
- internal PageIndex[] _pages;
+ internal PageIndex[] _pages = new PageIndex[CellStore<int>._pagesPerColumnMin];
internal int PageCount;
}
internal class PageIndex : IndexBase {
- internal IndexBase _searchIx = new();
+ private readonly IndexBase _searchIx = new();
public PageIndex() {
Rows = new IndexItem[CellStore<int>._pageSizeMin];
@@ -186,10 +169,6 @@
Offset = offset;
}
- ~PageIndex() {
- Rows = null;
- }
-
internal int Offset;
internal int IndexOffset => IndexExpanded + Offset;
@@ -262,14 +241,10 @@
internal const int _pagesPerColumnMin = 32;
private List<T> _values = new();
- internal ColumnIndex[] _columnIndex;
+ internal ColumnIndex[] _columnIndex = new ColumnIndex[_colSizeMin];
internal IndexBase _searchIx = new();
internal int ColumnCount;
- public CellStore() {
- _columnIndex = new ColumnIndex[_colSizeMin];
- }
-
~CellStore() {
if (_values != null) {
_values.Clear();
@@ -290,34 +265,6 @@
: Array.BinarySearch(_columnIndex, 0, ColumnCount, _searchIx);
}
- internal CellStore<T> Clone() {
- int row,
- col;
- var ret = new CellStore<T>();
- for (int c = 0; c < ColumnCount; c++) {
- col = _columnIndex[c].Index;
- for (int p = 0; p < _columnIndex[c].PageCount; p++) {
- for (int r = 0; r < _columnIndex[c]._pages[p].RowCount; r++) {
- row = _columnIndex[c]._pages[p].IndexOffset + _columnIndex[c]._pages[p].Rows[r].Index;
- ret.SetValue(row, col, _values[_columnIndex[c]._pages[p].Rows[r].IndexPointer]);
- }
- }
- }
- return ret;
- }
-
- internal int Count {
- get {
- int count = 0;
- for (int c = 0; c < ColumnCount; c++) {
- for (int p = 0; p < _columnIndex[c].PageCount; p++) {
- count += _columnIndex[c]._pages[p].RowCount;
- }
- }
- return count;
- }
- }
-
internal bool GetDimension(out int fromRow, out int fromCol, out int toRow, out int toCol) {
if (ColumnCount == 0) {
fromRow = fromCol = toRow = toCol = 0;
@@ -403,45 +350,6 @@
return _values[i];
}
return default(T);
- //var col = GetPosition(Column);
- //if (col >= 0)
- //{
- // var pos = _columnIndex[col].GetPosition(Row);
- // if (pos >= 0)
- // {
- // var pageItem = _columnIndex[col].Pages[pos];
- // if (pageItem.MinIndex > Row)
- // {
- // pos--;
- // if (pos < 0)
- // {
- // return default(T);
- // }
- // else
- // {
- // pageItem = _columnIndex[col].Pages[pos];
- // }
- // }
- // short ix = (short)(Row - pageItem.IndexOffset);
- // var cellPos = Array.BinarySearch(pageItem.Rows, 0, pageItem.RowCount, new IndexBase() { Index = ix });
- // if (cellPos >= 0)
- // {
- // return _values[pageItem.Rows[cellPos].IndexPointer];
- // }
- // else //Cell does not exist
- // {
- // return default(T);
- // }
- // }
- // else //Page does not exist
- // {
- // return default(T);
- // }
- //}
- //else //Column does not exist
- //{
- // return default(T);
- //}
}
private int GetPointer(int row, int column) {
@@ -492,125 +400,121 @@
}
internal void SetValue(int row, int column, T value) {
- lock (_columnIndex) {
- var col =
- (_columnIndex != null
- && column > 0
- && column - 1 < ColumnCount
- && column - 1 < _columnIndex.Length
- && _columnIndex[column - 1] != null
- && _columnIndex[column - 1].Index == column)
- ? column - 1
- : Array.BinarySearch(
- _columnIndex,
- 0,
- ColumnCount,
- new IndexBase {
- Index = (short)(column),
- });
- var page = (short)(row >> _pageBits);
- if (col >= 0) {
- //var pos = Array.BinarySearch(_columnIndex[col].Pages, 0, _columnIndex[col].Count, new IndexBase() { Index = page });
- var pos = _columnIndex[col].GetPosition(row);
- if (pos < 0) {
- pos = ~pos;
- if (pos - 1 < 0 || _columnIndex[col]._pages[pos - 1].IndexOffset + _pageSize - 1 < row) {
- AddPage(_columnIndex[col], pos, page);
- } else {
- pos--;
- }
- }
- if (pos >= _columnIndex[col].PageCount) {
+ var col =
+ (_columnIndex != null
+ && column > 0
+ && column - 1 < ColumnCount
+ && column - 1 < _columnIndex.Length
+ && _columnIndex[column - 1] != null
+ && _columnIndex[column - 1].Index == column)
+ ? column - 1
+ : Array.BinarySearch(
+ _columnIndex,
+ 0,
+ ColumnCount,
+ new IndexBase {
+ Index = (short)(column),
+ });
+ var page = (short)(row >> _pageBits);
+ if (col >= 0) {
+ //var pos = Array.BinarySearch(_columnIndex[col].Pages, 0, _columnIndex[col].Count, new IndexBase() { Index = page });
+ var pos = _columnIndex[col].GetPosition(row);
+ if (pos < 0) {
+ pos = ~pos;
+ if (pos - 1 < 0 || _columnIndex[col]._pages[pos - 1].IndexOffset + _pageSize - 1 < row) {
AddPage(_columnIndex[col], pos, page);
- }
- var pageItem = _columnIndex[col]._pages[pos];
- if (pageItem.IndexOffset > row) {
- pos--;
- page--;
- if (pos < 0) {
- throw (new("Unexpected error when setting value"));
- }
- pageItem = _columnIndex[col]._pages[pos];
- }
-
- short ix = (short)(row - ((pageItem.Index << _pageBits) + pageItem.Offset));
- _searchIx.Index = ix;
- var cellPos =
- (pageItem.Rows != null
- && ix >= 0
- && ix < pageItem.RowCount
- && ix < pageItem.Rows.Length
- && pageItem.Rows[ix] != null
- && pageItem.Rows[ix].Index == ix)
- ? ix
- : Array.BinarySearch(pageItem.Rows, 0, pageItem.RowCount, _searchIx);
- if (cellPos < 0) {
- cellPos = ~cellPos;
- AddCell(_columnIndex[col], pos, cellPos, ix, value);
} else {
- _values[pageItem.Rows[cellPos].IndexPointer] = value;
+ pos--;
}
- } else //Column does not exist
- {
- col = ~col;
- AddColumn(col, column);
- AddPage(_columnIndex[col], 0, page);
- short ix = (short)(row - (page << _pageBits));
- AddCell(_columnIndex[col], 0, 0, ix, value);
}
+ if (pos >= _columnIndex[col].PageCount) {
+ AddPage(_columnIndex[col], pos, page);
+ }
+ var pageItem = _columnIndex[col]._pages[pos];
+ if (pageItem.IndexOffset > row) {
+ pos--;
+ page--;
+ if (pos < 0) {
+ throw (new("Unexpected error when setting value"));
+ }
+ pageItem = _columnIndex[col]._pages[pos];
+ }
+
+ short ix = (short)(row - ((pageItem.Index << _pageBits) + pageItem.Offset));
+ _searchIx.Index = ix;
+ var cellPos =
+ (pageItem.Rows != null
+ && ix >= 0
+ && ix < pageItem.RowCount
+ && ix < pageItem.Rows.Length
+ && pageItem.Rows[ix] != null
+ && pageItem.Rows[ix].Index == ix)
+ ? ix
+ : Array.BinarySearch(pageItem.Rows, 0, pageItem.RowCount, _searchIx);
+ if (cellPos < 0) {
+ cellPos = ~cellPos;
+ AddCell(_columnIndex[col], pos, cellPos, ix, value);
+ } else {
+ _values[pageItem.Rows[cellPos].IndexPointer] = value;
+ }
+ } else //Column does not exist
+ {
+ col = ~col;
+ AddColumn(col, column);
+ AddPage(_columnIndex[col], 0, page);
+ short ix = (short)(row - (page << _pageBits));
+ AddCell(_columnIndex[col], 0, 0, ix, value);
}
}
internal void Insert(int fromRow, int fromCol, int rows, int columns) {
- lock (_columnIndex) {
- if (columns > 0) {
- var col = GetPosition(fromCol);
- if (col < 0) {
- col = ~col;
- }
- for (var c = col; c < ColumnCount; c++) {
- _columnIndex[c].Index += (short)columns;
- }
- } else {
- var page = fromRow >> _pageBits;
- for (int c = 0; c < ColumnCount; c++) {
- var column = _columnIndex[c];
- var pagePos = column.GetPosition(fromRow);
- if (pagePos >= 0) {
- if (fromRow >= column._pages[pagePos].MinIndex
- && fromRow
- <= column._pages[pagePos].MaxIndex) //The row is inside the page
- {
- int offset = fromRow - column._pages[pagePos].IndexOffset;
- var rowPos = column._pages[pagePos].GetPosition(offset);
- if (rowPos < 0) {
- rowPos = ~rowPos;
- }
- UpdateIndexOffset(column, pagePos, rowPos, fromRow, rows);
- } else if (column._pages[pagePos].MinIndex > fromRow - 1
- && pagePos
- > 0) //The row is on the page before.
- {
- int offset = fromRow - ((page - 1) << _pageBits);
- var rowPos = column._pages[pagePos - 1].GetPosition(offset);
- if (rowPos > 0 && pagePos > 0) {
- UpdateIndexOffset(column, pagePos - 1, rowPos, fromRow, rows);
- }
- } else if (column.PageCount >= pagePos + 1) {
- int offset = fromRow - column._pages[pagePos].IndexOffset;
- var rowPos = column._pages[pagePos].GetPosition(offset);
- if (rowPos < 0) {
- rowPos = ~rowPos;
- }
- if (column._pages[pagePos].RowCount > rowPos) {
- UpdateIndexOffset(column, pagePos, rowPos, fromRow, rows);
- } else {
- UpdateIndexOffset(column, pagePos + 1, 0, fromRow, rows);
- }
+ if (columns > 0) {
+ var col = GetPosition(fromCol);
+ if (col < 0) {
+ col = ~col;
+ }
+ for (var c = col; c < ColumnCount; c++) {
+ _columnIndex[c].Index += (short)columns;
+ }
+ } else {
+ var page = fromRow >> _pageBits;
+ for (int c = 0; c < ColumnCount; c++) {
+ var column = _columnIndex[c];
+ var pagePos = column.GetPosition(fromRow);
+ if (pagePos >= 0) {
+ if (fromRow >= column._pages[pagePos].MinIndex
+ && fromRow
+ <= column._pages[pagePos].MaxIndex) //The row is inside the page
+ {
+ int offset = fromRow - column._pages[pagePos].IndexOffset;
+ var rowPos = column._pages[pagePos].GetPosition(offset);
+ if (rowPos < 0) {
+ rowPos = ~rowPos;
}
- } else {
- UpdateIndexOffset(column, ~pagePos, 0, fromRow, rows);
+ UpdateIndexOffset(column, pagePos, rowPos, fromRow, rows);
+ } else if (column._pages[pagePos].MinIndex > fromRow - 1
+ && pagePos
+ > 0) //The row is on the page before.
+ {
+ int offset = fromRow - ((page - 1) << _pageBits);
+ var rowPos = column._pages[pagePos - 1].GetPosition(offset);
+ if (rowPos > 0 && pagePos > 0) {
+ UpdateIndexOffset(column, pagePos - 1, rowPos, fromRow, rows);
+ }
+ } else if (column.PageCount >= pagePos + 1) {
+ int offset = fromRow - column._pages[pagePos].IndexOffset;
+ var rowPos = column._pages[pagePos].GetPosition(offset);
+ if (rowPos < 0) {
+ rowPos = ~rowPos;
+ }
+ if (column._pages[pagePos].RowCount > rowPos) {
+ UpdateIndexOffset(column, pagePos, rowPos, fromRow, rows);
+ } else {
+ UpdateIndexOffset(column, pagePos + 1, 0, fromRow, rows);
+ }
}
+ } else {
+ UpdateIndexOffset(column, ~pagePos, 0, fromRow, rows);
}
}
}
@@ -625,93 +529,87 @@
}
internal void Delete(int fromRow, int fromCol, int rows, int columns, bool shift) {
- lock (_columnIndex) {
- if (columns > 0 && fromRow == 1 && rows >= ExcelPackage.MaxRows) {
- DeleteColumns(fromCol, columns, shift);
- } else {
- var toCol = fromCol + columns - 1;
- var pageFromRow = fromRow >> _pageBits;
- for (int c = 0; c < ColumnCount; c++) {
- var column = _columnIndex[c];
- if (column.Index >= fromCol) {
- if (column.Index > toCol) {
- break;
+ if (columns > 0 && fromRow == 1 && rows >= ExcelPackage.MaxRows) {
+ DeleteColumns(fromCol, columns, shift);
+ } else {
+ var toCol = fromCol + columns - 1;
+ var pageFromRow = fromRow >> _pageBits;
+ for (int c = 0; c < ColumnCount; c++) {
+ var column = _columnIndex[c];
+ if (column.Index >= fromCol) {
+ if (column.Index > toCol) {
+ break;
+ }
+ var pagePos = column.GetPosition(fromRow);
+ if (pagePos < 0) {
+ pagePos = ~pagePos;
+ }
+ if (pagePos < column.PageCount) {
+ var page = column._pages[pagePos];
+ if (shift
+ && page.RowCount > 0
+ && page.MinIndex > fromRow
+ && page.MaxIndex >= fromRow + rows) {
+ var o = page.MinIndex - fromRow;
+ if (o < rows) {
+ rows -= o;
+ page.Offset -= o;
+ UpdatePageOffset(column, pagePos, o);
+ } else {
+ page.Offset -= rows;
+ UpdatePageOffset(column, pagePos, rows);
+ continue;
+ }
}
- var pagePos = column.GetPosition(fromRow);
- if (pagePos < 0) {
- pagePos = ~pagePos;
- }
- if (pagePos < column.PageCount) {
- var page = column._pages[pagePos];
- if (shift
- && page.RowCount > 0
- && page.MinIndex > fromRow
- && page.MaxIndex >= fromRow + rows) {
- var o = page.MinIndex - fromRow;
- if (o < rows) {
- rows -= o;
- page.Offset -= o;
- UpdatePageOffset(column, pagePos, o);
- } else {
- page.Offset -= rows;
- UpdatePageOffset(column, pagePos, rows);
- continue;
+ if (page.RowCount > 0
+ && page.MinIndex <= fromRow + rows - 1
+ && page.MaxIndex
+ >= fromRow) //The row is inside the page
+ {
+ var endRow = fromRow + rows;
+ var delEndRow = DeleteCells(column._pages[pagePos], fromRow, endRow, shift);
+ if (shift && delEndRow != fromRow) {
+ UpdatePageOffset(column, pagePos, delEndRow - fromRow);
+ }
+ if (endRow > delEndRow
+ && pagePos < column.PageCount
+ && column._pages[pagePos].MinIndex < endRow) {
+ pagePos = (delEndRow == fromRow ? pagePos : pagePos + 1);
+ var rowsLeft = DeletePage(
+ shift ? fromRow : delEndRow,
+ endRow - delEndRow,
+ column,
+ pagePos,
+ shift);
+ //if (shift) UpdatePageOffset(column, pagePos, endRow - fromRow - rowsLeft);
+ if (rowsLeft > 0) {
+ var fr = shift ? fromRow : endRow - rowsLeft;
+ pagePos = column.GetPosition(fr);
+ DeleteCells(column._pages[pagePos], fr, shift ? fr + rowsLeft : endRow, shift);
+ if (shift) {
+ UpdatePageOffset(column, pagePos, rowsLeft);
+ }
}
}
- if (page.RowCount > 0
- && page.MinIndex <= fromRow + rows - 1
- && page.MaxIndex
- >= fromRow) //The row is inside the page
- {
- var endRow = fromRow + rows;
- var delEndRow = DeleteCells(column._pages[pagePos], fromRow, endRow, shift);
- if (shift && delEndRow != fromRow) {
- UpdatePageOffset(column, pagePos, delEndRow - fromRow);
+ } else if (pagePos > 0
+ && column._pages[pagePos].IndexOffset
+ > fromRow) //The row is on the page before.
+ {
+ int offset = fromRow + rows - 1 - ((pageFromRow - 1) << _pageBits);
+ var rowPos = column._pages[pagePos - 1].GetPosition(offset);
+ if (rowPos > 0 && pagePos > 0) {
+ if (shift) {
+ UpdateIndexOffset(column, pagePos - 1, rowPos, fromRow + rows - 1, -rows);
}
- if (endRow > delEndRow
- && pagePos < column.PageCount
- && column._pages[pagePos].MinIndex < endRow) {
- pagePos = (delEndRow == fromRow ? pagePos : pagePos + 1);
- var rowsLeft = DeletePage(
- shift ? fromRow : delEndRow,
- endRow - delEndRow,
- column,
- pagePos,
- shift);
- //if (shift) UpdatePageOffset(column, pagePos, endRow - fromRow - rowsLeft);
- if (rowsLeft > 0) {
- var fr = shift ? fromRow : endRow - rowsLeft;
- pagePos = column.GetPosition(fr);
- delEndRow = DeleteCells(
- column._pages[pagePos],
- fr,
- shift ? fr + rowsLeft : endRow,
- shift);
- if (shift) {
- UpdatePageOffset(column, pagePos, rowsLeft);
- }
- }
- }
- } else if (pagePos > 0
- && column._pages[pagePos].IndexOffset
- > fromRow) //The row is on the page before.
- {
- int offset = fromRow + rows - 1 - ((pageFromRow - 1) << _pageBits);
- var rowPos = column._pages[pagePos - 1].GetPosition(offset);
- if (rowPos > 0 && pagePos > 0) {
- if (shift) {
- UpdateIndexOffset(column, pagePos - 1, rowPos, fromRow + rows - 1, -rows);
- }
- }
- } else {
- if (shift && pagePos + 1 < column.PageCount) {
- UpdateIndexOffset(
- column,
- pagePos + 1,
- 0,
- column._pages[pagePos + 1].MinIndex,
- -rows);
- }
+ }
+ } else {
+ if (shift && pagePos + 1 < column.PageCount) {
+ UpdateIndexOffset(
+ column,
+ pagePos + 1,
+ 0,
+ column._pages[pagePos + 1].MinIndex,
+ -rows);
}
}
}
@@ -737,31 +635,12 @@
|| Math.Abs(column._pages[pagePos].Rows[column._pages[pagePos].RowCount - 1].Index)
> _pageSizeMax) //Split or Merge???
{
- rows = ResetPageOffset(column, pagePos, rows);
- ////MergePages
- //if (column.Pages[pagePos - 1].Index + 1 == column.Pages[pagePos].Index)
- //{
- // if (column.Pages[pagePos].IndexOffset + column.Pages[pagePos].Rows[column.Pages[pagePos].RowCount - 1].Index + rows -
- // column.Pages[pagePos - 1].IndexOffset + column.Pages[pagePos - 1].Rows[0].Index <= PageSize)
- // {
- // //Merge
- // MergePage(column, pagePos - 1, -rows);
- // }
- // else
- // {
- // //Split
- // }
- //}
- //rows -= PageSize;
- //for (int p = pagePos; p < column.PageCount; p++)
- //{
- // column.Pages[p].Index -= 1;
- //}
+ ResetPageOffset(column, pagePos, rows);
}
}
}
- private int ResetPageOffset(ColumnIndex column, int pagePos, int rows) {
+ private void ResetPageOffset(ColumnIndex column, int pagePos, int rows) {
PageIndex fromPage = column._pages[pagePos];
PageIndex toPage;
short pageAdd = 0;
@@ -775,14 +654,6 @@
+ toPage.Rows[0].Index
<= _pageSizeMax) {
MergePage(column, pagePos - 1);
- //var newPage = new PageIndex(toPage, 0, GetSize(fromPage.RowCount + toPage.RowCount));
- //newPage.RowCount = fromPage.RowCount + fromPage.RowCount;
- //Array.Copy(toPage.Rows, 0, newPage.Rows, 0, toPage.RowCount);
- //Array.Copy(fromPage.Rows, 0, newPage.Rows, toPage.RowCount, fromPage.RowCount);
- //for (int r = toPage.RowCount; r < newPage.RowCount; r++)
- //{
- // newPage.Rows[r].Index += (short)(fromPage.IndexOffset - toPage.IndexOffset);
- //}
}
} else //No page after
{
@@ -797,7 +668,6 @@
fromPage.Offset += _pageSize;
}
}
- return rows;
}
private int DeletePage(int fromRow, int rows, ColumnIndex column, int pagePos, bool shift) {
@@ -841,7 +711,6 @@
return rows;
}
- ///
private int DeleteCells(PageIndex page, int fromRow, int toRow, bool shift) {
var fromPos = page.GetPosition(fromRow - (page.IndexOffset));
if (fromPos < 0) {
@@ -908,13 +777,10 @@
}
if (_columnIndex[fPos].Index >= fromCol && _columnIndex[fPos].Index <= fromCol + columns) {
- //if (_columnIndex[fPos].Index < ColumnCount)
- //{
if (tPos < ColumnCount) {
Array.Copy(_columnIndex, tPos, _columnIndex, fPos, ColumnCount - tPos);
}
ColumnCount -= (tPos - fPos);
- //}
}
if (shift) {
for (var c = fPos; c < ColumnCount; c++) {
@@ -1243,22 +1109,6 @@
ColumnCount++;
}
- private int _colPos = -1,
- _row;
-
- public ulong Current => ((ulong)_row << 32) | (uint)(_columnIndex[_colPos].Index);
-
- //object IEnumerator.Current
- //{
- // get
- // {
- // return GetValue(_row+1, _columnIndex[_colPos].Index);
- // }
- //}
- public bool MoveNext() {
- return GetNextCell(ref _row, ref _colPos, 0, ExcelPackage.MaxRows, ExcelPackage.MaxColumns);
- }
-
internal bool NextCell(ref int row, ref int col) {
return NextCell(ref row, ref col, 0, 0, ExcelPackage.MaxRows, ExcelPackage.MaxColumns);
}
@@ -1379,47 +1229,11 @@
return GetNextCell(ref row, ref colPos, startColPos, endRow, endColPos);
}
- internal bool GetNextCell(
- ref int row,
- ref int colPos,
- int startColPos,
- int endRow,
- int endColPos,
- ref int[] pagePos,
- ref int[] cellPos) {
- if (colPos == endColPos) {
- colPos = startColPos;
- row++;
- } else {
- colPos++;
- }
-
- if (pagePos[colPos] < 0) {
- if (pagePos[colPos] == -1) {
- pagePos[colPos] = _columnIndex[colPos].GetPosition(row);
- }
- } else if (_columnIndex[colPos]._pages[pagePos[colPos]].RowCount <= row) {
- if (_columnIndex[colPos].PageCount > pagePos[colPos]) {
- pagePos[colPos]++;
- } else {
- pagePos[colPos] = -2;
- }
- }
-
- var r =
- _columnIndex[colPos]._pages[pagePos[colPos]].IndexOffset
- + _columnIndex[colPos]._pages[pagePos[colPos]].Rows[cellPos[colPos]].Index;
- if (r == row) {
- row = r;
- }
- return true;
- }
-
internal bool PrevCell(ref int row, ref int col) {
return PrevCell(ref row, ref col, 0, 0, ExcelPackage.MaxRows, ExcelPackage.MaxColumns);
}
- internal bool PrevCell(
+ private bool PrevCell(
ref int row,
ref int col,
int minRow,
@@ -1542,28 +1356,10 @@
colPos = ColumnCount;
row--;
if (row < startRow) {
- Reset();
return false;
}
return GetPrevCell(ref colPos, ref row, startRow, startColPos, endColPos);
}
-
- public void Reset() {
- _colPos = -1;
- _row = 0;
- }
-
- //public IEnumerator<ulong> GetEnumerator()
- //{
- // this.Reset();
- // return this;
- //}
-
- //IEnumerator IEnumerable.GetEnumerator()
- //{
- // this.Reset();
- // return this;
- //}
}
internal class CellsStoreEnumerator<T> : IEnumerable<T>, IEnumerator<T> {
@@ -1639,29 +1435,14 @@
}
internal T Value {
- get {
- lock (_cellStore) {
- return _cellStore.GetValue(row, Column);
- }
- }
- set {
- lock (_cellStore) {
- _cellStore.SetValue(row, Column, value);
- }
- }
+ get => _cellStore.GetValue(row, Column);
+ set => _cellStore.SetValue(row, Column, value);
}
internal bool Next() {
- //return _cellStore.GetNextCell(ref row, ref colPos, minColPos, maxRow, maxColPos);
return _cellStore.GetNextCell(ref row, ref colPos, minColPos, maxRow, maxColPos);
}
- internal bool Previous() {
- lock (_cellStore) {
- return _cellStore.GetPrevCell(ref row, ref colPos, minRow, minColPos, maxColPos);
- }
- }
-
public string CellAddress => ExcelCellBase.GetAddress(Row, Column);
public IEnumerator<T> GetEnumerator() {
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingCollection.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingCollection.cs
index 08605aa..8717d2e 100644
--- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingCollection.cs
+++ b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingCollection.cs
@@ -31,6 +31,7 @@
using System.Collections;
using System.Collections.Generic;
+using System.Collections.Immutable;
using System.Xml;
using OfficeOpenXml.ConditionalFormatting.Contracts;
using OfficeOpenXml.Utils;
@@ -68,6 +69,9 @@
private readonly List<IExcelConditionalFormattingRule> _rules = new();
private readonly ExcelWorksheet _worksheet;
+ protected override ImmutableArray<string> SchemaNodeOrder =>
+ ExcelWorksheet.WorksheetSchemaNodeOrder;
+
/// <summary>
/// Initialize the <see cref="ExcelConditionalFormattingCollection"/>
/// </summary>
@@ -77,7 +81,6 @@
Require.Argument(worksheet).IsNotNull("worksheet");
_worksheet = worksheet;
- SchemaNodeOrder = _worksheet.SchemaNodeOrder;
// Look for all the <conditionalFormatting>
var conditionalFormattingNodes = TopNode.SelectNodes(
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingColorScaleValue.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingColorScaleValue.cs
index 84d8fb1..59376e7 100644
--- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingColorScaleValue.cs
+++ b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingColorScaleValue.cs
@@ -30,6 +30,7 @@
*******************************************************************************/
using System;
+using System.Collections.Immutable;
using System.Xml;
using OfficeOpenXml.Utils;
@@ -44,6 +45,11 @@
private eExcelConditionalFormattingRuleType _ruleType;
private readonly ExcelWorksheet _worksheet;
+ protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
+ ExcelConditionalFormattingConstants.Nodes._cfvo,
+ ExcelConditionalFormattingConstants.Nodes._color,
+ ];
+
/// <summary>
/// Initialize the cfvo (§18.3.1.11) node
/// </summary>
@@ -78,12 +84,6 @@
// Save the worksheet for private methods to use
_worksheet = worksheet;
- // Schema order list
- SchemaNodeOrder = new[] {
- ExcelConditionalFormattingConstants.Nodes._cfvo,
- ExcelConditionalFormattingConstants.Nodes._color,
- };
-
// Check if the parent does not exists
if (itemElementNode == null) {
// Get the parent node path by the rule type
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingIconDatabarValue.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingIconDatabarValue.cs
index bffef35..c38d095 100644
--- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingIconDatabarValue.cs
+++ b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingIconDatabarValue.cs
@@ -30,6 +30,7 @@
*******************************************************************************/
using System;
+using System.Collections.Immutable;
using System.Drawing;
using System.Globalization;
using System.Xml;
@@ -117,6 +118,10 @@
Formula = formula;
}
+ protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
+ ExcelConditionalFormattingConstants.Nodes._cfvo,
+ ];
+
/// <summary>
/// Initialize the cfvo (§18.3.1.11) node
/// </summary>
@@ -139,9 +144,6 @@
// Save the worksheet for private methods to use
_worksheet = worksheet;
- // Schema order list
- SchemaNodeOrder = new[] { ExcelConditionalFormattingConstants.Nodes._cfvo };
-
//Check if the parent does not exists
if (itemElementNode == null) {
// Get the parent node path by the rule type
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingOperatorType.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingOperatorType.cs
index cf0fae8..c513d8d 100644
--- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingOperatorType.cs
+++ b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingOperatorType.cs
@@ -29,8 +29,6 @@
* Eyal Seagull Conditional Formatting Adaption 2012-04-17
*******************************************************************************/
-using System;
-
namespace OfficeOpenXml.ConditionalFormatting;
/// <summary>
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingRuleType.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingRuleType.cs
index b1c6b32..8168caa 100644
--- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingRuleType.cs
+++ b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingRuleType.cs
@@ -29,7 +29,6 @@
* Eyal Seagull Conditional Formatting Adaption 2012-04-03
*******************************************************************************/
-using System;
using System.Xml;
namespace OfficeOpenXml.ConditionalFormatting;
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingTimePeriodType.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingTimePeriodType.cs
index 2051e7b..c93a82d 100644
--- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingTimePeriodType.cs
+++ b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingTimePeriodType.cs
@@ -29,8 +29,6 @@
* Eyal Seagull Conditional Formatting Adaption 2012-04-17
*******************************************************************************/
-using System;
-
namespace OfficeOpenXml.ConditionalFormatting;
/// <summary>
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingValueObjectType.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingValueObjectType.cs
index 9d28645..22d9356 100644
--- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingValueObjectType.cs
+++ b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingValueObjectType.cs
@@ -29,7 +29,6 @@
* Eyal Seagull Conditional Formatting Adaption 2012-04-03
*******************************************************************************/
-using System;
using System.Xml;
namespace OfficeOpenXml.ConditionalFormatting;
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingDataBar.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingDataBar.cs
index 8ca4be2..6c37773 100644
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingDataBar.cs
+++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingDataBar.cs
@@ -29,7 +29,7 @@
* Eyal Seagull Added 2012-04-03
*******************************************************************************/
-using System.Globalization;
+using System.Collections.Immutable;
using System.Xml;
using OfficeOpenXml.ConditionalFormatting.Contracts;
@@ -41,6 +41,8 @@
public class ExcelConditionalFormattingDataBar
: ExcelConditionalFormattingRule,
IExcelConditionalFormattingDataBarGroup {
+ protected override ImmutableArray<string> SchemaNodeOrder { get; } = ["cfvo", "color"];
+
/// <summary>
///
/// </summary>
@@ -64,7 +66,6 @@
worksheet,
itemElementNode,
namespaceManager ?? worksheet.NameSpaceManager) {
- SchemaNodeOrder = new[] { "cfvo", "color" };
//Create the <dataBar> node inside the <cfRule> node
if (itemElementNode != null && itemElementNode.HasChildNodes) {
bool high = false;
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingRule.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingRule.cs
index a85ebaa..082da63 100644
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingRule.cs
+++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingRule.cs
@@ -30,6 +30,7 @@
*******************************************************************************/
using System;
+using System.Collections.Immutable;
using System.Xml;
using OfficeOpenXml.ConditionalFormatting.Contracts;
using OfficeOpenXml.Style.Dxf;
@@ -50,6 +51,9 @@
/// </summary>
private static bool _changingPriority;
+ protected override ImmutableArray<string> SchemaNodeOrder =>
+ ExcelWorksheet.WorksheetSchemaNodeOrder;
+
/// <summary>
/// Initialize the <see cref="ExcelConditionalFormattingRule"/>
/// </summary>
@@ -73,7 +77,6 @@
_type = type;
_worksheet = worksheet;
- SchemaNodeOrder = _worksheet.SchemaNodeOrder;
if (itemElementNode == null) {
// Create/Get the <cfRule> inside <conditionalFormatting>
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeColorScale.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeColorScale.cs
index 5700e10..23c8d02 100644
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeColorScale.cs
+++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeColorScale.cs
@@ -29,7 +29,6 @@
* Eyal Seagull Added 2012-04-03
*******************************************************************************/
-using System.Drawing;
using System.Xml;
using OfficeOpenXml.ConditionalFormatting.Contracts;
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTwoColorScale.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTwoColorScale.cs
index ad7d79f..691f0dd 100644
--- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTwoColorScale.cs
+++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTwoColorScale.cs
@@ -29,7 +29,6 @@
* Eyal Seagull Added 2012-04-03
*******************************************************************************/
-using System.Drawing;
using System.Xml;
using OfficeOpenXml.ConditionalFormatting.Contracts;
diff --git a/EPPlus/DataValidation/ExcelDataValidation.cs b/EPPlus/DataValidation/ExcelDataValidation.cs
index 88a60de..1e5f445 100644
--- a/EPPlus/DataValidation/ExcelDataValidation.cs
+++ b/EPPlus/DataValidation/ExcelDataValidation.cs
@@ -31,6 +31,7 @@
*******************************************************************************/
using System;
+using System.Collections.Immutable;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Xml;
@@ -59,6 +60,22 @@
protected readonly string _formula1Path = "d:formula1";
protected readonly string _formula2Path = "d:formula2";
+ protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
+ "type",
+ "errorStyle",
+ "operator",
+ "allowBlank",
+ "showInputMessage",
+ "showErrorMessage",
+ "errorTitle",
+ "error",
+ "promptTitle",
+ "prompt",
+ "sqref",
+ "formula1",
+ "formula2",
+ ];
+
internal ExcelDataValidation(
ExcelWorksheet worksheet,
string address,
@@ -112,26 +129,6 @@
TopNode = itemElementNode;
ValidationType = validationType;
Address = new(address);
- Init();
- }
-
- private void Init() {
- // set schema node order
- SchemaNodeOrder = new[] {
- "type",
- "errorStyle",
- "operator",
- "allowBlank",
- "showInputMessage",
- "showErrorMessage",
- "errorTitle",
- "error",
- "promptTitle",
- "prompt",
- "sqref",
- "formula1",
- "formula2",
- };
}
private string CheckAndFixRangeAddress(string address) {
diff --git a/EPPlus/DataValidation/ExcelDataValidationCollection.cs b/EPPlus/DataValidation/ExcelDataValidationCollection.cs
index 4518881..3c186a5 100644
--- a/EPPlus/DataValidation/ExcelDataValidationCollection.cs
+++ b/EPPlus/DataValidation/ExcelDataValidationCollection.cs
@@ -36,6 +36,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
+using System.Collections.Immutable;
using System.Xml;
using OfficeOpenXml.DataValidation.Contracts;
using OfficeOpenXml.Utils;
@@ -75,6 +76,9 @@
"{0}/d:dataValidation",
_dataValidationPath);
+ protected override ImmutableArray<string> SchemaNodeOrder =>
+ ExcelWorksheet.WorksheetSchemaNodeOrder;
+
/// <summary>
/// Constructor
/// </summary>
@@ -83,7 +87,6 @@
: base(worksheet.NameSpaceManager, worksheet.WorksheetXml.DocumentElement) {
Require.Argument(worksheet).IsNotNull("worksheet");
_worksheet = worksheet;
- SchemaNodeOrder = worksheet.SchemaNodeOrder;
// check existing nodes and load them
var dataValidationNodes = worksheet.WorksheetXml.SelectNodes(
diff --git a/EPPlus/Drawing/Vml/ExcelVmlDrawingBase.cs b/EPPlus/Drawing/Vml/ExcelVmlDrawingBase.cs
index df934c8..ade7974 100644
--- a/EPPlus/Drawing/Vml/ExcelVmlDrawingBase.cs
+++ b/EPPlus/Drawing/Vml/ExcelVmlDrawingBase.cs
@@ -30,6 +30,7 @@
* Jan Källman License changed GPL-->LGPL 2011-12-16
*******************************************************************************/
+using System.Collections.Immutable;
using System.Xml;
namespace OfficeOpenXml.Drawing.Vml;
@@ -70,28 +71,28 @@
/// Drawing object used for comments
/// </summary>
public class ExcelVmlDrawingBase : XmlHelper {
+ protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
+ "fill",
+ "stroke",
+ "shadow",
+ "path",
+ "textbox",
+ "ClientData",
+ "MoveWithCells",
+ "SizeWithCells",
+ "Anchor",
+ "Locked",
+ "AutoFill",
+ "LockText",
+ "TextHAlign",
+ "TextVAlign",
+ "Row",
+ "Column",
+ "Visible",
+ ];
+
internal ExcelVmlDrawingBase(XmlNode topNode, XmlNamespaceManager ns)
- : base(ns, topNode) {
- SchemaNodeOrder = new[] {
- "fill",
- "stroke",
- "shadow",
- "path",
- "textbox",
- "ClientData",
- "MoveWithCells",
- "SizeWithCells",
- "Anchor",
- "Locked",
- "AutoFill",
- "LockText",
- "TextHAlign",
- "TextVAlign",
- "Row",
- "Column",
- "Visible",
- };
- }
+ : base(ns, topNode) {}
public string Id {
get => GetXmlNodeString("@id");
diff --git a/EPPlus/Drawing/Vml/ExcelVmlDrawingBaseCollection.cs b/EPPlus/Drawing/Vml/ExcelVmlDrawingBaseCollection.cs
index 912214e..a0bd7e1 100644
--- a/EPPlus/Drawing/Vml/ExcelVmlDrawingBaseCollection.cs
+++ b/EPPlus/Drawing/Vml/ExcelVmlDrawingBaseCollection.cs
@@ -38,7 +38,6 @@
public class ExcelVmlDrawingBaseCollection {
internal ExcelVmlDrawingBaseCollection(ExcelPackage pck, ExcelWorksheet ws, Uri uri) {
- VmlDrawingXml = new();
VmlDrawingXml.PreserveWhitespace = false;
NameTable nt = new NameTable();
@@ -55,7 +54,8 @@
}
}
- internal XmlDocument VmlDrawingXml { get; set; }
+ internal XmlDocument VmlDrawingXml { get; set; } = new();
+
internal Uri Uri { get; set; }
internal string RelId { get; set; }
internal ZipPackagePart Part { get; set; }
diff --git a/EPPlus/Drawing/Vml/ExcelVmlDrawingComment.cs b/EPPlus/Drawing/Vml/ExcelVmlDrawingComment.cs
index bd137cd..7eecb26 100644
--- a/EPPlus/Drawing/Vml/ExcelVmlDrawingComment.cs
+++ b/EPPlus/Drawing/Vml/ExcelVmlDrawingComment.cs
@@ -30,6 +30,7 @@
* Jan Källman License changed GPL-->LGPL 2011-12-16
*******************************************************************************/
+using System.Collections.Immutable;
using System.Xml;
namespace OfficeOpenXml.Drawing.Vml;
@@ -38,28 +39,29 @@
/// Drawing object used for comments
/// </summary>
public class ExcelVmlDrawingComment : ExcelVmlDrawingBase, IRangeId {
+ protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
+ "fill",
+ "stroke",
+ "shadow",
+ "path",
+ "textbox",
+ "ClientData",
+ "MoveWithCells",
+ "SizeWithCells",
+ "Anchor",
+ "Locked",
+ "AutoFill",
+ "LockText",
+ "TextHAlign",
+ "TextVAlign",
+ "Row",
+ "Column",
+ "Visible",
+ ];
+
internal ExcelVmlDrawingComment(XmlNode topNode, ExcelRangeBase range, XmlNamespaceManager ns)
: base(topNode, ns) {
Range = range;
- SchemaNodeOrder = new[] {
- "fill",
- "stroke",
- "shadow",
- "path",
- "textbox",
- "ClientData",
- "MoveWithCells",
- "SizeWithCells",
- "Anchor",
- "Locked",
- "AutoFill",
- "LockText",
- "TextHAlign",
- "TextVAlign",
- "Row",
- "Column",
- "Visible",
- };
}
internal ExcelRangeBase Range { get; set; }
diff --git a/EPPlus/Drawing/Vml/ExcelVmlDrawingPosition.cs b/EPPlus/Drawing/Vml/ExcelVmlDrawingPosition.cs
index 294f9b2..ec28659 100644
--- a/EPPlus/Drawing/Vml/ExcelVmlDrawingPosition.cs
+++ b/EPPlus/Drawing/Vml/ExcelVmlDrawingPosition.cs
@@ -30,7 +30,6 @@
* Jan Källman License changed GPL-->LGPL 2011-12-16
*******************************************************************************/
-using System;
using System.Xml;
namespace OfficeOpenXml.Drawing.Vml;
diff --git a/EPPlus/EPPlusSDK.csproj b/EPPlus/EPPlusSDK.csproj
index 2cdc079..2a2e866 100644
--- a/EPPlus/EPPlusSDK.csproj
+++ b/EPPlus/EPPlusSDK.csproj
@@ -4,6 +4,6 @@
<RootNamespace>OfficeOpenXml</RootNamespace>
<AssemblyName>EPPlus</AssemblyName>
<PackageId>Appsheet.EPPlus</PackageId>
- <Version>1.0.5</Version>
+ <Version>1.0.6</Version>
</PropertyGroup>
</Project>
diff --git a/EPPlus/ExcelAddress.cs b/EPPlus/ExcelAddress.cs
index 9a5f20d..51ad999 100644
--- a/EPPlus/ExcelAddress.cs
+++ b/EPPlus/ExcelAddress.cs
@@ -33,7 +33,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
-using System.Text.RegularExpressions;
namespace OfficeOpenXml;
@@ -837,7 +836,6 @@
}
internal static AddressType IsValid(string address) {
- double d;
if (address == "#REF!") {
return AddressType.Invalid;
}
@@ -845,15 +843,14 @@
address,
NumberStyles.Any,
CultureInfo.InvariantCulture,
- out d)) //A double, no valid address
+ out _)) //A double, no valid address
{
return AddressType.Invalid;
}
if (IsFormula(address)) {
return AddressType.Formula;
}
- string ws;
- if (SplitAddress(address, out var wb, out ws, out var intAddress)) {
+ if (SplitAddress(address, out var wb, out _, out var intAddress)) {
if (intAddress.Contains(
"[")) //Table reference
{
@@ -868,72 +865,6 @@
return string.IsNullOrEmpty(wb) ? AddressType.InternalName : AddressType.ExternalName;
}
return AddressType.Invalid;
-
- //if(string.IsNullOrEmpty(wb));
- //ExcelAddress a = new ExcelAddress(Address);
- //if (Address.IndexOf('!') > 0)
- //{
- // string[] split = Address.Split('!');
- // if (split.Length == 2)
- // {
- // ws = split[0];
- // Address = split[1];
- // }
- // else if (split.Length == 3 && split[1] == "#REF" && split[2] == "")
- // {
- // ws = split[0];
- // Address = "#REF!";
- // if (ws.StartsWith("[") && ws.IndexOf("]") > 1)
- // {
- // return AddressType.ExternalAddress;
- // }
- // else
- // {
- // return AddressType.InternalAddress;
- // }
- // }
- // else
- // {
- // return AddressType.Invalid;
- // }
- //}
- //int _fromRow, column, _toRow, _toCol;
- //if (ExcelAddressBase.GetRowColFromAddress(Address, out _fromRow, out column, out _toRow, out _toCol))
- //{
- // if (_fromRow > 0 && column > 0 && _toRow <= ExcelPackage.MaxRows && _toCol <= ExcelPackage.MaxColumns)
- // {
- // if (ws.StartsWith("[") && ws.IndexOf("]") > 1)
- // {
- // return AddressType.ExternalAddress;
- // }
- // else
- // {
- // return AddressType.InternalAddress;
- // }
- // }
- // else
- // {
- // return AddressType.Invalid;
- // }
- //}
- //else
- //{
- // if(IsValidName(Address))
- // {
- // if (ws.StartsWith("[") && ws.IndexOf("]") > 1)
- // {
- // return AddressType.ExternalName;
- // }
- // else
- // {
- // return AddressType.InternalName;
- // }
- // }
- // else
- // {
- // return AddressType.Invalid;
- // }
- //}
}
private static bool IsAddress(string intAddress) {
@@ -1040,12 +971,8 @@
public int Columns => _toCol - _fromCol + 1;
- internal bool IsMultiCell() {
- return (_fromRow < _fromCol || _fromCol < _toCol);
- }
-
internal static String GetWorkbookPart(string address) {
- var ix = 0;
+ int ix;
if (address[0] == '[') {
ix = address.IndexOf(']') + 1;
if (ix > 0) {
@@ -1055,11 +982,6 @@
return "";
}
- internal static string GetWorksheetPart(string address, string defaultWorkSheet) {
- int ix = 0;
- return GetWorksheetPart(address, defaultWorkSheet, ref ix);
- }
-
internal static string GetWorksheetPart(string address, string defaultWorkSheet, ref int endIx) {
if (address == "") {
return defaultWorkSheet;
@@ -1081,18 +1003,6 @@
return defaultWorkSheet;
}
- internal static string GetAddressPart(string address) {
- var ix = 0;
- GetWorksheetPart(address, "", ref ix);
- if (ix < address.Length) {
- if (address[ix] == '!') {
- return address.Substring(ix + 1);
- }
- return "";
- }
- return "";
- }
-
internal static void SplitAddress(
string fullAddress,
out string wb,
@@ -1115,9 +1025,7 @@
private static string GetString(string address, int ix, out int endIx) {
var strIx = address.IndexOf("''");
- var prevStrIx = ix;
while (strIx > -1) {
- prevStrIx = strIx;
strIx = address.IndexOf("''");
}
endIx = address.IndexOf("'");
@@ -1189,8 +1097,6 @@
_fromColFixed,
_toColFixed;
- internal ExcelFormulaAddress() {}
-
public ExcelFormulaAddress(int fromRow, int fromCol, int toRow, int toColumn)
: base(fromRow, fromCol, toRow, toColumn) {
_ws = "";
@@ -1201,24 +1107,6 @@
SetFixed();
}
- internal ExcelFormulaAddress(string ws, string address)
- : base(address) {
- if (string.IsNullOrEmpty(_ws)) {
- _ws = ws;
- }
- SetFixed();
- }
-
- internal ExcelFormulaAddress(string ws, string address, bool isName)
- : base(address, isName) {
- if (string.IsNullOrEmpty(_ws)) {
- _ws = ws;
- }
- if (!isName) {
- SetFixed();
- }
- }
-
private void SetFixed() {
if (Address.IndexOf("[") >= 0) {
return;
diff --git a/EPPlus/ExcelCellBase.cs b/EPPlus/ExcelCellBase.cs
index df48cb3..5a0b25e 100644
--- a/EPPlus/ExcelCellBase.cs
+++ b/EPPlus/ExcelCellBase.cs
@@ -153,7 +153,6 @@
if (isText == false && part != "" && prevTq == c) {
ret += addressTranslator(part, row, col, rowIncr, colIncr);
part = "";
- prevTq = (char)0;
}
prevTq = c;
isText = !isText;
@@ -220,7 +219,6 @@
if (isText == false && part != "" && prevTq == c) {
ret += addressTranslator(part, row, col, rowIncr, colIncr);
part = "";
- prevTq = (char)0;
}
prevTq = c;
isText = !isText;
diff --git a/EPPlus/ExcelColumn.cs b/EPPlus/ExcelColumn.cs
index 31bd864..889c682 100644
--- a/EPPlus/ExcelColumn.cs
+++ b/EPPlus/ExcelColumn.cs
@@ -30,7 +30,6 @@
* Jan K�llman License changed GPL-->LGPL 2011-12-27
*******************************************************************************/
-using System;
using System.Xml;
using OfficeOpenXml.Style;
diff --git a/EPPlus/ExcelComment.cs b/EPPlus/ExcelComment.cs
index 3930bde..74df866 100644
--- a/EPPlus/ExcelComment.cs
+++ b/EPPlus/ExcelComment.cs
@@ -40,7 +40,7 @@
/// An Excel Cell Comment
/// </summary>
public class ExcelComment : ExcelVmlDrawingComment {
- internal XmlHelper _commentHelper;
+ private readonly XmlHelper _commentHelper;
private readonly string _text;
internal ExcelComment(XmlNamespaceManager ns, XmlNode commentTopNode, ExcelRangeBase cell)
@@ -83,10 +83,6 @@
_commentHelper.NameSpaceManager)
.InnerText;
}
- set {
- int authorRef = GetAuthor(value);
- _commentHelper.SetXmlNodeString("@authorId", authorRef.ToString());
- }
}
private int GetAuthor(string value) {
@@ -141,5 +137,5 @@
/// <summary>
/// Richtext collection
/// </summary>
- public ExcelRichTextCollection RichText { get; set; }
+ internal ExcelRichTextCollection RichText { get; set; }
}
diff --git a/EPPlus/ExcelCommentCollection.cs b/EPPlus/ExcelCommentCollection.cs
index 9146df7..70a4820 100644
--- a/EPPlus/ExcelCommentCollection.cs
+++ b/EPPlus/ExcelCommentCollection.cs
@@ -45,7 +45,6 @@
internal RangeCollection _comments;
internal ExcelCommentCollection(ExcelPackage pck, ExcelWorksheet ws, XmlNamespaceManager ns) {
- CommentXml = new();
CommentXml.PreserveWhitespace = false;
NameSpaceManager = ns;
Worksheet = ws;
@@ -89,7 +88,7 @@
/// <summary>
/// Access to the comment xml document
/// </summary>
- public XmlDocument CommentXml { get; set; }
+ public XmlDocument CommentXml { get; set; } = new();
internal Uri Uri { get; set; }
diff --git a/EPPlus/ExcelHeaderFooter.cs b/EPPlus/ExcelHeaderFooter.cs
deleted file mode 100644
index c4a3eeb..0000000
--- a/EPPlus/ExcelHeaderFooter.cs
+++ /dev/null
@@ -1,349 +0,0 @@
-/*******************************************************************************
- * 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 2009-10-01
- * Jan Källman Total rewrite 2010-03-01
- * Jan Källman License changed GPL-->LGPL 2011-12-27
- * *******************************************************************************/
-
-using System.Xml;
-
-namespace OfficeOpenXml;
-
-/// <summary>
-/// Print header and footer
-/// </summary>
-public class ExcelHeaderFooterText {
- private ExcelWorksheet _ws;
- private string _hf;
-
- internal ExcelHeaderFooterText(XmlNode textNode, ExcelWorksheet ws, string hf) {
- _ws = ws;
- _hf = hf;
- if (textNode == null || string.IsNullOrEmpty(textNode.InnerText)) {
- return;
- }
- string text = textNode.InnerText;
- string code = text.Substring(0, 2);
- int startPos = 2;
- for (int pos = startPos; pos < text.Length - 2; pos++) {
- string newCode = text.Substring(pos, 2);
- if (newCode == "&C" || newCode == "&R") {
- SetText(code, text.Substring(startPos, pos - startPos));
- startPos = pos + 2;
- pos = startPos;
- code = newCode;
- }
- }
- SetText(code, text.Substring(startPos, text.Length - startPos));
- }
-
- private void SetText(string code, string text) {
- switch (code) {
- case "&L":
- LeftAlignedText = text;
- break;
- case "&C":
- CenteredText = text;
- break;
- default:
- RightAlignedText = text;
- break;
- }
- }
-
- /// <summary>
- /// Get/set the text to appear on the left hand side of the header (or footer) on the worksheet.
- /// </summary>
- public string LeftAlignedText;
-
- /// <summary>
- /// Get/set the text to appear in the center of the header (or footer) on the worksheet.
- /// </summary>
- public string CenteredText;
-
- /// <summary>
- /// Get/set the text to appear on the right hand side of the header (or footer) on the worksheet.
- /// </summary>
- public string RightAlignedText;
-}
-
-/// <summary>
-/// Represents the Header and Footer on an Excel Worksheet
-/// </summary>
-public sealed class ExcelHeaderFooter : XmlHelper {
- /// <summary>
- /// The code for "current page #"
- /// </summary>
- public const string PageNumber = "&P";
-
- /// <summary>
- /// The code for "total pages"
- /// </summary>
- public const string NumberOfPages = "&N";
-
- /// <summary>
- /// The code for "text font color"
- /// RGB Color is specified as RRGGBB
- /// Theme Color is specified as TTSNN where TT is the theme color Id, S is either "+" or "-" of the tint/shade value, NN is the tint/shade value.
- /// </summary>
- public const string FontColor = "&K";
-
- /// <summary>
- /// The code for "sheet tab name"
- /// </summary>
- public const string SheetName = "&A";
-
- /// <summary>
- /// The code for "this workbook's file path"
- /// </summary>
- public const string FilePath = "&Z";
-
- /// <summary>
- /// The code for "this workbook's file name"
- /// </summary>
- public const string FileName = "&F";
-
- /// <summary>
- /// The code for "date"
- /// </summary>
- public const string CurrentDate = "&D";
-
- /// <summary>
- /// The code for "time"
- /// </summary>
- public const string CurrentTime = "&T";
-
- /// <summary>
- /// The code for "picture as background"
- /// </summary>
- public const string Image = "&G";
-
- /// <summary>
- /// The code for "outline style"
- /// </summary>
- public const string OutlineStyle = "&O";
-
- /// <summary>
- /// The code for "shadow style"
- /// </summary>
- public const string ShadowStyle = "&H";
-
- internal ExcelHeaderFooterText _oddHeader;
- internal ExcelHeaderFooterText _oddFooter;
- internal ExcelHeaderFooterText _evenHeader;
- internal ExcelHeaderFooterText _evenFooter;
- internal ExcelHeaderFooterText _firstHeader;
- internal ExcelHeaderFooterText _firstFooter;
- private readonly ExcelWorksheet _ws;
-
- /// <summary>
- /// ExcelHeaderFooter Constructor
- /// </summary>
- /// <param name="nameSpaceManager"></param>
- /// <param name="topNode"></param>
- /// <param name="ws">The worksheet</param>
- internal ExcelHeaderFooter(
- XmlNamespaceManager nameSpaceManager,
- XmlNode topNode,
- ExcelWorksheet ws)
- : base(nameSpaceManager, topNode) {
- _ws = ws;
- SchemaNodeOrder = new[] {
- "headerFooter",
- "oddHeader",
- "oddFooter",
- "evenHeader",
- "evenFooter",
- "firstHeader",
- "firstFooter",
- };
- }
-
- private const string _alignWithMarginsPath = "@alignWithMargins";
-
- /// <summary>
- /// Gets/sets the alignWithMargins attribute
- /// </summary>
- public bool AlignWithMargins {
- get => GetXmlNodeBool(_alignWithMarginsPath);
- set => SetXmlNodeString(_alignWithMarginsPath, value ? "1" : "0");
- }
-
- private const string _differentOddEvenPath = "@differentOddEven";
-
- /// <summary>
- /// Gets/sets the flag that tells Excel to display different headers and footers on odd and even pages.
- /// </summary>
- public bool differentOddEven {
- get => GetXmlNodeBool(_differentOddEvenPath);
- set => SetXmlNodeString(_differentOddEvenPath, value ? "1" : "0");
- }
-
- private const string _differentFirstPath = "@differentFirst";
-
- /// <summary>
- /// Gets/sets the flag that tells Excel to display different headers and footers on the first page of the worksheet.
- /// </summary>
- public bool differentFirst {
- get => GetXmlNodeBool(_differentFirstPath);
- set => SetXmlNodeString(_differentFirstPath, value ? "1" : "0");
- }
-
- /// <summary>
- /// Provides access to the header on odd numbered pages of the document.
- /// If you want the same header on both odd and even pages, then only set values in this ExcelHeaderFooterText class.
- /// </summary>
- public ExcelHeaderFooterText OddHeader {
- get {
- if (_oddHeader == null) {
- _oddHeader = new(TopNode.SelectSingleNode("d:oddHeader", NameSpaceManager), _ws, "H");
- }
- return _oddHeader;
- }
- }
-
- /// <summary>
- /// Provides access to the footer on odd numbered pages of the document.
- /// If you want the same footer on both odd and even pages, then only set values in this ExcelHeaderFooterText class.
- /// </summary>
- public ExcelHeaderFooterText OddFooter {
- get {
- if (_oddFooter == null) {
- _oddFooter = new(TopNode.SelectSingleNode("d:oddFooter", NameSpaceManager), _ws, "F");
- ;
- }
- return _oddFooter;
- }
- }
-
- // evenHeader and evenFooter set differentOddEven = true
- /// <summary>
- /// Provides access to the header on even numbered pages of the document.
- /// </summary>
- public ExcelHeaderFooterText EvenHeader {
- get {
- if (_evenHeader == null) {
- _evenHeader = new(TopNode.SelectSingleNode("d:evenHeader", NameSpaceManager), _ws, "HEVEN");
- differentOddEven = true;
- }
- return _evenHeader;
- }
- }
-
- /// <summary>
- /// Provides access to the footer on even numbered pages of the document.
- /// </summary>
- public ExcelHeaderFooterText EvenFooter {
- get {
- if (_evenFooter == null) {
- _evenFooter = new(TopNode.SelectSingleNode("d:evenFooter", NameSpaceManager), _ws, "FEVEN");
- differentOddEven = true;
- }
- return _evenFooter;
- }
- }
-
- /// <summary>
- /// Provides access to the header on the first page of the document.
- /// </summary>
- public ExcelHeaderFooterText FirstHeader {
- get {
- if (_firstHeader == null) {
- _firstHeader = new(
- TopNode.SelectSingleNode("d:firstHeader", NameSpaceManager),
- _ws,
- "HFIRST");
- differentFirst = true;
- }
- return _firstHeader;
- }
- }
-
- /// <summary>
- /// Provides access to the footer on the first page of the document.
- /// </summary>
- public ExcelHeaderFooterText FirstFooter {
- get {
- if (_firstFooter == null) {
- _firstFooter = new(
- TopNode.SelectSingleNode("d:firstFooter", NameSpaceManager),
- _ws,
- "FFIRST");
- differentFirst = true;
- }
- return _firstFooter;
- }
- }
-
- /// <summary>
- /// Saves the header and footer information to the worksheet XML
- /// </summary>
- internal void Save() {
- if (_oddHeader != null) {
- SetXmlNodeString("d:oddHeader", GetText(OddHeader));
- }
- if (_oddFooter != null) {
- SetXmlNodeString("d:oddFooter", GetText(OddFooter));
- }
-
- // only set evenHeader and evenFooter
- if (differentOddEven) {
- if (_evenHeader != null) {
- SetXmlNodeString("d:evenHeader", GetText(EvenHeader));
- }
- if (_evenFooter != null) {
- SetXmlNodeString("d:evenFooter", GetText(EvenFooter));
- }
- }
-
- // only set firstHeader and firstFooter
- if (differentFirst) {
- if (_firstHeader != null) {
- SetXmlNodeString("d:firstHeader", GetText(FirstHeader));
- }
- if (_firstFooter != null) {
- SetXmlNodeString("d:firstFooter", GetText(FirstFooter));
- }
- }
- }
-
- private string GetText(ExcelHeaderFooterText headerFooter) {
- string ret = "";
- if (headerFooter.LeftAlignedText != null) {
- ret += "&L" + headerFooter.LeftAlignedText;
- }
- if (headerFooter.CenteredText != null) {
- ret += "&C" + headerFooter.CenteredText;
- }
- if (headerFooter.RightAlignedText != null) {
- ret += "&R" + headerFooter.RightAlignedText;
- }
- return ret;
- }
-}
diff --git a/EPPlus/ExcelPackage.cs b/EPPlus/ExcelPackage.cs
index be8f56e..7d12a0e 100644
--- a/EPPlus/ExcelPackage.cs
+++ b/EPPlus/ExcelPackage.cs
@@ -42,32 +42,10 @@
namespace OfficeOpenXml;
/// <summary>
-/// Maps to DotNetZips CompressionLevel enum
-/// </summary>
-public enum CompressionLevel {
- Level0 = 0,
- None = 0,
- Level1 = 1,
- BestSpeed = 1,
- Level2 = 2,
- Level3 = 3,
- Level4 = 4,
- Level5 = 5,
- Level6 = 6,
- Default = 6,
- Level7 = 7,
- Level8 = 8,
- BestCompression = 9,
- Level9 = 9,
-}
-
-/// <summary>
/// Represents an Excel XLSX file package.
-/// This is the top-level object to access all parts of the document.\
+/// This is the top-level object to access all parts of the document.
/// </summary>
public sealed class ExcelPackage {
- internal const bool _preserveWhitespace = false;
-
/// <summary>
/// Extention Schema types
/// </summary>
@@ -86,8 +64,6 @@
internal const string _schemaRelationships =
"http://schemas.openxmlformats.org/officeDocument/2006/relationships";
- internal const string _schemaDrawings = "http://schemas.openxmlformats.org/drawingml/2006/main";
-
internal const string _schemaMicrosoftVml = "urn:schemas-microsoft-com:vml";
internal const string _schemaMicrosoftOffice = "urn:schemas-microsoft-com:office:office";
internal const string _schemaMicrosoftExcel = "urn:schemas-microsoft-com:office:excel";
@@ -112,18 +88,6 @@
internal const string _schemaVt =
"http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes";
- //Pivottables
- internal const string _schemaPivotTable =
- "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml";
- internal const string _schemaPivotCacheDefinition =
- "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml";
- internal const string _schemaPivotCacheRecords =
- "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml";
-
- internal const string _contentTypeWorkbookDefault =
- "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml";
- internal const string _contentTypeWorkbookMacroEnabled =
- "application/vnd.ms-excel.sheet.macroEnabled.main+xml";
internal const string _contentTypeSharedString =
"application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml";
@@ -142,13 +106,7 @@
/// </summary>
public ExcelPackage() {
Package = new();
- Workbook = CreateWorkbook();
- _ = Workbook.WorkbookXml;
- // create the relationship to the main part
- Package.CreateRelationship(
- UriHelper.GetRelativeUri(new("/xl", UriKind.Relative), ExcelWorkbook.WorkbookUri),
- TargetMode.Internal,
- _schemaRelationships + "/officeDocument");
+ Workbook = new(this, CreateDefaultNsm());
}
/// <summary>
@@ -157,7 +115,7 @@
public ExcelPackage(FileInfo newFile) {
using var inputStream = newFile.OpenRead();
Package = new(inputStream);
- Workbook = CreateWorkbook();
+ Workbook = new(this, CreateDefaultNsm());
}
/// <summary>
@@ -165,14 +123,7 @@
/// </summary>
public ExcelPackage(Stream newStream) {
Package = new(newStream);
- Workbook = CreateWorkbook();
- }
-
- private ExcelWorkbook CreateWorkbook() {
- ExcelWorkbook workbook = new(this, CreateDefaultNsm());
- workbook.GetExternalReferences();
- workbook.GetDefinedNames();
- return workbook;
+ Workbook = new(this, CreateDefaultNsm());
}
internal ZipPackage Package { get; }
@@ -207,52 +158,54 @@
return ns;
}
- /// <summary>
- /// Saves the XmlDocument into the package at the specified Uri.
- /// </summary>
- /// <param name="uri">The Uri of the component</param>
- /// <param name="xmlDoc">The XmlDocument to save</param>
- internal void SavePart(Uri uri, XmlDocument xmlDoc) {
- ZipPackagePart part = Package.GetPart(uri);
- xmlDoc.Save(part.GetStream(FileMode.Create, FileAccess.Write));
+ internal XmlDocument GetXmlDocument(Uri uri) {
+ var xmlDocument = new XmlDocument();
+ var part = Package.GetPart(uri);
+ XmlHelper.LoadXmlSafe(xmlDocument, part.GetStream());
+ part.SaveHandler = writer => xmlDocument.Save(writer);
+ return xmlDocument;
}
- /// <summary>
- /// Compression option for the package
- /// </summary>
- public CompressionLevel Compression {
- get => Package.Compression;
- set => Package.Compression = value;
+ internal ZipPackageRelationship CreateXmlDocument(
+ Uri uri,
+ string contentType,
+ string relationship,
+ XmlDocument newDoc) {
+ Package.CreatePart(uri, contentType, newDoc.Save);
+ return Package.CreateRelationship(
+ UriHelper.GetRelativeUri(new("/xl", UriKind.Relative), uri),
+ TargetMode.Internal,
+ relationship);
}
- /// <summary>
- /// Get the XmlDocument from an URI
- /// </summary>
- /// <param name="uri">The Uri to the part</param>
- /// <returns>The XmlDocument</returns>
- internal XmlDocument GetXmlFromUri(Uri uri) {
- XmlDocument xml = new XmlDocument();
- ZipPackagePart part = Package.GetPart(uri);
- XmlHelper.LoadXmlSafe(xml, part.GetStream());
- return (xml);
+ internal XmlDocument GetOrCreateXmlDocument(
+ Uri uri,
+ string contentType,
+ string relationship,
+ Func<XmlDocument> createDocument) {
+ if (Package.PartExists(uri)) {
+ return GetXmlDocument(uri);
+ }
+ var newDoc = createDocument();
+ CreateXmlDocument(uri, contentType, relationship, newDoc);
+ return newDoc;
}
- /// <summary>
- /// Saves and returns the Excel files as a bytearray.
- /// Note that the package is closed upon save
- /// </summary>
- /// <example>
- /// Example how to return a document from a Webserver...
- /// <code>
- /// ExcelPackage package=new ExcelPackage();
- /// /**** ... Create the document ****/
- /// Byte[] bin = package.GetAsByteArray();
- /// Response.ContentType = "Application/vnd.ms-Excel";
- /// Response.AddHeader("content-disposition", "attachment; filename=TheFile.xlsx");
- /// Response.BinaryWrite(bin);
- /// </code>
- /// </example>
- /// <returns></returns>
+ internal XmlDocument GetOrCreateXmlDocument(
+ Uri uri,
+ string contentType,
+ string relationship,
+ string initialDocumentXml) =>
+ GetOrCreateXmlDocument(
+ uri,
+ contentType,
+ relationship,
+ () => {
+ var emptyDocument = new XmlDocument();
+ emptyDocument.LoadXml(initialDocumentXml);
+ return emptyDocument;
+ });
+
public byte[] GetAsByteArray() {
var result = new MemoryStream();
Workbook.Save();
diff --git a/EPPlus/ExcelProtectedRange.cs b/EPPlus/ExcelProtectedRange.cs
index ef0da39..f89c544 100644
--- a/EPPlus/ExcelProtectedRange.cs
+++ b/EPPlus/ExcelProtectedRange.cs
@@ -1,35 +1,14 @@
using System.Xml;
-using OfficeOpenXml.Utils;
namespace OfficeOpenXml;
public class ExcelProtectedRange : XmlHelper {
- public string Name {
- get => GetXmlNodeString("@name");
- set => SetXmlNodeString("@name", value);
- }
+ public string Name => GetXmlNodeString("@name");
private ExcelAddress _address;
- public ExcelAddress Address {
- get {
- if (_address == null) {
- _address = new(GetXmlNodeString("@sqref"));
- }
- return _address;
- }
- set {
- SetXmlNodeString("@sqref", SqRefUtility.ToSqRefAddress(value.Address));
- _address = value;
- }
- }
- internal ExcelProtectedRange(
- string name,
- ExcelAddress address,
- XmlNamespaceManager ns,
- XmlNode topNode)
- : base(ns, topNode) {
- Name = name;
- Address = address;
- }
+ public ExcelAddress Address => _address ??= new(GetXmlNodeString("@sqref"));
+
+ internal ExcelProtectedRange(XmlNamespaceManager ns, XmlNode topNode)
+ : base(ns, topNode) {}
}
diff --git a/EPPlus/ExcelProtectedRangeCollection.cs b/EPPlus/ExcelProtectedRangeCollection.cs
index fdc2053..0b95ccf 100644
--- a/EPPlus/ExcelProtectedRangeCollection.cs
+++ b/EPPlus/ExcelProtectedRangeCollection.cs
@@ -1,15 +1,11 @@
using System.Collections;
using System.Collections.Generic;
using System.Xml;
-using OfficeOpenXml.Utils;
namespace OfficeOpenXml;
public class ExcelProtectedRangeCollection : XmlHelper, IEnumerable<ExcelProtectedRange> {
- internal ExcelProtectedRangeCollection(
- XmlNamespaceManager nsm,
- XmlNode topNode,
- ExcelWorksheet ws)
+ internal ExcelProtectedRangeCollection(XmlNamespaceManager nsm, XmlNode topNode)
: base(nsm, topNode) {
foreach (XmlNode protectedRangeNode in topNode.SelectNodes(
"d:protectedRanges/d:protectedRange",
@@ -17,64 +13,12 @@
if (!(protectedRangeNode is XmlElement)) {
continue;
}
- _baseList.Add(
- new(
- protectedRangeNode.Attributes["name"].Value,
- new(SqRefUtility.FromSqRefAddress(protectedRangeNode.Attributes["sqref"].Value)),
- nsm,
- topNode));
+ _baseList.Add(new(nsm, topNode));
}
}
private readonly List<ExcelProtectedRange> _baseList = new();
- public ExcelProtectedRange Add(string name, ExcelAddress address) {
- if (!ExistNode("d:protectedRanges")) {
- CreateNode("d:protectedRanges");
- }
-
- var newNode = CreateNode("d:protectedRanges/d:protectedRange");
- var item = new ExcelProtectedRange(name, address, NameSpaceManager, newNode);
- _baseList.Add(item);
- return item;
- }
-
- public void Clear() {
- DeleteNode("d:protectedRanges");
- _baseList.Clear();
- }
-
- public bool Contains(ExcelProtectedRange item) {
- return _baseList.Contains(item);
- }
-
- public void CopyTo(ExcelProtectedRange[] array, int arrayIndex) {
- _baseList.CopyTo(array, arrayIndex);
- }
-
- public int Count => _baseList.Count;
-
- public bool Remove(ExcelProtectedRange item) {
- DeleteAllNode(
- "d:protectedRanges/d:protectedRange[@name='"
- + item.Name
- + "' and @sqref='"
- + item.Address.Address
- + "']");
- if (_baseList.Count == 0) {
- DeleteNode("d:protectedRanges");
- }
- return _baseList.Remove(item);
- }
-
- public int IndexOf(ExcelProtectedRange item) {
- return _baseList.IndexOf(item);
- }
-
- public void RemoveAt(int index) {
- _baseList.RemoveAt(index);
- }
-
public ExcelProtectedRange this[int index] => _baseList[index];
IEnumerator<ExcelProtectedRange> IEnumerable<ExcelProtectedRange>.GetEnumerator() {
diff --git a/EPPlus/ExcelProtection.cs b/EPPlus/ExcelProtection.cs
index bf10612..5d0c943 100644
--- a/EPPlus/ExcelProtection.cs
+++ b/EPPlus/ExcelProtection.cs
@@ -30,6 +30,7 @@
* Jan Källman License changed GPL-->LGPL 2011-12-27
*******************************************************************************/
+using System.Collections.Immutable;
using System.Xml;
namespace OfficeOpenXml;
@@ -40,10 +41,11 @@
///<seealso cref="ExcelSheetProtection"/>
/// </summary>
public class ExcelProtection : XmlHelper {
- internal ExcelProtection(XmlNamespaceManager ns, XmlNode topNode, ExcelWorkbook wb)
- : base(ns, topNode) {
- SchemaNodeOrder = wb.SchemaNodeOrder;
- }
+ protected override ImmutableArray<string> SchemaNodeOrder =>
+ ExcelWorkbook.WorkbookSchemaNodeOrder;
+
+ internal ExcelProtection(XmlNamespaceManager ns, XmlNode topNode)
+ : base(ns, topNode) {}
private const string _lockStructurePath = "d:workbookProtection/@lockStructure";
diff --git a/EPPlus/ExcelRangeBase.cs b/EPPlus/ExcelRangeBase.cs
index 686eb78..9c82531 100644
--- a/EPPlus/ExcelRangeBase.cs
+++ b/EPPlus/ExcelRangeBase.cs
@@ -34,23 +34,15 @@
using System;
using System.Collections;
using System.Collections.Generic;
-using System.ComponentModel;
-using System.Data;
using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Reflection;
using System.Security;
using System.Text;
-using System.Text.RegularExpressions;
-using System.Threading;
using System.Xml;
using OfficeOpenXml.ConditionalFormatting;
using OfficeOpenXml.DataValidation;
using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
using OfficeOpenXml.Style;
using OfficeOpenXml.Style.XmlAccess;
-using OfficeOpenXml.Table;
namespace OfficeOpenXml;
@@ -1310,460 +1302,6 @@
public IRangeDataValidation DataValidation => new RangeDataValidation(_worksheet, Address);
/// <summary>
- /// Load the data from the datareader starting from the top left cell of the range
- /// </summary>
- /// <param name="reader">The datareader to loadfrom</param>
- /// <param name="printHeaders">Print the column caption property (if set) or the columnname property if not, on first row</param>
- /// <param name="tableName">The name of the table</param>
- /// <param name="tableStyle">The table style to apply to the data</param>
- /// <returns>The filled range</returns>
- public ExcelRangeBase LoadFromDataReader(
- IDataReader reader,
- bool printHeaders,
- string tableName,
- TableStyles tableStyle = TableStyles.None) {
- var r = LoadFromDataReader(reader, printHeaders);
-
- int rows = r.Rows - 1;
- if (rows >= 0 && r.Columns > 0) {
- var tbl = _worksheet.Tables.Add(
- new(_fromRow, _fromCol, _fromRow + (rows <= 0 ? 1 : rows), _fromCol + r.Columns - 1),
- tableName);
- tbl.ShowHeader = printHeaders;
- tbl.TableStyle = tableStyle;
- }
- return r;
- }
-
- /// <summary>
- /// Load the data from the datareader starting from the top left cell of the range
- /// </summary>
- /// <param name="reader">The datareader to load from</param>
- /// <param name="printHeaders">Print the caption property (if set) or the columnname property if not, on first row</param>
- /// <returns>The filled range</returns>
- public ExcelRangeBase LoadFromDataReader(IDataReader reader, bool printHeaders) {
- if (reader == null) {
- throw (new ArgumentNullException("reader", "Reader can't be null"));
- }
- int fieldCount = reader.FieldCount;
-
- int col = _fromCol,
- row = _fromRow;
- if (printHeaders) {
- for (int i = 0; i < fieldCount; i++) {
- // If no caption is set, the ColumnName property is called implicitly.
- _worksheet._values.SetValue(row, col++, reader.GetName(i));
- }
- row++;
- col = _fromCol;
- }
- while (reader.Read()) {
- for (int i = 0; i < fieldCount; i++) {
- _worksheet._values.SetValue(row, col++, reader.GetValue(i));
- }
- row++;
- col = _fromCol;
- }
- return _worksheet.Cells[_fromRow, _fromCol, row - 1, _fromCol + fieldCount - 1];
- }
-
- /// <summary>
- /// Load the data from the datatable starting from the top left cell of the range
- /// </summary>
- /// <param name="table">The datatable to load</param>
- /// <param name="printHeaders">Print the column caption property (if set) or the columnname property if not, on first row</param>
- /// <param name="tableStyle">The table style to apply to the data</param>
- /// <returns>The filled range</returns>
- public ExcelRangeBase LoadFromDataTable(
- DataTable table,
- bool printHeaders,
- TableStyles tableStyle) {
- var r = LoadFromDataTable(table, printHeaders);
-
- int rows = (table.Rows.Count == 0 ? 1 : table.Rows.Count) + (printHeaders ? 1 : 0);
- if (rows >= 0 && table.Columns.Count > 0) {
- var tbl = _worksheet.Tables.Add(
- new(_fromRow, _fromCol, _fromRow + rows - 1, _fromCol + table.Columns.Count - 1),
- table.TableName);
- tbl.ShowHeader = printHeaders;
- tbl.TableStyle = tableStyle;
- }
- return r;
- }
-
- /// <summary>
- /// Load the data from the datatable starting from the top left cell of the range
- /// </summary>
- /// <param name="table">The datatable to load</param>
- /// <param name="printHeaders">Print the caption property (if set) or the columnname property if not, on first row</param>
- /// <returns>The filled range</returns>
- public ExcelRangeBase LoadFromDataTable(DataTable table, bool printHeaders) {
- if (table == null) {
- throw (new ArgumentNullException("Table can't be null"));
- }
-
- int col = _fromCol,
- row = _fromRow;
- if (printHeaders) {
- foreach (DataColumn dc in table.Columns) {
- // If no caption is set, the ColumnName property is called implicitly.
- _worksheet._values.SetValue(row, col++, dc.Caption);
- }
- row++;
- col = _fromCol;
- } else if (table.Rows.Count == 0) {
- return null;
- }
- foreach (DataRow dr in table.Rows) {
- foreach (object value in dr.ItemArray) {
- if (value != null && value != DBNull.Value && !string.IsNullOrEmpty(value.ToString())) {
- _worksheet._values.SetValue(row, col++, value);
- } else {
- col++;
- }
- }
- row++;
- col = _fromCol;
- }
- return _worksheet.Cells[_fromRow,
- _fromCol,
- (row == _fromRow ? _fromRow : row - 1),
- _fromCol + table.Columns.Count - 1];
- }
-
- /// <summary>
- /// Loads data from the collection of arrays of objects into the range, starting from
- /// the top-left cell.
- /// </summary>
- /// <param name="data">The data.</param>
- public ExcelRangeBase LoadFromArrays(IEnumerable<object[]> data) {
- //thanx to Abdullin for the code contribution
- if (data == null) {
- throw new ArgumentNullException("data");
- }
-
- int column = _fromCol,
- row = _fromRow;
-
- foreach (var rowData in data) {
- column = _fromCol;
- foreach (var cellData in rowData) {
- _worksheet._values.SetValue(row, column, cellData);
- column += 1;
- }
- row += 1;
- }
- return _worksheet.Cells[_fromRow, _fromCol, row - 1, column - 1];
- }
-
- /// <summary>
- /// Load a collection into a the worksheet starting from the top left row of the range.
- /// </summary>
- /// <typeparam name="T">The datatype in the collection</typeparam>
- /// <param name="collection">The collection to load</param>
- /// <returns>The filled range</returns>
- public ExcelRangeBase LoadFromCollection<T>(IEnumerable<T> collection) {
- return LoadFromCollection(
- collection,
- false,
- TableStyles.None,
- BindingFlags.Public | BindingFlags.Instance,
- null);
- }
-
- /// <summary>
- /// Load a collection of T into the worksheet starting from the top left row of the range.
- /// Default option will load all public instance properties of T
- /// </summary>
- /// <typeparam name="T">The datatype in the collection</typeparam>
- /// <param name="collection">The collection to load</param>
- /// <param name="printHeaders">Print the property names on the first row. If the property is decorated with a <see cref="DisplayNameAttribute"/> or a <see cref="DescriptionAttribute"/> that attribute will be used instead of the reflected member name.</param>
- /// <returns>The filled range</returns>
- public ExcelRangeBase LoadFromCollection<T>(IEnumerable<T> collection, bool printHeaders) {
- return LoadFromCollection(
- collection,
- printHeaders,
- TableStyles.None,
- BindingFlags.Public | BindingFlags.Instance,
- null);
- }
-
- /// <summary>
- /// Load a collection of T into the worksheet starting from the top left row of the range.
- /// Default option will load all public instance properties of T
- /// </summary>
- /// <typeparam name="T">The datatype in the collection</typeparam>
- /// <param name="collection">The collection to load</param>
- /// <param name="printHeaders">Print the property names on the first row. If the property is decorated with a <see cref="DisplayNameAttribute"/> or a <see cref="DescriptionAttribute"/> that attribute will be used instead of the reflected member name.</param>
- /// <param name="tableStyle">Will create a table with this style. If set to TableStyles.None no table will be created</param>
- /// <returns>The filled range</returns>
- public ExcelRangeBase LoadFromCollection<T>(
- IEnumerable<T> collection,
- bool printHeaders,
- TableStyles tableStyle) {
- return LoadFromCollection(
- collection,
- printHeaders,
- tableStyle,
- BindingFlags.Public | BindingFlags.Instance,
- null);
- }
-
- /// <summary>
- /// Load a collection into the worksheet starting from the top left row of the range.
- /// </summary>
- /// <typeparam name="T">The datatype in the collection</typeparam>
- /// <param name="collection">The collection to load</param>
- /// <param name="printHeaders">Print the property names on the first row. Any underscore in the property name will be converted to a space. If the property is decorated with a <see cref="DisplayNameAttribute"/> or a <see cref="DescriptionAttribute"/> that attribute will be used instead of the reflected member name.</param>
- /// <param name="tableStyle">Will create a table with this style. If set to TableStyles.None no table will be created</param>
- /// <param name="memberFlags">Property flags to use</param>
- /// <param name="members">The properties to output. Must be of type T</param>
- /// <returns>The filled range</returns>
- public ExcelRangeBase LoadFromCollection<T>(
- IEnumerable<T> collection,
- bool printHeaders,
- TableStyles tableStyle,
- BindingFlags memberFlags,
- MemberInfo[] members) {
- var type = typeof(T);
- if (members == null) {
- members = type.GetProperties(memberFlags);
- } else {
- foreach (var t in members) {
- if (t.DeclaringType != null
- && t.DeclaringType != type
- && !t.DeclaringType.IsSubclassOf(type)) {
- throw new InvalidCastException(
- "Supplied properties in parameter Properties must be of the same type as T (or an assignable type from T");
- }
- }
- }
-
- int col = _fromCol,
- row = _fromRow;
- if (members.Length > 0 && printHeaders) {
- foreach (var t in members) {
- var descriptionAttribute =
- t.GetCustomAttributes(typeof(DescriptionAttribute), false).FirstOrDefault()
- as DescriptionAttribute;
- var header = string.Empty;
- if (descriptionAttribute != null) {
- header = descriptionAttribute.Description;
- } else {
- var displayNameAttribute =
- t.GetCustomAttributes(typeof(DisplayNameAttribute), false).FirstOrDefault()
- as DisplayNameAttribute;
- if (displayNameAttribute != null) {
- header = displayNameAttribute.DisplayName;
- } else {
- header = t.Name.Replace('_', ' ');
- }
- }
- _worksheet._values.SetValue(row, col++, header);
- }
- row++;
- }
-
- if (!collection.Any() && (members.Length == 0 || printHeaders == false)) {
- return null;
- }
-
- if (members.Length == 0) {
- foreach (var item in collection) {
- _worksheet.Cells[row++, col].Value = item;
- }
- } else {
- foreach (var item in collection) {
- col = _fromCol;
- if (item is string || item is decimal || item is DateTime || item.GetType().IsPrimitive) {
- _worksheet.Cells[row, col++].Value = item;
- } else {
- foreach (var t in members) {
- if (t is PropertyInfo info) {
- _worksheet.Cells[row, col++].Value = info.GetValue(item, null);
- } else if (t is FieldInfo fieldInfo) {
- _worksheet.Cells[row, col++].Value = fieldInfo.GetValue(item);
- } else if (t is MethodInfo methodInfo) {
- _worksheet.Cells[row, col++].Value = methodInfo.Invoke(item, null);
- }
- }
- }
- row++;
- }
- }
-
- if (_fromRow == row - 1 && printHeaders) {
- row++;
- }
-
- var r = _worksheet.Cells[_fromRow, _fromCol, row - 1, members.Length == 0 ? col : col - 1];
-
- if (tableStyle != TableStyles.None) {
- var tbl = _worksheet.Tables.Add(r, "");
- tbl.ShowHeader = printHeaders;
- tbl.TableStyle = tableStyle;
- }
- return r;
- }
-
- /// <summary>
- /// Loads a CSV text into a range starting from the top left cell.
- /// Default settings is Comma separation
- /// </summary>
- /// <param name="text">The Text</param>
- /// <returns>The range containing the data</returns>
- public ExcelRangeBase LoadFromText(string text) {
- return LoadFromText(text, new());
- }
-
- /// <summary>
- /// Loads a CSV text into a range starting from the top left cell.
- /// </summary>
- /// <param name="text">The Text</param>
- /// <param name="format">Information how to load the text</param>
- /// <returns>The range containing the data</returns>
- public ExcelRangeBase LoadFromText(string text, ExcelTextFormat format) {
- if (string.IsNullOrEmpty(text)) {
- var r = _worksheet.Cells[_fromRow, _fromCol];
- r.Value = "";
- return r;
- }
-
- if (format == null) {
- format = new();
- }
-
- string splitRegex = String.Format(
- "{0}(?=(?:[^{1}]*{1}[^{1}]*{1})*[^{1}]*$)",
- format.EOL,
- format.TextQualifier);
- string[] lines = Regex.Split(text, splitRegex);
- int row = _fromRow;
- int col = _fromCol;
- int maxCol = col;
- int lineNo = 1;
- foreach (string line in lines) {
- if (lineNo > format.SkipLinesBeginning && lineNo <= lines.Length - format.SkipLinesEnd) {
- col = _fromCol;
- string v = "";
- bool isText = false,
- isQualifier = false;
- int qCount = 0;
- int lineQCount = 0;
- foreach (char c in line) {
- if (format.TextQualifier != 0 && c == format.TextQualifier) {
- if (!isText && v != "") {
- throw (new(string.Format("Invalid Text Qualifier in line : {0}", line)));
- }
- isQualifier = !isQualifier;
- qCount += 1;
- lineQCount++;
- isText = true;
- } else {
- if (qCount > 1 && !string.IsNullOrEmpty(v)) {
- v += new string(format.TextQualifier, qCount / 2);
- } else if (qCount > 2 && string.IsNullOrEmpty(v)) {
- v += new string(format.TextQualifier, (qCount - 1) / 2);
- }
-
- if (isQualifier) {
- v += c;
- } else {
- if (c == format.Delimiter) {
- _worksheet.SetValue(row, col, ConvertData(format, v, col - _fromCol, isText));
- v = "";
- isText = false;
- col++;
- } else {
- if (qCount % 2 == 1) {
- throw (new(string.Format("Text delimiter is not closed in line : {0}", line)));
- }
- v += c;
- }
- }
- qCount = 0;
- }
- }
- if (qCount > 1) {
- v += new string(format.TextQualifier, qCount / 2);
- }
- if (lineQCount % 2 == 1) {
- throw (new(string.Format("Text delimiter is not closed in line : {0}", line)));
- }
-
- _worksheet._values.SetValue(row, col, ConvertData(format, v, col - _fromCol, isText));
- if (col > maxCol) {
- maxCol = col;
- }
- row++;
- }
- lineNo++;
- }
- return _worksheet.Cells[_fromRow, _fromCol, row - 1, maxCol];
- }
-
- /// <summary>
- /// Loads a CSV text into a range starting from the top left cell.
- /// </summary>
- /// <param name="text">The Text</param>
- /// <param name="format">Information how to load the text</param>
- /// <param name="tableStyle">Create a table with this style</param>
- /// <param name="firstRowIsHeader">Use the first row as header</param>
- /// <returns></returns>
- public ExcelRangeBase LoadFromText(
- string text,
- ExcelTextFormat format,
- TableStyles tableStyle,
- bool firstRowIsHeader) {
- var r = LoadFromText(text, format);
-
- var tbl = _worksheet.Tables.Add(r, "");
- tbl.ShowHeader = firstRowIsHeader;
- tbl.TableStyle = tableStyle;
-
- return r;
- }
-
- /// <summary>
- /// Loads a CSV file into a range starting from the top left cell.
- /// </summary>
- /// <param name="textFile">The Textfile</param>
- /// <returns></returns>
- public ExcelRangeBase LoadFromText(FileInfo textFile) {
- return LoadFromText(File.ReadAllText(textFile.FullName, Encoding.ASCII));
- }
-
- /// <summary>
- /// Loads a CSV file into a range starting from the top left cell.
- /// </summary>
- /// <param name="textFile">The Textfile</param>
- /// <param name="format">Information how to load the text</param>
- /// <returns></returns>
- public ExcelRangeBase LoadFromText(FileInfo textFile, ExcelTextFormat format) {
- return LoadFromText(File.ReadAllText(textFile.FullName, format.Encoding), format);
- }
-
- /// <summary>
- /// Loads a CSV file into a range starting from the top left cell.
- /// </summary>
- /// <param name="textFile">The Textfile</param>
- /// <param name="format">Information how to load the text</param>
- /// <param name="tableStyle">Create a table with this style</param>
- /// <param name="firstRowIsHeader">Use the first row as header</param>
- /// <returns></returns>
- public ExcelRangeBase LoadFromText(
- FileInfo textFile,
- ExcelTextFormat format,
- TableStyles tableStyle,
- bool firstRowIsHeader) {
- return LoadFromText(
- File.ReadAllText(textFile.FullName, format.Encoding),
- format,
- tableStyle,
- firstRowIsHeader);
- }
-
- /// <summary>
/// Get the strongly typed value of the cell.
/// </summary>
/// <typeparam name="T">The type</typeparam>
diff --git a/EPPlus/ExcelRow.cs b/EPPlus/ExcelRow.cs
index bb94e2b..f4336c7 100644
--- a/EPPlus/ExcelRow.cs
+++ b/EPPlus/ExcelRow.cs
@@ -44,20 +44,6 @@
internal bool PageBreak;
internal bool Phonetic;
internal bool CustomHeight;
- internal int MergeID;
-
- internal RowInternal Clone() {
- return new() {
- Height = Height,
- Hidden = Hidden,
- Collapsed = Collapsed,
- OutlineLevel = OutlineLevel,
- PageBreak = PageBreak,
- Phonetic = Phonetic,
- CustomHeight = CustomHeight,
- MergeID = MergeID,
- };
- }
}
/// <summary>
@@ -269,20 +255,4 @@
get => RowID;
set => Row = ((int)(value >> 29));
}
-
- /// <summary>
- /// Copies the current row to a new worksheet
- /// </summary>
- /// <param name="added">The worksheet where the copy will be created</param>
- internal void Clone(ExcelWorksheet added) {
- ExcelRow newRow = added.Row(Row);
- newRow.Collapsed = Collapsed;
- newRow.Height = Height;
- newRow.Hidden = Hidden;
- newRow.OutlineLevel = OutlineLevel;
- newRow.PageBreak = PageBreak;
- newRow.Phonetic = Phonetic;
- newRow._styleName = _styleName;
- newRow.StyleID = StyleID;
- }
}
diff --git a/EPPlus/ExcelSheetProtection.cs b/EPPlus/ExcelSheetProtection.cs
index bc7996d..0b2cb09 100644
--- a/EPPlus/ExcelSheetProtection.cs
+++ b/EPPlus/ExcelSheetProtection.cs
@@ -30,6 +30,7 @@
* Jan Källman License changed GPL-->LGPL 2011-12-27
*******************************************************************************/
+using System.Collections.Immutable;
using System.Xml;
namespace OfficeOpenXml;
@@ -40,10 +41,11 @@
///<seealso cref="ExcelProtection"/>
/// </summary>
public sealed class ExcelSheetProtection : XmlHelper {
- internal ExcelSheetProtection(XmlNamespaceManager nsm, XmlNode topNode, ExcelWorksheet ws)
- : base(nsm, topNode) {
- SchemaNodeOrder = ws.SchemaNodeOrder;
- }
+ protected override ImmutableArray<string> SchemaNodeOrder =>
+ ExcelWorksheet.WorksheetSchemaNodeOrder;
+
+ internal ExcelSheetProtection(XmlNamespaceManager nsm, XmlNode topNode)
+ : base(nsm, topNode) {}
private const string _isProtectedPath = "d:sheetProtection/@sheet";
diff --git a/EPPlus/ExcelStyles.cs b/EPPlus/ExcelStyles.cs
index 9f1b283..6bb75ff 100644
--- a/EPPlus/ExcelStyles.cs
+++ b/EPPlus/ExcelStyles.cs
@@ -32,6 +32,7 @@
using System;
using System.Collections.Generic;
+using System.Collections.Immutable;
using System.Linq;
using System.Xml;
using OfficeOpenXml.ConditionalFormatting;
@@ -60,21 +61,22 @@
private readonly XmlNamespaceManager _nameSpaceManager;
internal int _nextDfxNumFmtID = 164;
+ protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
+ "numFmts",
+ "fonts",
+ "fills",
+ "borders",
+ "cellStyleXfs",
+ "cellXfs",
+ "cellStyles",
+ "dxfs",
+ ];
+
internal ExcelStyles(XmlNamespaceManager nameSpaceManager, XmlDocument xml, ExcelWorkbook wb)
: base(nameSpaceManager, xml) {
_styleXml = xml;
_wb = wb;
_nameSpaceManager = nameSpaceManager;
- SchemaNodeOrder = new[] {
- "numFmts",
- "fonts",
- "fills",
- "borders",
- "cellStyleXfs",
- "cellXfs",
- "cellStyles",
- "dxfs",
- };
LoadFromDocument();
}
@@ -177,13 +179,11 @@
var ws = _wb.Worksheets[e.PositionID];
Dictionary<int, int> styleCashe = new Dictionary<int, int>();
//Set single address
- lock (ws._styles) {
- SetStyleAddress(sender, e, address, ws, ref styleCashe);
- if (address.Addresses != null) {
- //Handle multiaddresses
- foreach (var innerAddress in address.Addresses) {
- SetStyleAddress(sender, e, innerAddress, ws, ref styleCashe);
- }
+ SetStyleAddress(sender, e, address, ws, ref styleCashe);
+ if (address.Addresses != null) {
+ //Handle multiaddresses
+ foreach (var innerAddress in address.Addresses) {
+ SetStyleAddress(sender, e, innerAddress, ws, ref styleCashe);
}
}
return 0;
@@ -769,113 +769,106 @@
}
internal int CloneStyle(ExcelStyles style, int styleId, bool isNamedStyle, bool allwaysAdd) {
- ExcelXfs xfs;
- lock (style) {
- if (isNamedStyle) {
- xfs = style.CellStyleXfs[styleId];
- } else {
- xfs = style.CellXfs[styleId];
- }
- ExcelXfs newXfs = xfs.Copy(this);
- //Numberformat
- if (xfs.NumberFormatId > 0) {
- //rake36: Two problems here...
- //rake36: 1. the first time through when format stays equal to String.Empty, it adds a string.empty to the list of Number Formats
- //rake36: 2. when adding a second sheet, if the numberformatid == 164, it finds the 164 added by previous sheets but was using the array index
- //rake36: for the numberformatid
+ var xfs = isNamedStyle ? style.CellStyleXfs[styleId] : style.CellXfs[styleId];
+ ExcelXfs newXfs = xfs.Copy(this);
+ //Numberformat
+ if (xfs.NumberFormatId > 0) {
+ //rake36: Two problems here...
+ //rake36: 1. the first time through when format stays equal to String.Empty, it adds a string.empty to the list of Number Formats
+ //rake36: 2. when adding a second sheet, if the numberformatid == 164, it finds the 164 added by previous sheets but was using the array index
+ //rake36: for the numberformatid
- string format = string.Empty;
- foreach (var fmt in style.NumberFormats) {
- if (fmt.NumFmtId == xfs.NumberFormatId) {
- format = fmt.Format;
- break;
- }
- }
- //rake36: Don't add another format if it's blank
- if (!String.IsNullOrEmpty(format)) {
- int ix = NumberFormats.FindIndexById(format);
- if (ix < 0) {
- var item = new ExcelNumberFormatXml(NameSpaceManager) {
- Format = format,
- NumFmtId = NumberFormats.NextId++,
- };
- NumberFormats.Add(format, item);
- //rake36: Use the just added format id
- newXfs.NumberFormatId = item.NumFmtId;
- } else {
- //rake36: Use the format id defined by the index... not the index itself
- newXfs.NumberFormatId = NumberFormats[ix].NumFmtId;
- }
+ string format = string.Empty;
+ foreach (var fmt in style.NumberFormats) {
+ if (fmt.NumFmtId == xfs.NumberFormatId) {
+ format = fmt.Format;
+ break;
}
}
-
- //Font
- if (xfs.FontId > -1) {
- int ix = Fonts.FindIndexById(xfs.Font.Id);
+ //rake36: Don't add another format if it's blank
+ if (!String.IsNullOrEmpty(format)) {
+ int ix = NumberFormats.FindIndexById(format);
if (ix < 0) {
- ExcelFontXml item = style.Fonts[xfs.FontId].Copy();
- ix = Fonts.Add(xfs.Font.Id, item);
- }
- newXfs.FontId = ix;
- }
-
- //Border
- if (xfs.BorderId > -1) {
- int ix = Borders.FindIndexById(xfs.Border.Id);
- if (ix < 0) {
- ExcelBorderXml item = style.Borders[xfs.BorderId].Copy();
- ix = Borders.Add(xfs.Border.Id, item);
- }
- newXfs.BorderId = ix;
- }
-
- //Fill
- if (xfs.FillId > -1) {
- int ix = Fills.FindIndexById(xfs.Fill.Id);
- if (ix < 0) {
- var item = style.Fills[xfs.FillId].Copy();
- ix = Fills.Add(xfs.Fill.Id, item);
- }
- newXfs.FillId = ix;
- }
-
- //Named style reference
- if (xfs.XfId > 0) {
- var id = style.CellStyleXfs[xfs.XfId].Id;
- var newId = CellStyleXfs.FindIndexById(id);
- if (newId >= 0) {
- newXfs.XfId = newId;
- } else if (style._wb != _wb
- && allwaysAdd
- == false) //Not the same workbook, copy the namedstyle to the workbook or match the id
- {
- var nsFind = style.NamedStyles.ToDictionary(d => (d.StyleXfId));
- if (nsFind.ContainsKey(xfs.XfId)) {
- var st = nsFind[xfs.XfId];
- if (NamedStyles.ExistsKey(st.Name)) {
- newXfs.XfId = NamedStyles.FindIndexById(st.Name);
- } else {
- var ns = CreateNamedStyle(st.Name, st.Style);
- newXfs.XfId = NamedStyles.Count - 1;
- }
- }
- }
- }
-
- int index;
- if (isNamedStyle) {
- index = CellStyleXfs.Add(newXfs.Id, newXfs);
- } else {
- if (allwaysAdd) {
- index = CellXfs.Add(newXfs.Id, newXfs);
+ var item = new ExcelNumberFormatXml(NameSpaceManager) {
+ Format = format,
+ NumFmtId = NumberFormats.NextId++,
+ };
+ NumberFormats.Add(format, item);
+ //rake36: Use the just added format id
+ newXfs.NumberFormatId = item.NumFmtId;
} else {
- index = CellXfs.FindIndexById(newXfs.Id);
- if (index < 0) {
- index = CellXfs.Add(newXfs.Id, newXfs);
+ //rake36: Use the format id defined by the index... not the index itself
+ newXfs.NumberFormatId = NumberFormats[ix].NumFmtId;
+ }
+ }
+ }
+
+ //Font
+ if (xfs.FontId > -1) {
+ int ix = Fonts.FindIndexById(xfs.Font.Id);
+ if (ix < 0) {
+ ExcelFontXml item = style.Fonts[xfs.FontId].Copy();
+ ix = Fonts.Add(xfs.Font.Id, item);
+ }
+ newXfs.FontId = ix;
+ }
+
+ //Border
+ if (xfs.BorderId > -1) {
+ int ix = Borders.FindIndexById(xfs.Border.Id);
+ if (ix < 0) {
+ ExcelBorderXml item = style.Borders[xfs.BorderId].Copy();
+ ix = Borders.Add(xfs.Border.Id, item);
+ }
+ newXfs.BorderId = ix;
+ }
+
+ //Fill
+ if (xfs.FillId > -1) {
+ int ix = Fills.FindIndexById(xfs.Fill.Id);
+ if (ix < 0) {
+ var item = style.Fills[xfs.FillId].Copy();
+ ix = Fills.Add(xfs.Fill.Id, item);
+ }
+ newXfs.FillId = ix;
+ }
+
+ //Named style reference
+ if (xfs.XfId > 0) {
+ var id = style.CellStyleXfs[xfs.XfId].Id;
+ var newId = CellStyleXfs.FindIndexById(id);
+ if (newId >= 0) {
+ newXfs.XfId = newId;
+ } else if (style._wb != _wb
+ && allwaysAdd
+ == false) //Not the same workbook, copy the namedstyle to the workbook or match the id
+ {
+ var nsFind = style.NamedStyles.ToDictionary(d => (d.StyleXfId));
+ if (nsFind.ContainsKey(xfs.XfId)) {
+ var st = nsFind[xfs.XfId];
+ if (NamedStyles.ExistsKey(st.Name)) {
+ newXfs.XfId = NamedStyles.FindIndexById(st.Name);
+ } else {
+ var ns = CreateNamedStyle(st.Name, st.Style);
+ newXfs.XfId = NamedStyles.Count - 1;
}
}
}
- return index;
}
+
+ int index;
+ if (isNamedStyle) {
+ index = CellStyleXfs.Add(newXfs.Id, newXfs);
+ } else {
+ if (allwaysAdd) {
+ index = CellXfs.Add(newXfs.Id, newXfs);
+ } else {
+ index = CellXfs.FindIndexById(newXfs.Id);
+ if (index < 0) {
+ index = CellXfs.Add(newXfs.Id, newXfs);
+ }
+ }
+ }
+ return index;
}
}
diff --git a/EPPlus/ExcelTextFormat.cs b/EPPlus/ExcelTextFormat.cs
index 83b0c59..8029447 100644
--- a/EPPlus/ExcelTextFormat.cs
+++ b/EPPlus/ExcelTextFormat.cs
@@ -86,54 +86,45 @@
/// <item><term>Encoding</term><description>Encoding.ASCII</description></item>
/// </list>
/// </summary>
- public ExcelTextFormat() {
- Delimiter = ',';
- TextQualifier = '\0';
- EOL = "\r\n";
- Culture = CultureInfo.InvariantCulture;
- DataTypes = null;
- SkipLinesBeginning = 0;
- SkipLinesEnd = 0;
- Encoding = Encoding.ASCII;
- }
+ public ExcelTextFormat() {}
/// <summary>
/// Delimiter character
/// </summary>
- public char Delimiter { get; set; }
+ public char Delimiter { get; set; } = ',';
/// <summary>
/// Text qualifier character
/// </summary>
- public char TextQualifier { get; set; }
+ public char TextQualifier { get; set; } = '\0';
/// <summary>
/// End of line characters. Default CRLF
/// </summary>
- public string EOL { get; set; }
+ public string EOL { get; set; } = "\r\n";
/// <summary>
/// Datatypes list for each column (if column is not present Unknown is assumed)
/// </summary>
- public eDataTypes[] DataTypes { get; set; }
+ public eDataTypes[] DataTypes { get; set; } = null;
/// <summary>
/// Culture used when parsing. Default CultureInfo.InvariantCulture
/// </summary>
- public CultureInfo Culture { get; set; }
+ public CultureInfo Culture { get; set; } = CultureInfo.InvariantCulture;
/// <summary>
/// Number of lines skiped in the begining of the file. Default 0.
/// </summary>
- public int SkipLinesBeginning { get; set; }
+ public int SkipLinesBeginning { get; set; } = 0;
/// <summary>
/// Number of lines skiped at the end of the file. Default 0.
/// </summary>
- public int SkipLinesEnd { get; set; }
+ public int SkipLinesEnd { get; set; } = 0;
/// <summary>
/// Only used when reading files from disk using a FileInfo object. Default AscII
/// </summary>
- public Encoding Encoding { get; set; }
+ public Encoding Encoding { get; set; } = Encoding.ASCII;
}
diff --git a/EPPlus/ExcelWorkbook.cs b/EPPlus/ExcelWorkbook.cs
index 3331644..c581319 100644
--- a/EPPlus/ExcelWorkbook.cs
+++ b/EPPlus/ExcelWorkbook.cs
@@ -33,6 +33,7 @@
using System;
using System.Collections.Generic;
+using System.Collections.Immutable;
using System.Globalization;
using System.IO;
using System.Text;
@@ -77,57 +78,105 @@
internal bool isRichText;
}
- internal ExcelPackage _package;
+ private readonly ExcelPackage _package;
private ExcelWorksheets _worksheets;
private OfficeProperties _properties;
private ExcelStyles _styles;
- /// <summary>
- /// Creates a new instance of the ExcelWorkbook class.
- /// </summary>
- /// <param name="package">The parent package</param>
- /// <param name="namespaceManager">NamespaceManager</param>
+ internal static ImmutableArray<string> WorkbookSchemaNodeOrder = [
+ "fileVersion",
+ "fileSharing",
+ "workbookPr",
+ "workbookProtection",
+ "bookViews",
+ "sheets",
+ "functionGroups",
+ "functionPrototypes",
+ "externalReferences",
+ "definedNames",
+ "calcPr",
+ "oleSize",
+ "customWorkbookViews",
+ "pivotCaches",
+ "smartTagPr",
+ "smartTagTypes",
+ "webPublishing",
+ "fileRecoveryPr",
+ ];
+
+ protected override ImmutableArray<string> SchemaNodeOrder => WorkbookSchemaNodeOrder;
+
internal ExcelWorkbook(ExcelPackage package, XmlNamespaceManager namespaceManager)
: base(namespaceManager) {
_package = package;
-
_names = new(this);
_namespaceManager = namespaceManager;
+
+ WorkbookXml = package.GetOrCreateXmlDocument(
+ WorkbookUri,
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml",
+ ExcelPackage._schemaRelationships + "/officeDocument",
+ () => CreateEmptyWorkbookXml(namespaceManager));
+ _stylesXml = package.GetOrCreateXmlDocument(
+ StylesUri,
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
+ ExcelPackage._schemaRelationships + "/styles",
+ CreateEmptyStylesXml);
+
TopNode = WorkbookXml.DocumentElement;
- SchemaNodeOrder = new[] {
- "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();
+ GetExternalReferences();
+ GetDefinedNames();
}
- internal Dictionary<string, SharedStringItem> _sharedStrings = new(); //Used when reading cells.
+ private static XmlDocument CreateEmptyWorkbookXml(XmlNamespaceManager namespaceManager) {
+ var result = new XmlDocument(namespaceManager.NameTable);
+ var wbElem = result.CreateElement("workbook", ExcelPackage._schemaMain);
+
+ // Add the relationships namespace
+ wbElem.SetAttribute("xmlns:r", ExcelPackage._schemaRelationships);
+ result.AppendChild(wbElem);
+
+ // Create the bookViews and workbooks element
+ var bookViews = result.CreateElement("bookViews", ExcelPackage._schemaMain);
+ wbElem.AppendChild(bookViews);
+ var workbookView = result.CreateElement("workbookView", ExcelPackage._schemaMain);
+ bookViews.AppendChild(workbookView);
+
+ return result;
+ }
+
+ private static XmlDocument CreateEmptyStylesXml() {
+ 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>");
+
+ var result = new XmlDocument();
+ result.LoadXml(xml.ToString());
+ return result;
+ }
+
+ internal readonly Dictionary<string, SharedStringItem> _sharedStrings = new(); //Used when reading cells.
internal List<SharedStringItem> _sharedStringsList = new(); //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;
- internal FormulaParserManager _parserManager;
+ private readonly XmlNamespaceManager _namespaceManager;
+ private FormulaParser _formulaParser;
+ private FormulaParserManager _parserManager;
internal CellStore<List<Token>> _formulaTokens;
/// <summary>
@@ -135,7 +184,7 @@
/// </summary>
private void GetSharedStrings() {
if (_package.Package.PartExists(SharedStringsUri)) {
- var xml = _package.GetXmlFromUri(SharedStringsUri);
+ var xml = _package.GetXmlDocument(SharedStringsUri);
XmlNodeList nl = xml.SelectNodes("//d:sst/d:si", NameSpaceManager);
_sharedStringsList = new();
if (nl != null) {
@@ -273,7 +322,7 @@
public ExcelWorksheets Worksheets {
get {
if (_worksheets == null) {
- var sheetsNode = _workbookXml.DocumentElement.SelectSingleNode(
+ var sheetsNode = WorkbookXml.DocumentElement.SelectSingleNode(
"d:sheets",
_namespaceManager);
if (sheetsNode == null) {
@@ -314,15 +363,7 @@
/// <summary>
/// Access properties to protect or unprotect a workbook
/// </summary>
- public ExcelProtection Protection {
- get {
- if (_protection == null) {
- _protection = new(NameSpaceManager, TopNode, this);
- _protection.SchemaNodeOrder = SchemaNodeOrder;
- }
- return _protection;
- }
- }
+ public ExcelProtection Protection => _protection ??= new(NameSpaceManager, TopNode);
private ExcelWorkbookView _view;
@@ -346,31 +387,22 @@
/// <summary>
/// URI to the styles inside the package
/// </summary>
- internal static Uri StylesUri { get; } = new("/xl/styles.xml", UriKind.Relative);
+ private static Uri StylesUri { get; } = new("/xl/styles.xml", UriKind.Relative);
/// <summary>
/// URI to the shared strings inside the package
/// </summary>
- internal static Uri SharedStringsUri { get; } = new("/xl/sharedStrings.xml", UriKind.Relative);
+ private static Uri SharedStringsUri { get; } = new("/xl/sharedStrings.xml", UriKind.Relative);
/// <summary>
/// Returns a reference to the workbook's part within the package
/// </summary>
internal ZipPackagePart Part => (_package.Package.GetPart(WorkbookUri));
- 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);
- }
- }
+ internal XmlDocument WorkbookXml { get; }
private const string _codeModuleNamePath = "d:workbookPr/@codeName";
@@ -405,101 +437,7 @@
}
}
- /// <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
- ZipPackagePart partWorkbook = _package.Package.CreatePart(
- WorkbookUri,
- "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml",
- _package.Compression);
-
- // create the workbook
- _workbookXml = new(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);
- }
- }
-
- 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
- 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();
- _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
- Part.CreateRelationship(
- UriHelper.GetRelativeUri(WorkbookUri, StylesUri),
- TargetMode.Internal,
- ExcelPackage._schemaRelationships + "/styles");
- }
- }
- return (_stylesXml);
- }
- set => _stylesXml = value;
- }
+ private readonly XmlDocument _stylesXml;
/// <summary>
/// Package styles collection. Used internally to access style data.
@@ -507,7 +445,7 @@
public ExcelStyles Styles {
get {
if (_styles == null) {
- _styles = new(NameSpaceManager, StylesXml, this);
+ _styles = new(NameSpaceManager, _stylesXml, this);
}
return _styles;
}
@@ -527,14 +465,14 @@
}
}
- private readonly string CALC_MODE_PATH = "d:calcPr/@calcMode";
+ private readonly string _calcModePath = "d:calcPr/@calcMode";
/// <summary>
/// Calculation mode for the workbook.
/// </summary>
public ExcelCalcMode CalcMode {
get {
- string calcMode = GetXmlNodeString(CALC_MODE_PATH);
+ string calcMode = GetXmlNodeString(_calcModePath);
switch (calcMode) {
case "autoNoTable":
return ExcelCalcMode.AutomaticNoTable;
@@ -547,13 +485,13 @@
set {
switch (value) {
case ExcelCalcMode.AutomaticNoTable:
- SetXmlNodeString(CALC_MODE_PATH, "autoNoTable");
+ SetXmlNodeString(_calcModePath, "autoNoTable");
break;
case ExcelCalcMode.Manual:
- SetXmlNodeString(CALC_MODE_PATH, "manual");
+ SetXmlNodeString(_calcModePath, "manual");
break;
default:
- SetXmlNodeString(CALC_MODE_PATH, "auto");
+ SetXmlNodeString(_calcModePath, "auto");
break;
}
}
@@ -570,44 +508,16 @@
set => SetXmlNodeBool(_fullCalcOnLoadPath, value);
}
- /// <summary>
- /// Saves the workbook and all its components to the package.
- /// For internal use only!
- /// </summary>
- internal void Save() // Workbook Save
- {
+ internal void 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(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;
@@ -616,19 +526,16 @@
worksheet.View.WindowProtection = true;
}
worksheet.Save();
- worksheet.Part.SaveHandler = worksheet.SaveHandler;
}
- var part = _package.Package.CreatePart(
+ _package.Package.CreatePart(
SharedStringsUri,
ExcelPackage._contentTypeSharedString,
- _package.Compression);
- part.SaveHandler = SaveSharedStringHandler;
+ SaveSharedStringHandler);
Part.CreateRelationship(
UriHelper.GetRelativeUri(WorkbookUri, SharedStringsUri),
TargetMode.Internal,
ExcelPackage._schemaRelationships + "/sharedStrings");
- //UpdateSharedStringsXml();
// Data validation
ValidateDataValidations();
diff --git a/EPPlus/ExcelWorkbookView.cs b/EPPlus/ExcelWorkbookView.cs
index 6772936..26a2430 100644
--- a/EPPlus/ExcelWorkbookView.cs
+++ b/EPPlus/ExcelWorkbookView.cs
@@ -30,6 +30,7 @@
* Jan Källman License changed GPL-->LGPL 2011-12-27
*******************************************************************************/
+using System.Collections.Immutable;
using System.Globalization;
using System.Xml;
@@ -39,6 +40,9 @@
/// Access to workbook view properties
/// </summary>
public class ExcelWorkbookView : XmlHelper {
+ protected override ImmutableArray<string> SchemaNodeOrder =>
+ ExcelWorkbook.WorkbookSchemaNodeOrder;
+
/// <summary>
/// Creates a new ExcelWorkbookView which provides access to all the
/// view states of the worksheet.
@@ -47,9 +51,7 @@
/// <param name="node"></param>
/// <param name="wb"></param>
internal ExcelWorkbookView(XmlNamespaceManager ns, XmlNode node, ExcelWorkbook wb)
- : base(ns, node) {
- SchemaNodeOrder = wb.SchemaNodeOrder;
- }
+ : base(ns, node) {}
private const string _leftPath = "d:bookViews/d:workbookView/@xWindow";
diff --git a/EPPlus/ExcelWorksheet.cs b/EPPlus/ExcelWorksheet.cs
index 33d2dd8..02fe010 100644
--- a/EPPlus/ExcelWorksheet.cs
+++ b/EPPlus/ExcelWorksheet.cs
@@ -34,6 +34,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
+using System.Collections.Immutable;
using System.ComponentModel;
using System.Globalization;
using System.IO;
@@ -89,13 +90,12 @@
XmlNamespaceManager ns,
ExcelPackage pck,
ExcelWorkbook workbook,
- string relId,
- Uri uriWorksheet,
- string sheetName,
+ Uri worksheetUri,
+ string name,
int sheetId,
int positionId,
eWorkSheetHidden hidden)
- : base(ns, pck, workbook, relId, uriWorksheet, sheetName, sheetId, positionId, hidden) {}
+ : base(ns, pck, workbook, worksheetUri, name, sheetId, positionId, hidden) {}
}
/// <summary>
@@ -190,7 +190,7 @@
public class MergeCellsCollection : IEnumerable<string> {
internal MergeCellsCollection() {}
- internal CellStore<int> _cells = new();
+ internal readonly CellStore<int> _cells = new();
private readonly List<string> _list = new();
internal List<string> List => _list;
@@ -212,17 +212,13 @@
public string this[int index] => _list[index];
internal void Add(ExcelAddressBase address, bool doValidate) {
- int ix = 0;
-
//Validate
if (doValidate && Validate(address) == false) {
throw (new ArgumentException("Can't merge and already merged range"));
}
- lock (this) {
- ix = _list.Count;
- _list.Add(address.Address);
- SetIndex(address, ix);
- }
+ var ix = _list.Count;
+ _list.Add(address.Address);
+ SetIndex(address, ix);
}
private bool Validate(ExcelAddressBase address) {
@@ -329,143 +325,136 @@
}
}
- internal CellStore<object> _values;
- internal CellStore<string> _types;
- internal CellStore<int> _styles;
- internal CellStore<object> _formulas;
- internal FlagCellStore _flags;
+ internal readonly CellStore<object> _values = new();
+ internal readonly CellStore<string> _types = new();
+ internal readonly CellStore<int> _styles = new();
+ internal readonly CellStore<object> _formulas = new();
+ internal readonly FlagCellStore _flags = new();
internal CellStore<List<Token>> _formulaTokens;
- internal CellStore<Uri> _hyperLinks;
- internal CellStore<ExcelComment> _commentsStore;
+ internal readonly CellStore<Uri> _hyperLinks = new();
+ internal readonly CellStore<ExcelComment> _commentsStore = new();
- internal Dictionary<int, Formulas> _sharedFormulas = new();
- internal int _minCol = ExcelPackage.MaxColumns;
- internal int _maxCol = 0;
+ internal readonly Dictionary<int, Formulas> _sharedFormulas = new();
internal readonly ExcelPackage _package;
private readonly ExcelWorkbook _workbook;
- private readonly Uri _worksheetUri;
- private string _name;
- private readonly int _sheetID;
- private int _positionID;
- private readonly string _relationshipID;
- private XmlDocument _worksheetXml;
private ExcelWorksheetView _sheetView;
- private ExcelHeaderFooter _headerFooter;
+
+ internal static ImmutableArray<string> WorksheetSchemaNodeOrder = [
+ "sheetPr",
+ "tabColor",
+ "outlinePr",
+ "pageSetUpPr",
+ "dimension",
+ "sheetViews",
+ "sheetFormatPr",
+ "cols",
+ "sheetData",
+ "sheetProtection",
+ "protectedRanges",
+ "scenarios",
+ "autoFilter",
+ "sortState",
+ "dataConsolidate",
+ "customSheetViews",
+ "customSheetViews",
+ "mergeCells",
+ "phoneticPr",
+ "conditionalFormatting",
+ "dataValidations",
+ "hyperlinks",
+ "printOptions",
+ "pageMargins",
+ "pageSetup",
+ "headerFooter",
+ "linePrint",
+ "rowBreaks",
+ "colBreaks",
+ "customProperties",
+ "cellWatches",
+ "ignoredErrors",
+ "smartTags",
+ "drawing",
+ "legacyDrawing",
+ "legacyDrawingHF",
+ "picture",
+ "oleObjects",
+ "activeXControls",
+ "webPublishItems",
+ "tableParts",
+ "extLst",
+ ];
+
+ protected override ImmutableArray<string> SchemaNodeOrder => WorksheetSchemaNodeOrder;
internal ExcelWorksheet(
XmlNamespaceManager ns,
ExcelPackage excelPackage,
ExcelWorkbook workbook,
- string relId,
- Uri uriWorksheet,
- string sheetName,
+ Uri worksheetUri,
+ string name,
int sheetId,
int positionId,
- eWorkSheetHidden hide)
+ eWorkSheetHidden hidden)
: base(ns, null) {
_workbook = workbook;
- SchemaNodeOrder = new[] {
- "sheetPr",
- "tabColor",
- "outlinePr",
- "pageSetUpPr",
- "dimension",
- "sheetViews",
- "sheetFormatPr",
- "cols",
- "sheetData",
- "sheetProtection",
- "protectedRanges",
- "scenarios",
- "autoFilter",
- "sortState",
- "dataConsolidate",
- "customSheetViews",
- "customSheetViews",
- "mergeCells",
- "phoneticPr",
- "conditionalFormatting",
- "dataValidations",
- "hyperlinks",
- "printOptions",
- "pageMargins",
- "pageSetup",
- "headerFooter",
- "linePrint",
- "rowBreaks",
- "colBreaks",
- "customProperties",
- "cellWatches",
- "ignoredErrors",
- "smartTags",
- "drawing",
- "legacyDrawing",
- "legacyDrawingHF",
- "picture",
- "oleObjects",
- "activeXControls",
- "webPublishItems",
- "tableParts",
- "extLst",
- };
_package = excelPackage;
- _workbook = workbook;
- _relationshipID = relId;
- _worksheetUri = uriWorksheet;
- _name = sheetName;
- _sheetID = sheetId;
- _positionID = positionId;
- Hidden = hide;
-
- /**** Cellstore ****/
- _values = new();
- _types = new();
- _styles = new();
- _formulas = new();
- _flags = new();
- _commentsStore = new();
- _hyperLinks = new();
-
_names = new(Workbook, this);
- CreateXml();
- TopNode = _worksheetXml.DocumentElement;
- }
+ Hidden = hidden;
+ Name = name;
+ PositionID = positionId;
+ SheetID = sheetId;
- /// <summary>
- /// The Uri to the worksheet within the package
- /// </summary>
- internal Uri WorksheetUri => (_worksheetUri);
+ Part = _package.Package.GetPart(worksheetUri);
+ Part.SaveHandler = SaveHandler;
+
+ // First Columns, rows, cells, mergecells, hyperlinks and pagebreakes are loaded from an
+ // XmlTextReader to optimize speed.
+ using var stream = Part.GetStream();
+ var xr = new XmlTextReader(stream);
+ xr.ProhibitDtd = true;
+ xr.WhitespaceHandling = WhitespaceHandling.None;
+ LoadColumns(xr); //columnXml
+ long start = stream.Position;
+ LoadCells(xr);
+ var nextElementLength = GetAttributeLength(xr);
+ long end = stream.Position - nextElementLength;
+ LoadMergeCells(xr);
+ LoadHyperLinks(xr);
+ LoadRowPageBreakes(xr);
+ LoadColPageBreakes(xr);
+
+ // Then the rest of the XML is extracted and loaded into the WorksheetXml document.
+ stream.Seek(0, SeekOrigin.Begin);
+ var xml = GetWorkSheetXml(stream, start, end, out var encoding);
+
+ //first char is invalid sometimes??
+ if (xml[0] != '<') {
+ LoadXmlSafe(WorksheetXml, xml.Substring(1, xml.Length - 1), encoding);
+ } else {
+ LoadXmlSafe(WorksheetXml, xml, encoding);
+ }
+ ClearNodes();
+
+ TopNode = WorksheetXml.DocumentElement;
+ }
/// <summary>
/// The Zip.ZipPackagePart for the worksheet within the package
/// </summary>
- internal ZipPackagePart Part => (_package.Package.GetPart(WorksheetUri));
-
- /// <summary>
- /// The ID for the worksheet's relationship with the workbook in the package
- /// </summary>
- internal string RelationshipID => (_relationshipID);
+ internal ZipPackagePart Part { get; }
/// <summary>
/// The unique identifier for the worksheet.
/// </summary>
- internal int SheetID => (_sheetID);
+ internal int SheetID { get; }
/// <summary>
/// The position of the worksheet.
/// </summary>
- internal int PositionID {
- get => (_positionID);
- set => _positionID = value;
- }
-
- /// <summary>
- /// The index in the worksheets collection
- /// </summary>
- public int Index => (_positionID);
+ internal int PositionID { get; }
/// <summary>
/// Address for autofilter
@@ -513,47 +502,9 @@
/// <summary>
/// The worksheet's display name as it appears on the tab
/// </summary>
- public string Name {
- get => (_name);
- set {
- if (value == _name) {
- return;
- }
- value = _workbook.Worksheets.ValidateFixSheetName(value);
- foreach (var ws in Workbook.Worksheets) {
- if (ws.PositionID != PositionID
- && ws.Name.Equals(value, StringComparison.InvariantCultureIgnoreCase)) {
- throw (new ArgumentException("Worksheet name must be unique"));
- }
- }
- _workbook.SetXmlNodeString(
- string.Format("d:sheets/d:sheet[@sheetId={0}]/@name", _sheetID),
- value);
- ChangeNames(value);
+ public string Name { get; }
- _name = value;
- }
- }
-
- private void ChangeNames(string value) {
- //Renames name in this Worksheet;
- foreach (var n in Workbook.Names) {
- if (string.IsNullOrEmpty(n.NameFormula) && n.NameValue == null) {
- n.ChangeWorksheet(_name, value);
- }
- }
- foreach (var ws in Workbook.Worksheets) {
- if (!(ws is ExcelChartsheet)) {
- foreach (var n in ws.Names) {
- if (string.IsNullOrEmpty(n.NameFormula) && n.NameValue == null) {
- n.ChangeWorksheet(_name, value);
- }
- }
- }
- }
- }
-
- internal ExcelNamedRangeCollection _names;
+ private readonly ExcelNamedRangeCollection _names;
/// <summary>
/// Provides access to named ranges
@@ -571,7 +522,7 @@
public eWorkSheetHidden Hidden {
get {
string state = _workbook.GetXmlNodeString(
- string.Format("d:sheets/d:sheet[@sheetId={0}]/@state", _sheetID));
+ string.Format("d:sheets/d:sheet[@sheetId={0}]/@state", SheetID));
if (state == "hidden") {
return eWorkSheetHidden.Hidden;
}
@@ -582,13 +533,13 @@
}
set {
if (value == eWorkSheetHidden.Visible) {
- _workbook.DeleteNode(string.Format("d:sheets/d:sheet[@sheetId={0}]/@state", _sheetID));
+ _workbook.DeleteNode(string.Format("d:sheets/d:sheet[@sheetId={0}]/@state", SheetID));
} else {
string v;
v = value.ToString();
v = v.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + v.Substring(1);
_workbook.SetXmlNodeString(
- string.Format("d:sheets/d:sheet[@sheetId={0}]/@state", _sheetID),
+ string.Format("d:sheets/d:sheet[@sheetId={0}]/@state", SheetID),
v);
}
}
@@ -704,15 +655,11 @@
set => SetXmlNodeString(_codeModuleNamePath, value);
}
- internal void CodeNameChange(string value) {
- CodeModuleName = value;
- }
-
/// <summary>
/// The XML document holding the worksheet data.
/// All column, row, cell, pagebreak, merged cell and hyperlink-data are loaded into memory and removed from the document when loading the document.
/// </summary>
- public XmlDocument WorksheetXml => (_worksheetXml);
+ internal XmlDocument WorksheetXml { get; } = new();
internal ExcelVmlDrawingCommentCollection _vmlDrawings;
@@ -745,7 +692,7 @@
}
private void CreateVmlCollection() {
- var vmlNode = _worksheetXml.DocumentElement.SelectSingleNode(
+ var vmlNode = WorksheetXml.DocumentElement.SelectSingleNode(
"d:legacyDrawing/@r:id",
NameSpaceManager);
if (vmlNode == null) {
@@ -761,41 +708,6 @@
}
}
- private void CreateXml() {
- _worksheetXml = new();
- _worksheetXml.PreserveWhitespace = ExcelPackage._preserveWhitespace;
- ZipPackagePart packPart = _package.Package.GetPart(WorksheetUri);
- string xml = "";
-
- // First Columns, rows, cells, mergecells, hyperlinks and pagebreakes are loaded from a xmlstream to optimize speed...
- Stream stream = packPart.GetStream();
-
- XmlTextReader xr = new XmlTextReader(stream);
- xr.ProhibitDtd = true;
- xr.WhitespaceHandling = WhitespaceHandling.None;
- LoadColumns(xr); //columnXml
- long start = stream.Position;
- LoadCells(xr);
- var nextElementLength = GetAttributeLength(xr);
- long end = stream.Position - nextElementLength;
- LoadMergeCells(xr);
- LoadHyperLinks(xr);
- LoadRowPageBreakes(xr);
- LoadColPageBreakes(xr);
- //...then the rest of the Xml is extracted and loaded into the WorksheetXml document.
- stream.Seek(0, SeekOrigin.Begin);
- xml = GetWorkSheetXml(stream, start, end, out var encoding);
-
- //first char is invalid sometimes??
- if (xml[0] != '<') {
- LoadXmlSafe(_worksheetXml, xml.Substring(1, xml.Length - 1), encoding);
- } else {
- LoadXmlSafe(_worksheetXml, xml, encoding);
- }
-
- ClearNodes();
- }
-
/// <summary>
/// Get the lenth of the attributes
/// Conditional formatting attributes can be extremly long som get length of the attributes to finetune position.
@@ -850,20 +762,20 @@
}
private void ClearNodes() {
- if (_worksheetXml.SelectSingleNode("//d:cols", NameSpaceManager) != null) {
- _worksheetXml.SelectSingleNode("//d:cols", NameSpaceManager).RemoveAll();
+ if (WorksheetXml.SelectSingleNode("//d:cols", NameSpaceManager) != null) {
+ WorksheetXml.SelectSingleNode("//d:cols", NameSpaceManager).RemoveAll();
}
- if (_worksheetXml.SelectSingleNode("//d:mergeCells", NameSpaceManager) != null) {
- _worksheetXml.SelectSingleNode("//d:mergeCells", NameSpaceManager).RemoveAll();
+ if (WorksheetXml.SelectSingleNode("//d:mergeCells", NameSpaceManager) != null) {
+ WorksheetXml.SelectSingleNode("//d:mergeCells", NameSpaceManager).RemoveAll();
}
- if (_worksheetXml.SelectSingleNode("//d:hyperlinks", NameSpaceManager) != null) {
- _worksheetXml.SelectSingleNode("//d:hyperlinks", NameSpaceManager).RemoveAll();
+ if (WorksheetXml.SelectSingleNode("//d:hyperlinks", NameSpaceManager) != null) {
+ WorksheetXml.SelectSingleNode("//d:hyperlinks", NameSpaceManager).RemoveAll();
}
- if (_worksheetXml.SelectSingleNode("//d:rowBreaks", NameSpaceManager) != null) {
- _worksheetXml.SelectSingleNode("//d:rowBreaks", NameSpaceManager).RemoveAll();
+ if (WorksheetXml.SelectSingleNode("//d:rowBreaks", NameSpaceManager) != null) {
+ WorksheetXml.SelectSingleNode("//d:rowBreaks", NameSpaceManager).RemoveAll();
}
- if (_worksheetXml.SelectSingleNode("//d:colBreaks", NameSpaceManager) != null) {
- _worksheetXml.SelectSingleNode("//d:colBreaks", NameSpaceManager).RemoveAll();
+ if (WorksheetXml.SelectSingleNode("//d:colBreaks", NameSpaceManager) != null) {
+ WorksheetXml.SelectSingleNode("//d:colBreaks", NameSpaceManager).RemoveAll();
}
}
@@ -1250,11 +1162,6 @@
break;
}
}
- //if (cell != null) cellList.Add(cell);
-
- //_cells = new RangeCollection(cellList);
- //_rows = new RangeCollection(rowList);
- //_formulaCells = new RangeCollection(formulaList);
}
private bool DoAddRow(XmlTextReader xr) {
@@ -1277,16 +1184,6 @@
}
if (xr.NodeType == XmlNodeType.Element) {
string address = xr.GetAttribute("ref");
- //int fromRow, fromCol, toRow, toCol;
- //ExcelCellBase.GetRowColFromAddress(address, out fromRow, out fromCol, out toRow, out toCol);
- //for (int row = fromRow; row <= toRow; row++)
- //{
- // for (int col = fromCol; col <= toCol; col++)
- // {
- // _flags.SetFlagValue(row, col, true,CellFlags.Merged);
- // }
- //}
- //_mergedCells.List.Add(address);
_mergedCells.Add(new ExcelAddress(address), false);
}
}
@@ -1475,45 +1372,6 @@
//}
}
- //private string GetSharedString(int stringID)
- //{
- // string retValue = null;
- // XmlNodeList stringNodes = xlPackage.Workbook.SharedStringsXml.SelectNodes(string.Format("//d:si", stringID), NameSpaceManager);
- // XmlNode stringNode = stringNodes[stringID];
- // if (stringNode != null)
- // retValue = stringNode.InnerText;
- // return (retValue);
- //}
-
- /// <summary>
- /// A reference to the header and footer class which allows you to
- /// set the header and footer for all odd, even and first pages of the worksheet
- /// </summary>
- /// <remarks>
- /// To format the text you can use the following format
- /// <list type="table">
- /// <listheader><term>Prefix</term><description>Description</description></listheader>
- /// <item><term>&U</term><description>Underlined</description></item>
- /// <item><term>&E</term><description>Double Underline</description></item>
- /// <item><term>&K:xxxxxx</term><description>Color. ex &K:FF0000 for red</description></item>
- /// <item><term>&"Font,Regular Bold Italic"</term><description>Changes the font. Regular or Bold or Italic or Bold Italic can be used. ex &"Arial,Bold Italic"</description></item>
- /// <item><term>&nn</term><description>Change font size. nn is an integer. ex &24</description></item>
- /// <item><term>&G</term><description>Placeholder for images. Images can not be added by the library, but its possible to use in a template.</description></item>
- /// </list>
- /// </remarks>
- public ExcelHeaderFooter HeaderFooter {
- get {
- if (_headerFooter == null) {
- XmlNode headerFooterNode = TopNode.SelectSingleNode("d:headerFooter", NameSpaceManager);
- if (headerFooterNode == null) {
- headerFooterNode = CreateNode("d:headerFooter");
- }
- _headerFooter = new(NameSpaceManager, headerFooterNode, this);
- }
- return (_headerFooter);
- }
- }
-
///// <summary>
///// Provides access to an individual cell within the worksheet.
///// </summary>
@@ -1772,58 +1630,56 @@
"Can't insert. Rows will be shifted outside the boundries of the worksheet."));
}
- lock (this) {
- _values.Insert(rowFrom, 0, rows, 0);
- _formulas.Insert(rowFrom, 0, rows, 0);
- _styles.Insert(rowFrom, 0, rows, 0);
- _types.Insert(rowFrom, 0, rows, 0);
- _commentsStore.Insert(rowFrom, 0, rows, 0);
- _hyperLinks.Insert(rowFrom, 0, rows, 0);
- _flags.Insert(rowFrom, 0, rows, 0);
+ _values.Insert(rowFrom, 0, rows, 0);
+ _formulas.Insert(rowFrom, 0, rows, 0);
+ _styles.Insert(rowFrom, 0, rows, 0);
+ _types.Insert(rowFrom, 0, rows, 0);
+ _commentsStore.Insert(rowFrom, 0, rows, 0);
+ _hyperLinks.Insert(rowFrom, 0, rows, 0);
+ _flags.Insert(rowFrom, 0, rows, 0);
- foreach (var f in _sharedFormulas.Values) {
- if (f.StartRow >= rowFrom) {
- f.StartRow += rows;
- }
- var a = new ExcelAddressBase(f.Address);
- if (a._fromRow >= rowFrom) {
- a._fromRow += rows;
- a._toRow += rows;
- } else if (a._toRow >= rowFrom) {
- a._toRow += rows;
- }
- f.Address = ExcelCellBase.GetAddress(a._fromRow, a._fromCol, a._toRow, a._toCol);
- f.Formula = ExcelCellBase.UpdateFormulaReferences(f.Formula, rows, 0, rowFrom, 0);
+ foreach (var f in _sharedFormulas.Values) {
+ if (f.StartRow >= rowFrom) {
+ f.StartRow += rows;
}
- var cse = new CellsStoreEnumerator<object>(_formulas);
- while (cse.Next()) {
- if (cse.Value is string) {
- cse.Value = ExcelCellBase.UpdateFormulaReferences(
- cse.Value.ToString(),
- rows,
- 0,
- rowFrom,
- 0);
- }
+ var a = new ExcelAddressBase(f.Address);
+ if (a._fromRow >= rowFrom) {
+ a._fromRow += rows;
+ a._toRow += rows;
+ } else if (a._toRow >= rowFrom) {
+ a._toRow += rows;
}
-
- FixMergedCellsRow(rowFrom, rows, false);
- if (copyStylesFromRow > 0) {
- var cseS = new CellsStoreEnumerator<int>(
- _styles,
- copyStylesFromRow,
+ f.Address = ExcelCellBase.GetAddress(a._fromRow, a._fromCol, a._toRow, a._toCol);
+ f.Formula = ExcelCellBase.UpdateFormulaReferences(f.Formula, rows, 0, rowFrom, 0);
+ }
+ var cse = new CellsStoreEnumerator<object>(_formulas);
+ while (cse.Next()) {
+ if (cse.Value is string) {
+ cse.Value = ExcelCellBase.UpdateFormulaReferences(
+ cse.Value.ToString(),
+ rows,
0,
- copyStylesFromRow,
- ExcelPackage.MaxColumns); //Fixes issue 15068 , 15090
- while (cseS.Next()) {
- for (var r = 0; r < rows; r++) {
- _styles.SetValue(rowFrom + r, cseS.Column, cseS.Value);
- }
+ rowFrom,
+ 0);
+ }
+ }
+
+ FixMergedCellsRow(rowFrom, rows, false);
+ if (copyStylesFromRow > 0) {
+ var cseS = new CellsStoreEnumerator<int>(
+ _styles,
+ copyStylesFromRow,
+ 0,
+ copyStylesFromRow,
+ ExcelPackage.MaxColumns); //Fixes issue 15068 , 15090
+ while (cseS.Next()) {
+ for (var r = 0; r < rows; r++) {
+ _styles.SetValue(rowFrom + r, cseS.Column, cseS.Value);
}
}
- foreach (var tbl in Tables) {
- tbl.Address = tbl.Address.AddRow(rowFrom, rows);
- }
+ }
+ foreach (var tbl in Tables) {
+ tbl.Address = tbl.Address.AddRow(rowFrom, rows);
}
}
@@ -1859,87 +1715,85 @@
"Can't insert. Columns will be shifted outside the boundries of the worksheet."));
}
- lock (this) {
- _values.Insert(0, columnFrom, 0, columns);
- _formulas.Insert(0, columnFrom, 0, columns);
- _styles.Insert(0, columnFrom, 0, columns);
- _types.Insert(0, columnFrom, 0, columns);
- _commentsStore.Insert(0, columnFrom, 0, columns);
- _hyperLinks.Insert(0, columnFrom, 0, columns);
- _flags.Insert(0, columnFrom, 0, columns);
+ _values.Insert(0, columnFrom, 0, columns);
+ _formulas.Insert(0, columnFrom, 0, columns);
+ _styles.Insert(0, columnFrom, 0, columns);
+ _types.Insert(0, columnFrom, 0, columns);
+ _commentsStore.Insert(0, columnFrom, 0, columns);
+ _hyperLinks.Insert(0, columnFrom, 0, columns);
+ _flags.Insert(0, columnFrom, 0, columns);
- foreach (var f in _sharedFormulas.Values) {
- if (f.StartCol >= columnFrom) {
- f.StartCol += columns;
+ foreach (var f in _sharedFormulas.Values) {
+ if (f.StartCol >= columnFrom) {
+ f.StartCol += columns;
+ }
+ var a = new ExcelAddressBase(f.Address);
+ if (a._fromCol >= columnFrom) {
+ a._fromCol += columns;
+ a._toCol += columns;
+ } else if (a._toCol >= columnFrom) {
+ a._toCol += columns;
+ }
+ f.Address = ExcelCellBase.GetAddress(a._fromRow, a._fromCol, a._toRow, a._toCol);
+ f.Formula = ExcelCellBase.UpdateFormulaReferences(f.Formula, 0, columns, 0, columnFrom);
+ }
+
+ var cse = new CellsStoreEnumerator<object>(_formulas);
+ while (cse.Next()) {
+ if (cse.Value is string) {
+ cse.Value = ExcelCellBase.UpdateFormulaReferences(
+ cse.Value.ToString(),
+ 0,
+ columns,
+ 0,
+ columnFrom);
+ }
+ }
+
+ FixMergedCellsColumn(columnFrom, columns, false);
+
+ var csec = new CellsStoreEnumerator<object>(_values, 0, 1, 0, ExcelPackage.MaxColumns);
+ var lst = new List<ExcelColumn>();
+ foreach (var col in csec) {
+ if (col is ExcelColumn column) {
+ lst.Add(column);
+ }
+ }
+
+ for (int i = lst.Count - 1; i >= 0; i--) {
+ var c = lst[i];
+ if (c._columnMin >= columnFrom) {
+ if (c._columnMin + columns <= ExcelPackage.MaxColumns) {
+ c._columnMin += columns;
+ } else {
+ c._columnMin = ExcelPackage.MaxColumns;
}
- var a = new ExcelAddressBase(f.Address);
- if (a._fromCol >= columnFrom) {
- a._fromCol += columns;
- a._toCol += columns;
- } else if (a._toCol >= columnFrom) {
- a._toCol += columns;
+
+ if (c._columnMax + columns <= ExcelPackage.MaxColumns) {
+ c._columnMax += columns;
+ } else {
+ c._columnMax = ExcelPackage.MaxColumns;
}
- f.Address = ExcelCellBase.GetAddress(a._fromRow, a._fromCol, a._toRow, a._toCol);
- f.Formula = ExcelCellBase.UpdateFormulaReferences(f.Formula, 0, columns, 0, columnFrom);
+ } else if (c._columnMax >= columnFrom) {
+ var cc = c._columnMax - columnFrom;
+ c._columnMax = columnFrom - 1;
+ CopyColumn(c, columnFrom + columns, columnFrom + columns + cc);
+ }
+ }
+
+ if (copyStylesFromColumn > 0) {
+ for (var c = 0; c < columns; c++) {
+ var col = Column(columnFrom + c);
+ col.StyleID = Column(copyStylesFromColumn).StyleID;
+ }
+ }
+ //Adjust tables
+ foreach (var tbl in Tables) {
+ if (columnFrom > tbl.Address.Start.Column && columnFrom <= tbl.Address.End.Column) {
+ InsertTableColumns(columnFrom, columns, tbl);
}
- var cse = new CellsStoreEnumerator<object>(_formulas);
- while (cse.Next()) {
- if (cse.Value is string) {
- cse.Value = ExcelCellBase.UpdateFormulaReferences(
- cse.Value.ToString(),
- 0,
- columns,
- 0,
- columnFrom);
- }
- }
-
- FixMergedCellsColumn(columnFrom, columns, false);
-
- var csec = new CellsStoreEnumerator<object>(_values, 0, 1, 0, ExcelPackage.MaxColumns);
- var lst = new List<ExcelColumn>();
- foreach (var col in csec) {
- if (col is ExcelColumn column) {
- lst.Add(column);
- }
- }
-
- for (int i = lst.Count - 1; i >= 0; i--) {
- var c = lst[i];
- if (c._columnMin >= columnFrom) {
- if (c._columnMin + columns <= ExcelPackage.MaxColumns) {
- c._columnMin += columns;
- } else {
- c._columnMin = ExcelPackage.MaxColumns;
- }
-
- if (c._columnMax + columns <= ExcelPackage.MaxColumns) {
- c._columnMax += columns;
- } else {
- c._columnMax = ExcelPackage.MaxColumns;
- }
- } else if (c._columnMax >= columnFrom) {
- var cc = c._columnMax - columnFrom;
- c._columnMax = columnFrom - 1;
- CopyColumn(c, columnFrom + columns, columnFrom + columns + cc);
- }
- }
-
- if (copyStylesFromColumn > 0) {
- for (var c = 0; c < columns; c++) {
- var col = Column(columnFrom + c);
- col.StyleID = Column(copyStylesFromColumn).StyleID;
- }
- }
- //Adjust tables
- foreach (var tbl in Tables) {
- if (columnFrom > tbl.Address.Start.Column && columnFrom <= tbl.Address.End.Column) {
- InsertTableColumns(columnFrom, columns, tbl);
- }
-
- tbl.Address = tbl.Address.AddColumn(columnFrom, columns);
- }
+ tbl.Address = tbl.Address.AddColumn(columnFrom, columns);
}
}
@@ -2064,21 +1918,19 @@
"Row out of range. Spans from 1 to "
+ ExcelPackage.MaxRows.ToString(CultureInfo.InvariantCulture)));
}
- lock (this) {
- _values.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns);
- _types.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns);
- _formulas.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns);
- _styles.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns);
- _flags.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns);
- _commentsStore.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns);
- _hyperLinks.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns);
+ _values.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns);
+ _types.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns);
+ _formulas.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns);
+ _styles.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns);
+ _flags.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns);
+ _commentsStore.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns);
+ _hyperLinks.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns);
- AdjustFormulasRow(rowFrom, rows);
- FixMergedCellsRow(rowFrom, rows, true);
+ AdjustFormulasRow(rowFrom, rows);
+ FixMergedCellsRow(rowFrom, rows, true);
- foreach (var tbl in Tables) {
- tbl.Address = tbl.Address.DeleteRow(rowFrom, rows);
- }
+ foreach (var tbl in Tables) {
+ tbl.Address = tbl.Address.DeleteRow(rowFrom, rows);
}
}
@@ -2101,59 +1953,52 @@
"Column out of range. Spans from 1 to "
+ ExcelPackage.MaxColumns.ToString(CultureInfo.InvariantCulture)));
}
- lock (this) {
- var col = _values.GetValue(0, columnFrom) as ExcelColumn;
- if (col == null) {
- var r = 0;
- var c = columnFrom;
- if (_values.PrevCell(ref r, ref c)) {
- col = _values.GetValue(0, c) as ExcelColumn;
- if (col._columnMax >= columnFrom) {
- col.ColumnMax = columnFrom - 1;
- }
+ var col = _values.GetValue(0, columnFrom) as ExcelColumn;
+ if (col == null) {
+ var r = 0;
+ var c = columnFrom;
+ if (_values.PrevCell(ref r, ref c)) {
+ col = _values.GetValue(0, c) as ExcelColumn;
+ if (col._columnMax >= columnFrom) {
+ col.ColumnMax = columnFrom - 1;
}
}
+ }
- _values.Delete(0, columnFrom, ExcelPackage.MaxRows, columns);
- _types.Delete(0, columnFrom, ExcelPackage.MaxRows, columns);
- _formulas.Delete(0, columnFrom, ExcelPackage.MaxRows, columns);
- _styles.Delete(0, columnFrom, ExcelPackage.MaxRows, columns);
- _flags.Delete(0, columnFrom, ExcelPackage.MaxRows, columns);
- _commentsStore.Delete(0, columnFrom, ExcelPackage.MaxRows, columns);
- _hyperLinks.Delete(0, columnFrom, ExcelPackage.MaxRows, columns);
+ _values.Delete(0, columnFrom, ExcelPackage.MaxRows, columns);
+ _types.Delete(0, columnFrom, ExcelPackage.MaxRows, columns);
+ _formulas.Delete(0, columnFrom, ExcelPackage.MaxRows, columns);
+ _styles.Delete(0, columnFrom, ExcelPackage.MaxRows, columns);
+ _flags.Delete(0, columnFrom, ExcelPackage.MaxRows, columns);
+ _commentsStore.Delete(0, columnFrom, ExcelPackage.MaxRows, columns);
+ _hyperLinks.Delete(0, columnFrom, ExcelPackage.MaxRows, columns);
- AdjustFormulasColumn(columnFrom, columns);
- FixMergedCellsColumn(columnFrom, columns, true);
+ AdjustFormulasColumn(columnFrom, columns);
+ FixMergedCellsColumn(columnFrom, columns, true);
- var csec = new CellsStoreEnumerator<object>(
- _values,
- 0,
- columnFrom,
- 0,
- ExcelPackage.MaxColumns);
- foreach (var column in csec) {
- if (column is ExcelColumn excelColumn) {
- if (excelColumn._columnMin >= columnFrom) {
- excelColumn._columnMin -= columns;
- excelColumn._columnMax -= columns;
- }
+ var csec = new CellsStoreEnumerator<object>(_values, 0, columnFrom, 0, ExcelPackage.MaxColumns);
+ foreach (var column in csec) {
+ if (column is ExcelColumn excelColumn) {
+ if (excelColumn._columnMin >= columnFrom) {
+ excelColumn._columnMin -= columns;
+ excelColumn._columnMax -= columns;
}
}
+ }
- foreach (var tbl in Tables) {
- if (columnFrom >= tbl.Address.Start.Column && columnFrom <= tbl.Address.End.Column) {
- var node = tbl.Columns[0].TopNode.ParentNode;
- var ix = columnFrom - tbl.Address.Start.Column;
- for (int i = 0; i < columns; i++) {
- if (node.ChildNodes.Count > ix) {
- node.RemoveChild(node.ChildNodes[ix]);
- }
+ foreach (var tbl in Tables) {
+ if (columnFrom >= tbl.Address.Start.Column && columnFrom <= tbl.Address.End.Column) {
+ var node = tbl.Columns[0].TopNode.ParentNode;
+ var ix = columnFrom - tbl.Address.Start.Column;
+ for (int i = 0; i < columns; i++) {
+ if (node.ChildNodes.Count > ix) {
+ node.RemoveChild(node.ChildNodes[ix]);
}
- tbl._cols = new(tbl);
}
-
- tbl.Address = tbl.Address.DeleteColumn(columnFrom, columns);
+ tbl._cols = new(tbl);
}
+
+ tbl.Address = tbl.Address.DeleteColumn(columnFrom, columns);
}
}
@@ -2175,7 +2020,6 @@
foreach (var ix in delSf) {
_sharedFormulas.Remove(ix);
}
- delSf = null;
var cse = new CellsStoreEnumerator<object>(
_formulas,
1,
@@ -2212,7 +2056,6 @@
foreach (var ix in delSf) {
_sharedFormulas.Remove(ix);
}
- delSf = null;
var cse = new CellsStoreEnumerator<object>(
_formulas,
1,
@@ -2406,32 +2249,22 @@
internal void Save() {
DeletePrinterSettings();
-
- if (_worksheetXml != null) {
- if (!(this is ExcelChartsheet)) {
- // save the header & footer (if defined)
- if (_headerFooter != null) {
- HeaderFooter.Save();
- }
-
- var d = Dimension;
- if (d == null) {
- DeleteAllNode("d:dimension/@ref");
- } else {
- SetXmlNodeString("d:dimension/@ref", d.Address);
- }
-
- SaveComments();
- SaveTables();
- SavePivotTables();
+ if (!(this is ExcelChartsheet)) {
+ var d = Dimension;
+ if (d == null) {
+ DeleteAllNode("d:dimension/@ref");
+ } else {
+ SetXmlNodeString("d:dimension/@ref", d.Address);
}
+ SaveTables();
+ SavePivotTables();
}
}
internal void SaveHandler(StreamWriter streamWriter) {
//Create the nodes if they do not exist.
if (this is ExcelChartsheet) {
- streamWriter.Write(_worksheetXml.OuterXml);
+ streamWriter.Write(WorksheetXml.OuterXml);
} else {
CreateNode("d:cols");
CreateNode("d:sheetData");
@@ -2441,7 +2274,7 @@
CreateNode("d:colBreaks");
//StreamWriter sw=new StreamWriter(Part.GetStream(FileMode.Create, FileAccess.Write));
- var xml = _worksheetXml.OuterXml;
+ var xml = WorksheetXml.OuterXml;
int colStart = 0,
colEnd = 0;
GetBlockPos(xml, "cols", ref colStart, ref colEnd);
@@ -2512,59 +2345,6 @@
}
}
- private void SaveComments() {
- if (_comments != null) {
- if (_comments.Count == 0) {
- if (_comments.Uri != null) {
- Part.DeleteRelationship(_comments.RelId);
- _package.Package.DeletePart(_comments.Uri);
- }
- RemoveLegacyDrawingRel(VmlDrawingsComments.RelId);
- } else {
- if (_comments.Uri == null) {
- _comments.Uri = new(string.Format("/xl/comments{0}.xml", SheetID), UriKind.Relative);
- }
- if (_comments.Part == null) {
- _comments.Part = _package.Package.CreatePart(
- _comments.Uri,
- "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml",
- _package.Compression);
- var rel = Part.CreateRelationship(
- UriHelper.GetRelativeUri(WorksheetUri, _comments.Uri),
- TargetMode.Internal,
- ExcelPackage._schemaRelationships + "/comments");
- }
- _comments.CommentXml.Save(_comments.Part.GetStream(FileMode.Create));
- }
- }
-
- if (_vmlDrawings != null) {
- if (_vmlDrawings.Count == 0) {
- if (_vmlDrawings.Uri != null) {
- Part.DeleteRelationship(_vmlDrawings.RelId);
- _package.Package.DeletePart(_vmlDrawings.Uri);
- }
- } else {
- if (_vmlDrawings.Uri == null) {
- _vmlDrawings.Uri = GetNewUri(_package.Package, "/xl/drawings/vmlDrawing{0}.vml");
- }
- if (_vmlDrawings.Part == null) {
- _vmlDrawings.Part = _package.Package.CreatePart(
- _vmlDrawings.Uri,
- "application/vnd.openxmlformats-officedocument.vmlDrawing",
- _package.Compression);
- var rel = Part.CreateRelationship(
- UriHelper.GetRelativeUri(WorksheetUri, _vmlDrawings.Uri),
- TargetMode.Internal,
- ExcelPackage._schemaRelationships + "/vmlDrawing");
- SetXmlNodeString("d:legacyDrawing/@r:id", rel.Id);
- _vmlDrawings.RelId = rel.Id;
- }
- _vmlDrawings.VmlDrawingXml.Save(_vmlDrawings.Part.GetStream());
- }
- }
- }
-
/// <summary>
/// Save all table data
/// </summary>
@@ -2614,30 +2394,6 @@
colNum++;
}
}
- if (tbl.Part == null) {
- tbl.TableUri = GetNewUri(_package.Package, "/xl/tables/table{0}.xml", tbl.Id);
- tbl.Part = _package.Package.CreatePart(
- tbl.TableUri,
- "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml",
- Workbook._package.Compression);
- var stream = tbl.Part.GetStream(FileMode.Create);
- tbl.TableXml.Save(stream);
- var rel = Part.CreateRelationship(
- UriHelper.GetRelativeUri(WorksheetUri, tbl.TableUri),
- TargetMode.Internal,
- ExcelPackage._schemaRelationships + "/table");
- tbl.RelationshipID = rel.Id;
-
- CreateNode("d:tableParts");
- XmlNode tbls = TopNode.SelectSingleNode("d:tableParts", NameSpaceManager);
-
- var tblNode = tbls.OwnerDocument.CreateElement("tablePart", ExcelPackage._schemaMain);
- tbls.AppendChild(tblNode);
- tblNode.SetAttribute("id", ExcelPackage._schemaRelationships, rel.Id);
- } else {
- var stream = tbl.Part.GetStream(FileMode.Create);
- tbl.TableXml.Save(stream);
- }
}
}
@@ -2775,9 +2531,6 @@
}
}
}
- pt.PivotTableXml.Save(pt.Part.GetStream(FileMode.Create));
- pt.CacheDefinition.CacheDefinitionXml.Save(
- pt.CacheDefinition.Part.GetStream(FileMode.Create));
}
}
@@ -2896,7 +2649,6 @@
int row = -1;
- StringBuilder sbXml = new StringBuilder();
var ss = _workbook._sharedStrings;
var styles = _workbook.Styles;
var cache = new StringBuilder();
@@ -3190,16 +2942,13 @@
? ""
: "tooltip=\"" + SecurityElement.Escape(link.ToolTip) + "\" ");
} else if (uri != null) {
- string id;
Uri hyp;
if (uri is ExcelHyperLink hyperLink) {
hyp = hyperLink.OriginalUri;
} else {
hyp = uri;
}
- if (hyps.ContainsKey(hyp.OriginalString)) {
- id = hyps[hyp.OriginalString];
- } else {
+ if (!hyps.ContainsKey(hyp.OriginalString)) {
var relationship = Part.CreateRelationship(
hyp,
TargetMode.External,
@@ -3221,9 +2970,7 @@
ExcelCellBase.GetAddress(cse.Row, cse.Column),
relationship.Id);
}
- id = relationship.Id;
}
- //cell.HyperLinkRId = id;
}
}
if (!first) {
@@ -3232,24 +2979,6 @@
}
/// <summary>
- /// Create the hyperlinks node in the XML
- /// </summary>
- /// <returns></returns>
- private XmlNode CreateHyperLinkCollection() {
- XmlElement hl = _worksheetXml.CreateElement("hyperlinks", ExcelPackage._schemaMain);
- XmlNode prevNode = _worksheetXml.SelectSingleNode(
- "//d:conditionalFormatting",
- NameSpaceManager);
- if (prevNode == null) {
- prevNode = _worksheetXml.SelectSingleNode("//d:mergeCells", NameSpaceManager);
- if (prevNode == null) {
- prevNode = _worksheetXml.SelectSingleNode("//d:sheetData", NameSpaceManager);
- }
- }
- return _worksheetXml.DocumentElement.InsertAfter(hl, prevNode);
- }
-
- /// <summary>
/// Dimension address for the worksheet.
/// Top left cell to Bottom right.
/// If the worksheet has no cells, null is returned
@@ -3274,7 +3003,7 @@
public ExcelSheetProtection Protection {
get {
if (_protection == null) {
- _protection = new(NameSpaceManager, TopNode, this);
+ _protection = new(NameSpaceManager, TopNode);
}
return _protection;
}
@@ -3285,7 +3014,7 @@
public ExcelProtectedRangeCollection ProtectedRanges {
get {
if (_protectedRanges == null) {
- _protectedRanges = new(NameSpaceManager, TopNode, this);
+ _protectedRanges = new(NameSpaceManager, TopNode);
}
return _protectedRanges;
}
@@ -3399,19 +3128,6 @@
return i;
}
- internal void SetHfLegacyDrawingRel(string relId) {
- SetXmlNodeString("d:legacyDrawingHF/@r:id", relId);
- }
-
- internal void RemoveLegacyDrawingRel(string relId) {
- var n = WorksheetXml.DocumentElement.SelectSingleNode(
- string.Format("d:legacyDrawing[@r:id=\"{0}\"]", relId),
- NameSpaceManager);
- if (n != null) {
- n.ParentNode.RemoveChild(n);
- }
- }
-
internal void UpdateCellsWithDate1904Setting() {
var cse = new CellsStoreEnumerator<object>(_values);
var offset = Workbook.Date1904 ? -ExcelWorkbook._date1904Offset : ExcelWorkbook._date1904Offset;
diff --git a/EPPlus/ExcelWorksheetView.cs b/EPPlus/ExcelWorksheetView.cs
index bd132e5..758ec6e 100644
--- a/EPPlus/ExcelWorksheetView.cs
+++ b/EPPlus/ExcelWorksheetView.cs
@@ -31,6 +31,7 @@
*******************************************************************************/
using System;
+using System.Collections.Immutable;
using System.Xml;
namespace OfficeOpenXml;
@@ -127,6 +128,13 @@
private readonly ExcelWorksheet _worksheet;
+ protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
+ "sheetViews",
+ "sheetView",
+ "pane",
+ "selection",
+ ];
+
/// <summary>
/// Creates a new ExcelWorksheetView which provides access to all the view states of the worksheet.
/// </summary>
@@ -136,7 +144,6 @@
internal ExcelWorksheetView(XmlNamespaceManager ns, XmlNode node, ExcelWorksheet xlWorksheet)
: base(ns, node) {
_worksheet = xlWorksheet;
- SchemaNodeOrder = new[] { "sheetViews", "sheetView", "pane", "selection" };
Panes = LoadPanes();
}
diff --git a/EPPlus/ExcelWorksheets.cs b/EPPlus/ExcelWorksheets.cs
index 1ed69a2..a0e4ebb 100644
--- a/EPPlus/ExcelWorksheets.cs
+++ b/EPPlus/ExcelWorksheets.cs
@@ -33,10 +33,8 @@
using System;
using System.Collections;
using System.Collections.Generic;
-using System.IO;
using System.Text.RegularExpressions;
using System.Xml;
-using OfficeOpenXml.Packaging;
using OfficeOpenXml.Utils;
namespace OfficeOpenXml;
@@ -47,7 +45,7 @@
public class ExcelWorksheets : XmlHelper, IEnumerable<ExcelWorksheet> {
private readonly ExcelPackage _pck;
private readonly ExcelWorkbook _workbook;
- private Dictionary<int, ExcelWorksheet> _worksheets;
+ private Dictionary<int, ExcelWorksheet> _worksheets = new();
private readonly XmlNamespaceManager _namespaceManager;
internal ExcelWorksheets(
@@ -59,7 +57,6 @@
_pck = pck;
_workbook = workbook;
_namespaceManager = nsm;
- _worksheets = new();
int positionId = 1;
foreach (XmlNode sheetNode in topNode.ChildNodes) {
@@ -89,7 +86,6 @@
_namespaceManager,
pck,
_workbook,
- relId,
uriWorksheet,
name,
sheetId,
@@ -102,7 +98,6 @@
_namespaceManager,
pck,
_workbook,
- relId,
uriWorksheet,
name,
sheetId,
@@ -152,65 +147,42 @@
/// </summary>
/// <param name="name">The name of the workbook</param>
public ExcelWorksheet Add(string name) {
- int sheetId;
- Uri uriWorksheet;
- lock (_worksheets) {
- name = ValidateFixSheetName(name);
- if (GetByName(name) != null) {
- throw (new InvalidOperationException(_errDupWorksheet + " : " + name));
- }
- GetSheetUri(ref name, out sheetId, out uriWorksheet, false);
- ZipPackagePart worksheetPart = _pck.Package.CreatePart(
- uriWorksheet,
- _worksheetContentType,
- _pck.Compression);
-
- //Create the new, empty worksheet and save it to the package
- StreamWriter streamWorksheet = new StreamWriter(
- worksheetPart.GetStream(FileMode.Create, FileAccess.Write));
- XmlDocument worksheetXml = CreateNewWorksheet(false);
- worksheetXml.Save(streamWorksheet);
-
- string rel = CreateWorkbookRel(name, sheetId, uriWorksheet, false);
-
- int positionId = _worksheets.Count + 1;
- ExcelWorksheet worksheet;
-
- {
- worksheet = new(
- _namespaceManager,
- _pck,
- _workbook,
- rel,
- uriWorksheet,
- name,
- sheetId,
- positionId,
- eWorkSheetHidden.Visible);
- }
-
- _worksheets.Add(positionId, worksheet);
- return worksheet;
+ name = ValidateFixSheetName(name);
+ if (GetByName(name) != null) {
+ throw (new InvalidOperationException(_errDupWorksheet + " : " + name));
}
- }
+ GetSheetUri(ref name, out var sheetId, out var uriWorksheet, false);
- private string CreateWorkbookRel(string name, int sheetId, Uri uriWorksheet, bool isChart) {
- //Create the relationship between the workbook and the new worksheet
- var rel = _workbook.Part.CreateRelationship(
- UriHelper.GetRelativeUri(ExcelWorkbook.WorkbookUri, uriWorksheet),
- TargetMode.Internal,
- ExcelPackage._schemaRelationships + "/" + (isChart ? "chartsheet" : "worksheet"));
+ // Create the new worksheet
+ var rel = _pck.CreateXmlDocument(
+ uriWorksheet,
+ _worksheetContentType,
+ ExcelPackage._schemaRelationships + "/worksheet",
+ CreateNewWorksheet(false));
- //Create the new sheet node
+ // Add worksheet to the workbook
XmlElement worksheetNode = _workbook.WorkbookXml.CreateElement(
"sheet",
ExcelPackage._schemaMain);
worksheetNode.SetAttribute("name", name);
worksheetNode.SetAttribute("sheetId", sheetId.ToString());
worksheetNode.SetAttribute("id", ExcelPackage._schemaRelationships, rel.Id);
-
TopNode.AppendChild(worksheetNode);
- return rel.Id;
+
+ int positionId = _worksheets.Count + 1;
+
+ ExcelWorksheet worksheet = new(
+ _namespaceManager,
+ _pck,
+ _workbook,
+ uriWorksheet,
+ name,
+ sheetId,
+ positionId,
+ eWorkSheetHidden.Visible);
+
+ _worksheets.Add(positionId, worksheet);
+ return worksheet;
}
private void GetSheetUri(ref string name, out int sheetId, out Uri uriWorksheet, bool isChart) {
@@ -361,181 +333,4 @@
}
return (xlWorksheet);
}
-
- /// <summary>
- /// Moves the source worksheet to the position before the target worksheet
- /// </summary>
- /// <param name="sourceName">The name of the source worksheet</param>
- /// <param name="targetName">The name of the target worksheet</param>
- public void MoveBefore(string sourceName, string targetName) {
- Move(sourceName, targetName, false);
- }
-
- /// <summary>
- /// Moves the source worksheet to the position before the target worksheet
- /// </summary>
- /// <param name="sourcePositionId">The id of the source worksheet</param>
- /// <param name="targetPositionId">The id of the target worksheet</param>
- public void MoveBefore(int sourcePositionId, int targetPositionId) {
- Move(sourcePositionId, targetPositionId, false);
- }
-
- /// <summary>
- /// Moves the source worksheet to the position after the target worksheet
- /// </summary>
- /// <param name="sourceName">The name of the source worksheet</param>
- /// <param name="targetName">The name of the target worksheet</param>
- public void MoveAfter(string sourceName, string targetName) {
- Move(sourceName, targetName, true);
- }
-
- /// <summary>
- /// Moves the source worksheet to the position after the target worksheet
- /// </summary>
- /// <param name="sourcePositionId">The id of the source worksheet</param>
- /// <param name="targetPositionId">The id of the target worksheet</param>
- public void MoveAfter(int sourcePositionId, int targetPositionId) {
- Move(sourcePositionId, targetPositionId, true);
- }
-
- /// <summary>
- ///
- /// </summary>
- /// <param name="sourceName"></param>
- public void MoveToStart(string sourceName) {
- var sourceSheet = this[sourceName];
- if (sourceSheet == null) {
- throw new(
- string.Format(
- "Move worksheet error: Could not find worksheet to move '{0}'",
- sourceName));
- }
- Move(sourceSheet.PositionID, 1, false);
- }
-
- /// <summary>
- ///
- /// </summary>
- /// <param name="sourcePositionId"></param>
- public void MoveToStart(int sourcePositionId) {
- Move(sourcePositionId, 1, false);
- }
-
- /// <summary>
- ///
- /// </summary>
- /// <param name="sourceName"></param>
- public void MoveToEnd(string sourceName) {
- var sourceSheet = this[sourceName];
- if (sourceSheet == null) {
- throw new(
- string.Format(
- "Move worksheet error: Could not find worksheet to move '{0}'",
- sourceName));
- }
- Move(sourceSheet.PositionID, _worksheets.Count, true);
- }
-
- /// <summary>
- ///
- /// </summary>
- /// <param name="sourcePositionId"></param>
- public void MoveToEnd(int sourcePositionId) {
- Move(sourcePositionId, _worksheets.Count, true);
- }
-
- private void Move(string sourceName, string targetName, bool placeAfter) {
- var sourceSheet = this[sourceName];
- if (sourceSheet == null) {
- throw new(
- string.Format(
- "Move worksheet error: Could not find worksheet to move '{0}'",
- sourceName));
- }
- var targetSheet = this[targetName];
- if (targetSheet == null) {
- throw new(
- string.Format(
- "Move worksheet error: Could not find worksheet to move '{0}'",
- targetName));
- }
- Move(sourceSheet.PositionID, targetSheet.PositionID, placeAfter);
- }
-
- private void Move(int sourcePositionId, int targetPositionId, bool placeAfter) {
- // Bugfix: if source and target are the same worksheet the following code will create a duplicate
- // which will cause a corrupt workbook. /swmal 2014-05-10
- if (sourcePositionId == targetPositionId) {
- return;
- }
-
- lock (_worksheets) {
- var sourceSheet = this[sourcePositionId];
- if (sourceSheet == null) {
- throw new(
- string.Format(
- "Move worksheet error: Could not find worksheet at position '{0}'",
- sourcePositionId));
- }
- var targetSheet = this[targetPositionId];
- if (targetSheet == null) {
- throw new(
- string.Format(
- "Move worksheet error: Could not find worksheet at position '{0}'",
- targetPositionId));
- }
- if (sourcePositionId == targetPositionId && _worksheets.Count < 2) {
- return; //--- no reason to attempt to re-arrange a single item with itself
- }
-
- var index = 1;
- var newOrder = new Dictionary<int, ExcelWorksheet>();
- foreach (var entry in _worksheets) {
- if (entry.Key == targetPositionId) {
- if (!placeAfter) {
- sourceSheet.PositionID = index;
- newOrder.Add(index++, sourceSheet);
- }
-
- entry.Value.PositionID = index;
- newOrder.Add(index++, entry.Value);
-
- if (placeAfter) {
- sourceSheet.PositionID = index;
- newOrder.Add(index++, sourceSheet);
- }
- } else if (entry.Key == sourcePositionId) {
- //--- do nothing
- } else {
- entry.Value.PositionID = index;
- newOrder.Add(index++, entry.Value);
- }
- }
- _worksheets = newOrder;
-
- MoveSheetXmlNode(sourceSheet, targetSheet, placeAfter);
- }
- }
-
- private void MoveSheetXmlNode(
- ExcelWorksheet sourceSheet,
- ExcelWorksheet targetSheet,
- bool placeAfter) {
- lock (TopNode.OwnerDocument) {
- var sourceNode = TopNode.SelectSingleNode(
- string.Format("d:sheet[@sheetId = '{0}']", sourceSheet.SheetID),
- _namespaceManager);
- var targetNode = TopNode.SelectSingleNode(
- string.Format("d:sheet[@sheetId = '{0}']", targetSheet.SheetID),
- _namespaceManager);
- if (sourceNode == null || targetNode == null) {
- throw new("Source SheetId and Target SheetId must be valid");
- }
- if (placeAfter) {
- TopNode.InsertAfter(sourceNode, targetNode);
- } else {
- TopNode.InsertBefore(sourceNode, targetNode);
- }
- }
- }
} // end class Worksheets
diff --git a/EPPlus/FormulaParsing/CalculateExtentions.cs b/EPPlus/FormulaParsing/CalculateExtentions.cs
index 8d8792b..afeb3ff 100644
--- a/EPPlus/FormulaParsing/CalculateExtentions.cs
+++ b/EPPlus/FormulaParsing/CalculateExtentions.cs
@@ -30,13 +30,9 @@
*******************************************************************************/
using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Text;
using OfficeOpenXml.FormulaParsing;
using OfficeOpenXml.FormulaParsing.Excel.Functions;
using OfficeOpenXml.FormulaParsing.Exceptions;
-using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
namespace OfficeOpenXml;
diff --git a/EPPlus/FormulaParsing/Excel/Functions/ArgumentParsers.cs b/EPPlus/FormulaParsing/Excel/Functions/ArgumentParsers.cs
index 86f9d5c..0a518f9 100644
--- a/EPPlus/FormulaParsing/Excel/Functions/ArgumentParsers.cs
+++ b/EPPlus/FormulaParsing/Excel/Functions/ArgumentParsers.cs
@@ -1,4 +1,4 @@
-/* Copyright (C) 2011 Jan Källman
+/* 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
@@ -30,7 +30,6 @@
namespace OfficeOpenXml.FormulaParsing.Excel.Functions;
public class ArgumentParsers {
- private static readonly object _syncRoot = new();
private readonly Dictionary<DataType, ArgumentParser> _parsers = new();
private readonly ArgumentParserFactory _parserFactory;
@@ -44,10 +43,8 @@
public ArgumentParser GetParser(DataType dataType) {
if (!_parsers.ContainsKey(dataType)) {
- lock (_syncRoot) {
- if (!_parsers.ContainsKey(dataType)) {
- _parsers.Add(dataType, _parserFactory.CreateArgumentParser(dataType));
- }
+ if (!_parsers.ContainsKey(dataType)) {
+ _parsers.Add(dataType, _parserFactory.CreateArgumentParser(dataType));
}
}
return _parsers[dataType];
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/DcountA.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/DcountA.cs
index 0316950..3af4c77 100644
--- a/EPPlus/FormulaParsing/Excel/Functions/Database/DcountA.cs
+++ b/EPPlus/FormulaParsing/Excel/Functions/Database/DcountA.cs
@@ -43,7 +43,7 @@
ValidateArguments(arguments, 2);
var dbAddress = arguments.ElementAt(0).ValueAsRangeInfo.Address.Address;
string field = null;
- string criteriaRange = null;
+ string criteriaRange;
if (arguments.Count() == 2) {
criteriaRange = arguments.ElementAt(1).ValueAsRangeInfo.Address.Address;
} else {
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/DateParsingFunction.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/DateParsingFunction.cs
index fbac43c..47143ef 100644
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/DateParsingFunction.cs
+++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/DateParsingFunction.cs
@@ -5,7 +5,7 @@
public abstract class DateParsingFunction : ExcelFunction {
protected System.DateTime ParseDate(IEnumerable<FunctionArgument> arguments, object dateObj) {
- System.DateTime date = System.DateTime.MinValue;
+ System.DateTime date;
if (dateObj is string) {
date = System.DateTime.Parse(dateObj.ToString(), CultureInfo.InvariantCulture);
} else {
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Minute.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Minute.cs
index 57426d0..a93b354 100644
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Minute.cs
+++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Minute.cs
@@ -35,7 +35,7 @@
ParsingContext context) {
ValidateArguments(arguments, 1);
var dateObj = arguments.ElementAt(0).Value;
- System.DateTime date = System.DateTime.MinValue;
+ System.DateTime date;
if (dateObj is string) {
date = System.DateTime.Parse(dateObj.ToString());
} else {
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/TimeBaseFunction.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/TimeBaseFunction.cs
index 879fc64..4b2ef4a 100644
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/TimeBaseFunction.cs
+++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/TimeBaseFunction.cs
@@ -28,11 +28,7 @@
namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
public abstract class TimeBaseFunction : ExcelFunction {
- public TimeBaseFunction() {
- TimeStringParser = new();
- }
-
- protected TimeStringParser TimeStringParser { get; private set; }
+ protected TimeStringParser TimeStringParser { get; private set; } = new();
protected double SerialNumber { get; private set; }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/TimeStringParser.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/TimeStringParser.cs
index 533528d..0c403b6 100644
--- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/TimeStringParser.cs
+++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/TimeStringParser.cs
@@ -71,8 +71,7 @@
}
private double Parse12HourTimeString(string input) {
- string dayPart = string.Empty;
- dayPart = input.Substring(input.Length - 2, 2);
+ var dayPart = input.Substring(input.Length - 2, 2);
GetValuesFromString(input, out var hour, out var minute, out var second);
if (dayPart == "PM") {
hour += 12;
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/AverageIf.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/AverageIf.cs
index 0423f98..5568a25 100644
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/AverageIf.cs
+++ b/EPPlus/FormulaParsing/Excel/Functions/Math/AverageIf.cs
@@ -76,7 +76,7 @@
ThrowExcelErrorValueExceptionIf(
() => criteria == null || criteria.ToString().Length > 255,
eErrorType.Value);
- var retVal = 0d;
+ double retVal;
if (arguments.Count() > 2) {
var secondArg = arguments.ElementAt(2);
var lookupRange = secondArg.Value as IEnumerable<FunctionArgument>;
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Subtotal.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Subtotal.cs
index cc82beb..17d8586 100644
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/Subtotal.cs
+++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Subtotal.cs
@@ -81,8 +81,7 @@
return CreateResult(0d, DataType.Decimal);
}
var actualArgs = arguments.Skip(1);
- ExcelFunction function = null;
- function = GetFunctionByCalcType(funcNum);
+ var function = GetFunctionByCalcType(funcNum);
var compileResult = function.Execute(actualArgs, context);
compileResult.IsResultOfSubtotal = true;
return compileResult;
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/SumIf.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/SumIf.cs
index 232d460..8d8d61b 100644
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/SumIf.cs
+++ b/EPPlus/FormulaParsing/Excel/Functions/Math/SumIf.cs
@@ -53,7 +53,7 @@
ThrowExcelErrorValueExceptionIf(
() => criteria == null || criteria.ToString().Length > 255,
eErrorType.Value);
- var retVal = 0d;
+ double retVal;
if (arguments.Count() > 2) {
var sumRange = arguments.ElementAt(2).Value as ExcelDataProvider.IRangeInfo; //IEnumerable<FunctionArgument>;
retVal = CalculateWithSumRange(args, criteria.ToString(), sumRange, context);
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/VarMethods.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/VarMethods.cs
index d12ddf8..6061b74 100644
--- a/EPPlus/FormulaParsing/Excel/Functions/Math/VarMethods.cs
+++ b/EPPlus/FormulaParsing/Excel/Functions/Math/VarMethods.cs
@@ -39,13 +39,13 @@
public static double Var(IEnumerable<double> args) {
double avg = args.Average();
- double d = args.Aggregate(0.0, (total, next) => total += System.Math.Pow(next - avg, 2));
+ double d = args.Aggregate(0.0, (total, next) => total + System.Math.Pow(next - avg, 2));
return Divide(d, (args.Count() - 1));
}
public static double VarP(IEnumerable<double> args) {
double avg = args.Average();
- double d = args.Aggregate(0.0, (total, next) => total += System.Math.Pow(next - avg, 2));
+ double d = args.Aggregate(0.0, (total, next) => total + System.Math.Pow(next - avg, 2));
return Divide(d, args.Count());
}
}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Value.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Value.cs
index 2a05519..e5ee106 100644
--- a/EPPlus/FormulaParsing/Excel/Functions/Text/Value.cs
+++ b/EPPlus/FormulaParsing/Excel/Functions/Text/Value.cs
@@ -24,7 +24,7 @@
ParsingContext context) {
ValidateArguments(arguments, 1);
var val = ArgToString(arguments, 0).TrimEnd(' ');
- double result = 0d;
+ double result;
if (Regex.IsMatch(
val,
$"^[\\d]*({Regex.Escape(_groupSeparator)}?[\\d]*)?({Regex.Escape(_decimalSeparator)
diff --git a/EPPlus/FormulaParsing/ExcelCalculationOption.cs b/EPPlus/FormulaParsing/ExcelCalculationOption.cs
index a94d5ef..79d03bc 100644
--- a/EPPlus/FormulaParsing/ExcelCalculationOption.cs
+++ b/EPPlus/FormulaParsing/ExcelCalculationOption.cs
@@ -1,9 +1,5 @@
namespace OfficeOpenXml.FormulaParsing;
public class ExcelCalculationOption {
- public ExcelCalculationOption() {
- AllowCirculareReferences = false;
- }
-
- public bool AllowCirculareReferences { get; set; }
+ public bool AllowCirculareReferences { get; set; } = false;
}
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/ExcelAddressInfo.cs b/EPPlus/FormulaParsing/ExcelUtilities/ExcelAddressInfo.cs
index afba2c1..c7dd453 100644
--- a/EPPlus/FormulaParsing/ExcelUtilities/ExcelAddressInfo.cs
+++ b/EPPlus/FormulaParsing/ExcelUtilities/ExcelAddressInfo.cs
@@ -36,7 +36,6 @@
public class ExcelAddressInfo {
private ExcelAddressInfo(string address) {
var addressOnSheet = address;
- Worksheet = string.Empty;
if (address.Contains("!")) {
var worksheetArr = address.Split('!');
Worksheet = worksheetArr[0];
@@ -57,7 +56,7 @@
return new(address);
}
- public string Worksheet { get; private set; }
+ public string Worksheet { get; private set; } = string.Empty;
public bool WorksheetIsSpecified => !string.IsNullOrEmpty(Worksheet);
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/RangeAddress.cs b/EPPlus/FormulaParsing/ExcelUtilities/RangeAddress.cs
index cf62744..b46145c 100644
--- a/EPPlus/FormulaParsing/ExcelUtilities/RangeAddress.cs
+++ b/EPPlus/FormulaParsing/ExcelUtilities/RangeAddress.cs
@@ -32,11 +32,7 @@
namespace OfficeOpenXml.FormulaParsing.ExcelUtilities;
public class RangeAddress {
- public RangeAddress() {
- Address = string.Empty;
- }
-
- internal string Address { get; set; }
+ internal string Address { get; set; } = string.Empty;
public string Worksheet { get; internal set; }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/Expression.cs b/EPPlus/FormulaParsing/ExpressionGraph/Expression.cs
index e32e3f0..bdab90a 100644
--- a/EPPlus/FormulaParsing/ExpressionGraph/Expression.cs
+++ b/EPPlus/FormulaParsing/ExpressionGraph/Expression.cs
@@ -77,7 +77,7 @@
}
public virtual Expression MergeWithNext() {
- var expression = this;
+ Expression expression;
if (Next != null && Operator != null) {
var result = Operator.Apply(Compile(), Next.Compile());
expression = ExpressionConverter.Instance.FromCompileResult(result);
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/TokenFactory.cs b/EPPlus/FormulaParsing/LexicalAnalysis/TokenFactory.cs
index 6ba0d9b..4639753 100644
--- a/EPPlus/FormulaParsing/LexicalAnalysis/TokenFactory.cs
+++ b/EPPlus/FormulaParsing/LexicalAnalysis/TokenFactory.cs
@@ -70,9 +70,9 @@
var tokenList = (IList<Token>)tokens;
//Address with worksheet-string before /JK
if (token.StartsWith("!") && tokenList[tokenList.Count - 1].TokenType == TokenType.String) {
- string addr = "";
var i = tokenList.Count - 2;
if (i > 0) {
+ string addr;
if (tokenList[i].TokenType == TokenType.StringContent) {
addr = "'" + tokenList[i].Value.Replace("'", "''") + "'";
} else {
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorProvider.cs b/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorProvider.cs
index 337f2a2..d56dc18 100644
--- a/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorProvider.cs
+++ b/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorProvider.cs
@@ -34,10 +34,9 @@
namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis;
public class TokenSeparatorProvider : ITokenSeparatorProvider {
- private static readonly Dictionary<string, Token> _tokens;
+ private static readonly Dictionary<string, Token> _tokens = new();
static TokenSeparatorProvider() {
- _tokens = new();
_tokens.Add("+", new("+", TokenType.Operator));
_tokens.Add("-", new("-", TokenType.Operator));
_tokens.Add("*", new("*", TokenType.Operator));
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/TokenizerContext.cs b/EPPlus/FormulaParsing/LexicalAnalysis/TokenizerContext.cs
index ef9c31a..130324d 100644
--- a/EPPlus/FormulaParsing/LexicalAnalysis/TokenizerContext.cs
+++ b/EPPlus/FormulaParsing/LexicalAnalysis/TokenizerContext.cs
@@ -40,13 +40,11 @@
if (!string.IsNullOrEmpty(formula)) {
_chars = formula.ToArray();
}
- _result = new();
- _currentToken = new();
}
private readonly char[] _chars;
- private readonly List<Token> _result;
- private StringBuilder _currentToken;
+ private readonly List<Token> _result = new();
+ private StringBuilder _currentToken = new();
public char[] FormulaChars => _chars;
diff --git a/EPPlus/FormulaParsing/ParsingConfiguration.cs b/EPPlus/FormulaParsing/ParsingConfiguration.cs
index 71440b3..90792b4 100644
--- a/EPPlus/FormulaParsing/ParsingConfiguration.cs
+++ b/EPPlus/FormulaParsing/ParsingConfiguration.cs
@@ -15,11 +15,9 @@
public IExpressionCompiler ExpressionCompiler { get; private set; }
- public FunctionRepository FunctionRepository { get; private set; }
+ public FunctionRepository FunctionRepository { get; private set; } = FunctionRepository.Create();
- private ParsingConfiguration() {
- FunctionRepository = FunctionRepository.Create();
- }
+ private ParsingConfiguration() {}
internal static ParsingConfiguration Create() {
return new();
diff --git a/EPPlus/FormulaParsing/ParsingScope.cs b/EPPlus/FormulaParsing/ParsingScope.cs
index 1e861c5..f901f1e 100644
--- a/EPPlus/FormulaParsing/ParsingScope.cs
+++ b/EPPlus/FormulaParsing/ParsingScope.cs
@@ -16,13 +16,12 @@
_parsingScopes = parsingScopes;
Parent = parent;
Address = address;
- ScopeId = Guid.NewGuid();
}
/// <summary>
/// Id of the scope.
/// </summary>
- public Guid ScopeId { get; private set; }
+ public Guid ScopeId { get; private set; } = Guid.NewGuid();
/// <summary>
/// The calling scope.
diff --git a/EPPlus/OfficeProperties.cs b/EPPlus/OfficeProperties.cs
index 1b0a6be..e41d226 100644
--- a/EPPlus/OfficeProperties.cs
+++ b/EPPlus/OfficeProperties.cs
@@ -34,10 +34,7 @@
using System;
using System.Globalization;
-using System.IO;
using System.Xml;
-using OfficeOpenXml.Packaging;
-using OfficeOpenXml.Utils;
namespace OfficeOpenXml;
@@ -45,18 +42,14 @@
/// Provides access to the properties bag of the package
/// </summary>
public sealed class OfficeProperties : XmlHelper {
- private XmlDocument _xmlPropertiesCore;
- private XmlDocument _xmlPropertiesExtended;
- private XmlDocument _xmlPropertiesCustom;
+ private readonly XmlDocument _xmlPropertiesCore;
+ private readonly XmlDocument _xmlPropertiesExtended;
private readonly Uri _uriPropertiesCore = new("/docProps/core.xml", UriKind.Relative);
private readonly Uri _uriPropertiesExtended = new("/docProps/app.xml", UriKind.Relative);
- private readonly Uri _uriPropertiesCustom = new("/docProps/custom.xml", UriKind.Relative);
private readonly XmlHelper _coreHelper;
private readonly XmlHelper _extendedHelper;
- private XmlHelper _customHelper;
- private readonly ExcelPackage _package;
/// <summary>
/// Provides access to all the office document properties.
@@ -65,67 +58,25 @@
/// <param name="ns"></param>
internal OfficeProperties(ExcelPackage package, XmlNamespaceManager ns)
: base(ns) {
- _package = package;
-
+ const string coreBaseXml =
+ $"""<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><cp:coreProperties xmlns:cp="{ExcelPackage._schemaCore}" xmlns:dc="{ExcelPackage._schemaDc}" xmlns:dcterms="{ExcelPackage._schemaDcTerms}" xmlns:dcmitype="{ExcelPackage._schemaDcmiType}" xmlns:xsi="{ExcelPackage._schemaXsi}"></cp:coreProperties>""";
+ _xmlPropertiesCore = package.GetOrCreateXmlDocument(
+ _uriPropertiesCore,
+ "application/vnd.openxmlformats-package.core-properties+xml",
+ "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties",
+ coreBaseXml);
_coreHelper = XmlHelperFactory.Create(
ns,
- CorePropertiesXml.SelectSingleNode("cp:coreProperties", NameSpaceManager));
- _extendedHelper = XmlHelperFactory.Create(ns, ExtendedPropertiesXml);
- _customHelper = XmlHelperFactory.Create(ns, CustomPropertiesXml);
- }
+ _xmlPropertiesCore.SelectSingleNode("cp:coreProperties", NameSpaceManager));
- /// <summary>
- /// Provides access to the XML document that holds all the code
- /// document properties.
- /// </summary>
- public XmlDocument CorePropertiesXml {
- get {
- if (_xmlPropertiesCore == null) {
- string xml = string.Format(
- "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?><cp:coreProperties xmlns:cp=\"{0}\" xmlns:dc=\"{1}\" xmlns:dcterms=\"{2}\" xmlns:dcmitype=\"{3}\" xmlns:xsi=\"{4}\"></cp:coreProperties>",
- ExcelPackage._schemaCore,
- ExcelPackage._schemaDc,
- ExcelPackage._schemaDcTerms,
- ExcelPackage._schemaDcmiType,
- ExcelPackage._schemaXsi);
-
- _xmlPropertiesCore = GetXmlDocument(
- xml,
- _uriPropertiesCore,
- "application/vnd.openxmlformats-package.core-properties+xml",
- "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties");
- }
- return (_xmlPropertiesCore);
- }
- }
-
- private XmlDocument GetXmlDocument(
- string startXml,
- Uri uri,
- string contentType,
- string relationship) {
- XmlDocument xmlDoc;
- if (_package.Package.PartExists(uri)) {
- xmlDoc = _package.GetXmlFromUri(uri);
- } else {
- xmlDoc = new();
- xmlDoc.LoadXml(startXml);
-
- // Create a the part and add to the package
- ZipPackagePart part = _package.Package.CreatePart(uri, contentType);
-
- // Save it to the package
- StreamWriter stream = new StreamWriter(part.GetStream(FileMode.Create, FileAccess.Write));
- xmlDoc.Save(stream);
- //stream.Close();
-
- // create the relationship between the workbook and the new shared strings part
- _package.Package.CreateRelationship(
- UriHelper.GetRelativeUri(new("/xl", UriKind.Relative), uri),
- TargetMode.Internal,
- relationship);
- }
- return xmlDoc;
+ const string extendedBaseXml =
+ $"""<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><Properties xmlns:vt="{ExcelPackage._schemaVt}" xmlns="{ExcelPackage._schemaExtended}"></Properties>""";
+ _xmlPropertiesExtended = package.GetOrCreateXmlDocument(
+ _uriPropertiesExtended,
+ "application/vnd.openxmlformats-officedocument.extended-properties+xml",
+ "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties",
+ extendedBaseXml);
+ _extendedHelper = XmlHelperFactory.Create(ns, _xmlPropertiesExtended);
}
private const string _titlePath = "dc:title";
@@ -240,16 +191,7 @@
/// </summary>
public XmlDocument ExtendedPropertiesXml {
get {
- if (_xmlPropertiesExtended == null) {
- _xmlPropertiesExtended = GetXmlDocument(
- string.Format(
- "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?><Properties xmlns:vt=\"{0}\" xmlns=\"{1}\"></Properties>",
- ExcelPackage._schemaVt,
- ExcelPackage._schemaExtended),
- _uriPropertiesExtended,
- "application/vnd.openxmlformats-officedocument.extended-properties+xml",
- "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties");
- }
+ if (_xmlPropertiesExtended == null) {}
return (_xmlPropertiesExtended);
}
}
@@ -320,142 +262,4 @@
_coreHelper.SetXmlNodeString(_modifiedPath + "/@xsi:type", "dcterms:W3CDTF");
}
}
-
- /// <summary>
- /// Provides access to the XML document which holds the document's custom properties
- /// </summary>
- public XmlDocument CustomPropertiesXml {
- get {
- if (_xmlPropertiesCustom == null) {
- _xmlPropertiesCustom = GetXmlDocument(
- string.Format(
- "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?><Properties xmlns:vt=\"{0}\" xmlns=\"{1}\"></Properties>",
- ExcelPackage._schemaVt,
- ExcelPackage._schemaCustom),
- _uriPropertiesCustom,
- "application/vnd.openxmlformats-officedocument.custom-properties+xml",
- "http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties");
- }
- return (_xmlPropertiesCustom);
- }
- }
-
- /// <summary>
- /// Gets the value of a custom property
- /// </summary>
- /// <param name="propertyName">The name of the property</param>
- /// <returns>The current value of the property</returns>
- public object GetCustomPropertyValue(string propertyName) {
- string searchString = string.Format("ctp:Properties/ctp:property[@name='{0}']", propertyName);
- XmlElement node =
- CustomPropertiesXml.SelectSingleNode(searchString, NameSpaceManager) as XmlElement;
- if (node != null) {
- string value = node.LastChild.InnerText;
- switch (node.LastChild.LocalName) {
- case "filetime":
- if (DateTime.TryParse(value, out var dt)) {
- return dt;
- }
- return null;
- case "i4":
- if (int.TryParse(value, out var i)) {
- return i;
- }
- return null;
- case "r8":
- if (double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out var d)) {
- return d;
- }
- return null;
- case "bool":
- if (value == "true") {
- return true;
- }
- if (value == "false") {
- return false;
- }
- return null;
- default:
- return value;
- }
- }
- return null;
- }
-
- /// <summary>
- /// Allows you to set the value of a current custom property or create your own custom property.
- /// </summary>
- /// <param name="propertyName">The name of the property</param>
- /// <param name="value">The value of the property</param>
- public void SetCustomPropertyValue(string propertyName, object value) {
- XmlNode allProps = CustomPropertiesXml.SelectSingleNode("ctp:Properties", NameSpaceManager);
-
- var prop = string.Format("ctp:Properties/ctp:property[@name='{0}']", propertyName);
- XmlElement node = CustomPropertiesXml.SelectSingleNode(prop, NameSpaceManager) as XmlElement;
- if (node == null) {
- int pid;
- var maxNode = CustomPropertiesXml.SelectSingleNode(
- "ctp:Properties/ctp:property[not(@pid <= preceding-sibling::ctp:property/@pid) and not(@pid <= following-sibling::ctp:property/@pid)]",
- NameSpaceManager);
- if (maxNode == null) {
- pid = 2;
- } else {
- if (!int.TryParse(maxNode.Attributes["pid"].Value, out pid)) {
- pid = 2;
- }
- pid++;
- }
- node = CustomPropertiesXml.CreateElement("property", ExcelPackage._schemaCustom);
- node.SetAttribute("fmtid", "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}");
- node.SetAttribute("pid", pid.ToString()); // custom property pid
- node.SetAttribute("name", propertyName);
-
- allProps.AppendChild(node);
- } else {
- while (node.ChildNodes.Count > 0) {
- node.RemoveChild(node.ChildNodes[0]);
- }
- }
- XmlElement valueElem;
- if (value is bool) {
- valueElem = CustomPropertiesXml.CreateElement("vt", "bool", ExcelPackage._schemaVt);
- valueElem.InnerText = value.ToString().ToLower(CultureInfo.InvariantCulture);
- } else if (value is DateTime time) {
- valueElem = CustomPropertiesXml.CreateElement("vt", "filetime", ExcelPackage._schemaVt);
- valueElem.InnerText = time.AddHours(-1).ToString("yyyy-MM-ddTHH:mm:ssZ");
- } else if (value is short || value is int) {
- valueElem = CustomPropertiesXml.CreateElement("vt", "i4", ExcelPackage._schemaVt);
- valueElem.InnerText = value.ToString();
- } else if (value is double || value is decimal || value is float || value is long) {
- valueElem = CustomPropertiesXml.CreateElement("vt", "r8", ExcelPackage._schemaVt);
- if (value is double d) {
- valueElem.InnerText = d.ToString(CultureInfo.InvariantCulture);
- } else if (value is float f) {
- valueElem.InnerText = f.ToString(CultureInfo.InvariantCulture);
- } else if (value is decimal value1) {
- valueElem.InnerText = value1.ToString(CultureInfo.InvariantCulture);
- } else {
- valueElem.InnerText = value.ToString();
- }
- } else {
- valueElem = CustomPropertiesXml.CreateElement("vt", "lpwstr", ExcelPackage._schemaVt);
- valueElem.InnerText = value.ToString();
- }
- node.AppendChild(valueElem);
- }
-
- /// <summary>
- /// Saves the document properties back to the package.
- /// </summary>
- internal void Save() {
- if (_xmlPropertiesCore != null) {
- _package.SavePart(_uriPropertiesCore, _xmlPropertiesCore);
- }
- if (_xmlPropertiesExtended != null) {
- _package.SavePart(_uriPropertiesExtended, _xmlPropertiesExtended);
- }
- if (_xmlPropertiesCustom != null) {
- _package.SavePart(_uriPropertiesCustom, _xmlPropertiesCustom);
- }
- }
}
diff --git a/EPPlus/Packaging/ZipPackage.cs b/EPPlus/Packaging/ZipPackage.cs
index 843d105..921c744 100644
--- a/EPPlus/Packaging/ZipPackage.cs
+++ b/EPPlus/Packaging/ZipPackage.cs
@@ -35,6 +35,7 @@
using System.IO;
using System.IO.Compression;
using System.Linq;
+using System.Runtime.InteropServices;
using System.Text;
using System.Xml;
using OfficeOpenXml.Utils;
@@ -59,7 +60,7 @@
/// <summary>
/// Represent an OOXML Zip package.
/// </summary>
-public class ZipPackage : ZipPackageRelationshipBase {
+internal class ZipPackage : ZipPackageRelationshipBase {
internal class ContentType {
internal string Name;
internal bool IsExtension;
@@ -111,10 +112,13 @@
if (e.FullName.EndsWith(".rels", StringComparison.InvariantCultureIgnoreCase)) {
rels.Add(GetUriKey(e.FullName), e);
} else {
+ var data = new byte[e.Length];
using var inputStream = e.Open();
- var part = new ZipPackagePart(this, e);
- part.Stream = new();
- inputStream.CopyTo(part.Stream);
+ inputStream.ReadExactly(data);
+ var part = new ZipPackagePart(
+ this,
+ e,
+ ImmutableCollectionsMarshal.AsImmutableArray(data));
Parts.Add(GetUriKey(e.FullName), part);
}
}
@@ -158,24 +162,16 @@
}
}
- internal ZipPackagePart CreatePart(Uri partUri, string contentType) {
- return CreatePart(partUri, contentType, CompressionLevel.Default);
- }
-
- internal ZipPackagePart CreatePart(
- Uri partUri,
- string contentType,
- CompressionLevel compressionLevel) {
+ internal void CreatePart(Uri partUri, string contentType, Action<StreamWriter> saveHandler) {
if (PartExists(partUri)) {
throw (new InvalidOperationException("Part already exist"));
}
- var part = new ZipPackagePart(this, partUri, contentType, compressionLevel);
+ var part = new ZipPackagePart(this, partUri, contentType, saveHandler);
_contentTypes.Add(
GetUriKey(part.Uri.OriginalString),
new(contentType, false, part.Uri.OriginalString));
Parts.Add(GetUriKey(part.Uri.OriginalString), part);
- return part;
}
internal ZipPackagePart GetPart(Uri partUri) {
@@ -223,7 +219,6 @@
while (rels.Count > 0) {
rels.Remove(rels.First().Id);
}
- rels = null;
_contentTypes.Remove(GetUriKey(uri.OriginalString));
//remove all relations
Parts.Remove(GetUriKey(uri.OriginalString));
@@ -231,13 +226,13 @@
internal void Save(Stream stream) {
using var zipArchive = new ZipArchive(stream, ZipArchiveMode.Create, leaveOpen: true);
- /**** ContentType****/
+ // Content types
var contentTypesEntry = zipArchive.CreateEntry("[Content_Types].xml");
using (var contentTypesWriter = new StreamWriter(contentTypesEntry.Open())) {
contentTypesWriter.Write(GetContentTypeXml());
}
- /**** Top Rels ****/
- _rels.WriteZip(zipArchive, "_rels\\.rels");
+ // Top Rels
+ _rels.WriteZip(zipArchive, "_rels/.rels");
ZipPackagePart ssPart = null;
foreach (var part in Parts.Values) {
if (part.ContentType != ExcelPackage._contentTypeSharedString) {
@@ -250,7 +245,6 @@
if (ssPart != null) {
ssPart.WriteZip(zipArchive);
}
- //return ms;
}
private string GetContentTypeXml() {
@@ -258,29 +252,12 @@
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">");
foreach (ContentType ct in _contentTypes.Values) {
if (ct.IsExtension) {
- xml.AppendFormat("<Default ContentType=\"{0}\" Extension=\"{1}\"/>", ct.Name, ct.Match);
+ xml.Append($"<Default ContentType=\"{ct.Name}\" Extension=\"{ct.Match}\"/>");
} else {
- xml.AppendFormat(
- "<Override ContentType=\"{0}\" PartName=\"{1}\" />",
- ct.Name,
- GetUriKey(ct.Match));
+ xml.Append($"<Override ContentType=\"{ct.Name}\" PartName=\"{GetUriKey(ct.Match)}\" />");
}
}
xml.Append("</Types>");
return xml.ToString();
}
-
- private CompressionLevel _compression = CompressionLevel.Default;
-
- public CompressionLevel Compression {
- get => _compression;
- set {
- foreach (var part in Parts.Values) {
- if (part.CompressionLevel == _compression) {
- part.CompressionLevel = value;
- }
- }
- _compression = value;
- }
- }
}
diff --git a/EPPlus/Packaging/ZipPackagePart.cs b/EPPlus/Packaging/ZipPackagePart.cs
index 407428d..47d20fb 100644
--- a/EPPlus/Packaging/ZipPackagePart.cs
+++ b/EPPlus/Packaging/ZipPackagePart.cs
@@ -30,42 +30,35 @@
*******************************************************************************/
using System;
+using System.Collections.Immutable;
using System.IO;
using System.IO.Compression;
+using System.Runtime.InteropServices;
namespace OfficeOpenXml.Packaging;
internal class ZipPackagePart : ZipPackageRelationshipBase, IDisposable {
- internal delegate void SaveHandlerDelegate(StreamWriter streamWriter);
-
- internal ZipPackagePart(ZipPackage package, ZipArchiveEntry entry) {
+ internal ZipPackagePart(ZipPackage package, ZipArchiveEntry entry, ImmutableArray<byte> data) {
Package = package;
SaveHandler = null;
Uri = new(package.GetUriKey(entry.FullName), UriKind.Relative);
+ _data = data;
}
+ private readonly ImmutableArray<byte> _data;
+
internal ZipPackagePart(
ZipPackage package,
Uri partUri,
string contentType,
- CompressionLevel compressionLevel) {
+ Action<StreamWriter> saveHandler) {
Package = package;
- //Entry = new ZipEntry();
- //Entry.FileName = partUri.OriginalString.Replace('/','\\');
Uri = partUri;
ContentType = contentType;
- CompressionLevel = compressionLevel;
+ SaveHandler = saveHandler;
}
- internal ZipPackage Package { get; set; }
-
- internal CompressionLevel CompressionLevel;
- private MemoryStream _stream;
-
- internal MemoryStream Stream {
- get => _stream;
- set => _stream = value;
- }
+ private ZipPackage Package { get; }
internal override ZipPackageRelationship CreateRelationship(
Uri targetUri,
@@ -77,20 +70,7 @@
}
internal MemoryStream GetStream() {
- return GetStream(FileMode.OpenOrCreate, FileAccess.ReadWrite);
- }
-
- internal MemoryStream GetStream(FileMode fileMode) {
- return GetStream(FileMode.Create, FileAccess.ReadWrite);
- }
-
- internal MemoryStream GetStream(FileMode fileMode, FileAccess fileAccess) {
- if (_stream == null || fileMode == FileMode.CreateNew || fileMode == FileMode.Create) {
- _stream = new();
- } else {
- _stream.Seek(0, SeekOrigin.Begin);
- }
- return _stream;
+ return new(ImmutableCollectionsMarshal.AsArray(_data) ?? [], false);
}
private string _contentType = "";
@@ -110,22 +90,18 @@
}
}
- public Uri Uri { get; private set; }
+ public Uri Uri { get; }
- internal SaveHandlerDelegate SaveHandler { get; set; }
+ internal Action<StreamWriter> SaveHandler { get; set; }
internal void WriteZip(ZipArchive zipArchive) {
- byte[] b;
if (SaveHandler == null) {
- b = GetStream().ToArray();
- if (b.Length
- == 0) //Make sure the file isn't empty. DotNetZip streams does not seems to handle zero sized files.
- {
+ if (_data.Length == 0) {
return;
}
var zipEntry = zipArchive.CreateEntry(Uri.OriginalString);
using var os = zipEntry.Open();
- os.Write(b);
+ os.Write(_data.AsSpan());
} else {
var zipEntry = zipArchive.CreateEntry(Uri.OriginalString);
using var streamWriter = new StreamWriter(zipEntry.Open());
@@ -137,11 +113,7 @@
var name = Path.GetFileName(f);
_rels.WriteZip(zipArchive, $"{f.Substring(0, f.Length - name.Length)}_rels/{name}.rels");
}
- b = null;
}
- public void Dispose() {
- _stream.Close();
- _stream.Dispose();
- }
+ public void Dispose() {}
}
diff --git a/EPPlus/Packaging/ZipPackageRelationship.cs b/EPPlus/Packaging/ZipPackageRelationship.cs
index 15c4539..1d76501 100644
--- a/EPPlus/Packaging/ZipPackageRelationship.cs
+++ b/EPPlus/Packaging/ZipPackageRelationship.cs
@@ -33,7 +33,7 @@
namespace OfficeOpenXml.Packaging;
-public class ZipPackageRelationship {
+internal class ZipPackageRelationship {
public Uri TargetUri { get; internal set; }
public Uri SourceUri { get; internal set; }
diff --git a/EPPlus/Packaging/ZipPackageRelationshipBase.cs b/EPPlus/Packaging/ZipPackageRelationshipBase.cs
index 882358e..ff9bf8f 100644
--- a/EPPlus/Packaging/ZipPackageRelationshipBase.cs
+++ b/EPPlus/Packaging/ZipPackageRelationshipBase.cs
@@ -35,7 +35,7 @@
namespace OfficeOpenXml.Packaging;
-public abstract class ZipPackageRelationshipBase {
+internal abstract class ZipPackageRelationshipBase {
protected ZipPackageRelationshipCollection _rels = new();
protected internal int maxRId = 1;
diff --git a/EPPlus/Packaging/ZipPackageRelationshipCollection.cs b/EPPlus/Packaging/ZipPackageRelationshipCollection.cs
index f828f61..7890ad6 100644
--- a/EPPlus/Packaging/ZipPackageRelationshipCollection.cs
+++ b/EPPlus/Packaging/ZipPackageRelationshipCollection.cs
@@ -38,7 +38,7 @@
namespace OfficeOpenXml.Packaging;
-public class ZipPackageRelationshipCollection : IEnumerable<ZipPackageRelationship> {
+internal class ZipPackageRelationshipCollection : IEnumerable<ZipPackageRelationship> {
protected internal Dictionary<string, ZipPackageRelationship> _rels = new(
StringComparer.InvariantCultureIgnoreCase);
diff --git a/EPPlus/Style/Dxf/DxfStyleBase.cs b/EPPlus/Style/Dxf/DxfStyleBase.cs
index 0c73cb0..b81e07a 100644
--- a/EPPlus/Style/Dxf/DxfStyleBase.cs
+++ b/EPPlus/Style/Dxf/DxfStyleBase.cs
@@ -8,7 +8,6 @@
internal DxfStyleBase(ExcelStyles styles) {
_styles = styles;
- AllowChange = false; //Don't touch this value in the styles.xml (by default). When Dxfs is fully implemented this can be removed.
}
protected internal abstract string Id { get; }
@@ -75,5 +74,5 @@
/// <summary>
/// Is this value allowed to be changed?
/// </summary>
- protected internal bool AllowChange { get; set; }
+ protected internal bool AllowChange { get; set; } = false;
}
diff --git a/EPPlus/Style/Dxf/ExcelDxfStyle.cs b/EPPlus/Style/Dxf/ExcelDxfStyle.cs
index 325d5b1..4784a1e 100644
--- a/EPPlus/Style/Dxf/ExcelDxfStyle.cs
+++ b/EPPlus/Style/Dxf/ExcelDxfStyle.cs
@@ -1,11 +1,22 @@
using System;
+using System.Collections.Immutable;
using System.Globalization;
using System.Xml;
namespace OfficeOpenXml.Style.Dxf;
public class ExcelDxfStyleConditionalFormatting : DxfStyleBase<ExcelDxfStyleConditionalFormatting> {
- private readonly XmlHelperInstance _helper;
+ private readonly DxfStyleXmlHelper _helper;
+
+ private class DxfStyleXmlHelper(XmlNamespaceManager nameSpaceManager, XmlNode topNode)
+ : XmlHelper(nameSpaceManager, topNode) {
+ protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
+ "font",
+ "numFmt",
+ "fill",
+ "border",
+ ];
+ }
internal ExcelDxfStyleConditionalFormatting(
XmlNamespaceManager nameSpaceManager,
@@ -40,12 +51,11 @@
Fill.BackgroundColor = GetColor(_helper, "d:fill/d:patternFill/d:bgColor/");
Fill.PatternColor = GetColor(_helper, "d:fill/d:patternFill/d:fgColor/");
} else {
- _helper = new(nameSpaceManager);
+ _helper = new(nameSpaceManager, null);
}
- _helper.SchemaNodeOrder = new[] { "font", "numFmt", "fill", "border" };
}
- private ExcelDxfBorderItem GetBorderItem(XmlHelperInstance helper, string path) {
+ private ExcelDxfBorderItem GetBorderItem(XmlHelper helper, string path) {
ExcelDxfBorderItem bi = new ExcelDxfBorderItem(_styles);
bi.Style = GetBorderStyleEnum(helper.GetXmlNodeString(path + "/@style"));
bi.Color = GetColor(helper, path + "/d:color");
@@ -58,7 +68,7 @@
private ExcelFillStyle GetPatternTypeEnum(string patternType) =>
Enum.TryParse<ExcelFillStyle>(patternType, true, out var result) ? result : ExcelFillStyle.None;
- private ExcelDxfColor GetColor(XmlHelperInstance helper, string path) {
+ private ExcelDxfColor GetColor(XmlHelper helper, string path) {
ExcelDxfColor ret = new ExcelDxfColor(_styles);
ret.Theme = helper.GetXmlNodeIntNull(path + "/@theme");
ret.Index = helper.GetXmlNodeIntNull(path + "/@indexed");
diff --git a/EPPlus/Style/ExcelBorderItem.cs b/EPPlus/Style/ExcelBorderItem.cs
index 6f8208b..89dc283 100644
--- a/EPPlus/Style/ExcelBorderItem.cs
+++ b/EPPlus/Style/ExcelBorderItem.cs
@@ -30,7 +30,6 @@
* Jan Källman License changed GPL-->LGPL 2011-12-16
*******************************************************************************/
-using System;
using OfficeOpenXml.Style.XmlAccess;
namespace OfficeOpenXml.Style;
diff --git a/EPPlus/Style/ExcelColor.cs b/EPPlus/Style/ExcelColor.cs
index 8725905..e02de45 100644
--- a/EPPlus/Style/ExcelColor.cs
+++ b/EPPlus/Style/ExcelColor.cs
@@ -30,7 +30,6 @@
* Jan Källman License changed GPL-->LGPL 2011-12-16
*******************************************************************************/
-using System;
using OfficeOpenXml.Style.XmlAccess;
namespace OfficeOpenXml.Style;
@@ -103,98 +102,4 @@
internal override void SetIndex(int index) {
_parent.Index = index;
}
-
- /// <summary>
- /// Return the RGB value for the color object that uses the Indexed or Tint property
- /// </summary>
- /// <param name="theColor">The color object</param>
- /// <returns>The RGB color starting with a #</returns>
- public string LookupColor(ExcelColor theColor) {
- //Thanks to neaves for contributing this method.
- int iTint = 0;
- string translatedRgb = "";
-
- // reference extracted from ECMA-376, Part 4, Section 3.8.26
- string[] rgbLookup = {
- "#FF000000", // 0
- "#FFFFFFFF",
- "#FFFF0000",
- "#FF00FF00",
- "#FF0000FF",
- "#FFFFFF00",
- "#FFFF00FF",
- "#FF00FFFF",
- "#FF000000", // 8
- "#FFFFFFFF",
- "#FFFF0000",
- "#FF00FF00",
- "#FF0000FF",
- "#FFFFFF00",
- "#FFFF00FF",
- "#FF00FFFF",
- "#FF800000",
- "#FF008000",
- "#FF000080",
- "#FF808000",
- "#FF800080",
- "#FF008080",
- "#FFC0C0C0",
- "#FF808080",
- "#FF9999FF",
- "#FF993366",
- "#FFFFFFCC",
- "#FFCCFFFF",
- "#FF660066",
- "#FFFF8080",
- "#FF0066CC",
- "#FFCCCCFF",
- "#FF000080",
- "#FFFF00FF",
- "#FFFFFF00",
- "#FF00FFFF",
- "#FF800080",
- "#FF800000",
- "#FF008080",
- "#FF0000FF",
- "#FF00CCFF",
- "#FFCCFFFF",
- "#FFCCFFCC",
- "#FFFFFF99",
- "#FF99CCFF",
- "#FFFF99CC",
- "#FFCC99FF",
- "#FFFFCC99",
- "#FF3366FF",
- "#FF33CCCC",
- "#FF99CC00",
- "#FFFFCC00",
- "#FFFF9900",
- "#FFFF6600",
- "#FF666699",
- "#FF969696",
- "#FF003366",
- "#FF339966",
- "#FF003300",
- "#FF333300",
- "#FF993300",
- "#FF993366",
- "#FF333399",
- "#FF333333", // 63
- };
-
- if ((0 <= theColor.Indexed) && (rgbLookup.Length > theColor.Indexed)) {
- // coloring by pre-set color codes
- translatedRgb = rgbLookup[theColor.Indexed];
- } else if (null != theColor.Rgb && 0 < theColor.Rgb.Length) {
- // coloring by RGB value ("FFRRGGBB")
- translatedRgb = "#" + theColor.Rgb;
- } else {
- // coloring by shades of grey (-1 -> 0)
- iTint = ((int)(theColor.Tint * 160) + 0x80);
- translatedRgb = ((int)(decimal.Round(theColor.Tint * -512))).ToString("X");
- translatedRgb = "#FF" + translatedRgb + translatedRgb + translatedRgb;
- }
-
- return translatedRgb;
- }
}
diff --git a/EPPlus/Style/ExcelGradientFill.cs b/EPPlus/Style/ExcelGradientFill.cs
index 7103b37..4ab355e 100644
--- a/EPPlus/Style/ExcelGradientFill.cs
+++ b/EPPlus/Style/ExcelGradientFill.cs
@@ -30,7 +30,6 @@
* Jan Källman License changed GPL-->LGPL 2011-12-16
*******************************************************************************/
-using System;
using OfficeOpenXml.Style.XmlAccess;
namespace OfficeOpenXml.Style;
diff --git a/EPPlus/Style/ExcelParagraph.cs b/EPPlus/Style/ExcelParagraph.cs
deleted file mode 100644
index a758a83..0000000
--- a/EPPlus/Style/ExcelParagraph.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-/*******************************************************************************
- * 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 2009-10-01
- * Jan Källman License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System.Xml;
-
-namespace OfficeOpenXml.Style;
-
-/// <summary>
-/// Handels paragraph text
-/// </summary>
-public sealed class ExcelParagraph : ExcelTextFont {
- public ExcelParagraph(
- XmlNamespaceManager ns,
- XmlNode rootNode,
- string path,
- string[] schemaNodeOrder)
- : base(ns, rootNode, path + "a:rPr", schemaNodeOrder) {}
-
- private const string _textPath = "../a:t";
-
- /// <summary>
- /// Text
- /// </summary>
- public string Text {
- get => GetXmlNodeString(_textPath);
- set {
- CreateTopNode();
- SetXmlNodeString(_textPath, value);
- }
- }
-}
diff --git a/EPPlus/Style/ExcelParagraphCollection.cs b/EPPlus/Style/ExcelParagraphCollection.cs
deleted file mode 100644
index a74fe57..0000000
--- a/EPPlus/Style/ExcelParagraphCollection.cs
+++ /dev/null
@@ -1,145 +0,0 @@
-/*******************************************************************************
- * 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 2009-10-01
- * Jan Källman License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System.Collections;
-using System.Collections.Generic;
-using System.Text;
-using System.Xml;
-
-namespace OfficeOpenXml.Style;
-
-/// <summary>
-/// A collection of Paragraph objects
-/// </summary>
-public class ExcelParagraphCollection : XmlHelper, IEnumerable<ExcelParagraph> {
- private readonly List<ExcelParagraph> _list = new();
- private readonly string _path;
-
- internal ExcelParagraphCollection(
- XmlNamespaceManager ns,
- XmlNode topNode,
- string path,
- string[] schemaNodeOrder)
- : base(ns, topNode) {
- var nl = topNode.SelectNodes(path + "/a:r", NameSpaceManager);
- SchemaNodeOrder = schemaNodeOrder;
- if (nl != null) {
- foreach (XmlNode n in nl) {
- _list.Add(new(ns, n, "", schemaNodeOrder));
- }
- }
- _path = path;
- }
-
- public ExcelParagraph this[int index] => _list[index];
-
- public int Count => _list.Count;
-
- /// <summary>
- /// Add a rich text string
- /// </summary>
- /// <param name="text">The text to add</param>
- /// <returns></returns>
- public ExcelParagraph Add(string text) {
- XmlDocument doc;
- if (TopNode is XmlDocument document) {
- doc = document;
- } else {
- doc = TopNode.OwnerDocument;
- }
- XmlNode parentNode = TopNode.SelectSingleNode(_path, NameSpaceManager);
- if (parentNode == null) {
- CreateNode(_path);
- parentNode = TopNode.SelectSingleNode(_path, NameSpaceManager);
- }
-
- var node = doc.CreateElement("a", "r", ExcelPackage._schemaDrawings);
- parentNode.AppendChild(node);
- var childNode = doc.CreateElement("a", "rPr", ExcelPackage._schemaDrawings);
- node.AppendChild(childNode);
- var rt = new ExcelParagraph(NameSpaceManager, node, "", SchemaNodeOrder);
- rt.ComplexFont = "Calibri";
- rt.LatinFont = "Calibri";
- rt.Size = 11;
-
- rt.Text = text;
- _list.Add(rt);
- return rt;
- }
-
- public void Clear() {
- _list.Clear();
- TopNode.RemoveAll();
- }
-
- public void RemoveAt(int index) {
- var node = _list[index].TopNode;
- while (node != null && node.Name != "a:r") {
- node = node.ParentNode;
- }
- node.ParentNode.RemoveChild(node);
- _list.RemoveAt(index);
- }
-
- public void Remove(ExcelRichText item) {
- TopNode.RemoveChild(item.TopNode);
- }
-
- public string Text {
- get {
- StringBuilder sb = new StringBuilder();
- foreach (var item in _list) {
- sb.Append(item.Text);
- }
- return sb.ToString();
- }
- set {
- if (Count == 0) {
- Add(value);
- } else {
- this[0].Text = value;
- int count = Count;
- for (int ix = Count - 1; ix > 0; ix--) {
- RemoveAt(ix);
- }
- }
- }
- }
-
- IEnumerator<ExcelParagraph> IEnumerable<ExcelParagraph>.GetEnumerator() {
- return _list.GetEnumerator();
- }
-
- IEnumerator IEnumerable.GetEnumerator() {
- return _list.GetEnumerator();
- }
-}
diff --git a/EPPlus/Style/ExcelRichText.cs b/EPPlus/Style/ExcelRichText.cs
index 2458430..3e9994e 100644
--- a/EPPlus/Style/ExcelRichText.cs
+++ b/EPPlus/Style/ExcelRichText.cs
@@ -33,6 +33,7 @@
*******************************************************************************/
using System;
+using System.Collections.Immutable;
using System.Globalization;
using System.Xml;
@@ -42,26 +43,27 @@
/// A richtext part
/// </summary>
public class ExcelRichText : XmlHelper {
+ protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
+ "rPr",
+ "t",
+ "b",
+ "i",
+ "strike",
+ "u",
+ "vertAlign",
+ "sz",
+ "color",
+ "rFont",
+ "family",
+ "scheme",
+ "charset",
+ ];
+
internal ExcelRichText(
XmlNamespaceManager ns,
XmlNode topNode,
ExcelRichTextCollection collection)
: base(ns, topNode) {
- SchemaNodeOrder = new[] {
- "rPr",
- "t",
- "b",
- "i",
- "strike",
- "u",
- "vertAlign",
- "sz",
- "color",
- "rFont",
- "family",
- "scheme",
- "charset",
- };
_collection = collection;
}
diff --git a/EPPlus/Style/ExcelRichTextCollection.cs b/EPPlus/Style/ExcelRichTextCollection.cs
index 62925f7..21f4803 100644
--- a/EPPlus/Style/ExcelRichTextCollection.cs
+++ b/EPPlus/Style/ExcelRichTextCollection.cs
@@ -32,7 +32,6 @@
using System.Collections;
using System.Collections.Generic;
-using System.Globalization;
using System.Linq;
using System.Text;
using System.Xml;
diff --git a/EPPlus/Style/ExcelStyle.cs b/EPPlus/Style/ExcelStyle.cs
index 3292c7b..088b8c3 100644
--- a/EPPlus/Style/ExcelStyle.cs
+++ b/EPPlus/Style/ExcelStyle.cs
@@ -30,7 +30,6 @@
* Jan Källman License changed GPL-->LGPL 2011-12-16
*******************************************************************************/
-using System;
using OfficeOpenXml.Style.XmlAccess;
namespace OfficeOpenXml.Style;
diff --git a/EPPlus/Style/ExcelTextFont.cs b/EPPlus/Style/ExcelTextFont.cs
deleted file mode 100644
index 9252413..0000000
--- a/EPPlus/Style/ExcelTextFont.cs
+++ /dev/null
@@ -1,222 +0,0 @@
-/*******************************************************************************
- * 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 2009-10-01
- * Jan Källman License changed GPL-->LGPL 2011-12-16
- *******************************************************************************/
-
-using System;
-using System.Globalization;
-using System.Xml;
-
-namespace OfficeOpenXml.Style;
-
-/// <summary>
-/// Linestyle
-/// </summary>
-public enum eUnderLineType {
- Dash,
- DashHeavy,
- DashLong,
- DashLongHeavy,
- Double,
- DotDash,
- DotDashHeavy,
- DotDotDash,
- DotDotDashHeavy,
- Dotted,
- DottedHeavy,
- Heavy,
- None,
- Single,
- Wavy,
- WavyDbl,
- WavyHeavy,
- Words,
-}
-
-/// <summary>
-/// Type of font strike
-/// </summary>
-public enum eStrikeType {
- Double,
- No,
- Single,
-}
-
-/// <summary>
-/// Used by Rich-text and Paragraphs.
-/// </summary>
-public class ExcelTextFont : XmlHelper {
- private readonly string _path;
- private readonly XmlNode _rootNode;
-
- internal ExcelTextFont(
- XmlNamespaceManager namespaceManager,
- XmlNode rootNode,
- string path,
- string[] schemaNodeOrder)
- : base(namespaceManager, rootNode) {
- SchemaNodeOrder = schemaNodeOrder;
- _rootNode = rootNode;
- if (path != "") {
- XmlNode node = rootNode.SelectSingleNode(path, namespaceManager);
- if (node != null) {
- TopNode = node;
- }
- }
- _path = path;
- }
-
- private readonly string _fontLatinPath = "a:latin/@typeface";
-
- public string LatinFont {
- get => GetXmlNodeString(_fontLatinPath);
- set {
- CreateTopNode();
- SetXmlNodeString(_fontLatinPath, value);
- }
- }
-
- protected internal void CreateTopNode() {
- if (_path != "" && TopNode == _rootNode) {
- CreateNode(_path);
- TopNode = _rootNode.SelectSingleNode(_path, NameSpaceManager);
- }
- }
-
- private readonly string _fontCsPath = "a:cs/@typeface";
-
- public string ComplexFont {
- get => GetXmlNodeString(_fontCsPath);
- set {
- CreateTopNode();
- SetXmlNodeString(_fontCsPath, value);
- }
- }
-
- private readonly string _boldPath = "@b";
-
- public bool Bold {
- get => GetXmlNodeBool(_boldPath);
- set {
- CreateTopNode();
- SetXmlNodeString(_boldPath, value ? "1" : "0");
- }
- }
-
- private readonly string _underLinePath = "@u";
-
- public eUnderLineType UnderLine {
- get => TranslateUnderline(GetXmlNodeString(_underLinePath));
- set {
- CreateTopNode();
- SetXmlNodeString(_underLinePath, TranslateUnderlineText(value));
- }
- }
-
- private readonly string _italicPath = "@i";
-
- public bool Italic {
- get => GetXmlNodeBool(_italicPath);
- set {
- CreateTopNode();
- SetXmlNodeString(_italicPath, value ? "1" : "0");
- }
- }
-
- private readonly string _strikePath = "@strike";
-
- public eStrikeType Strike {
- get => TranslateStrike(GetXmlNodeString(_strikePath));
- set {
- CreateTopNode();
- SetXmlNodeString(_strikePath, TranslateStrikeText(value));
- }
- }
-
- private readonly string _sizePath = "@sz";
-
- public float Size {
- get => GetXmlNodeInt(_sizePath) / 100;
- set {
- CreateTopNode();
- SetXmlNodeString(_sizePath, ((int)(value * 100)).ToString());
- }
- }
-
- private eUnderLineType TranslateUnderline(string text) {
- switch (text) {
- case "sng":
- return eUnderLineType.Single;
- case "dbl":
- return eUnderLineType.Double;
- case "":
- return eUnderLineType.None;
- default:
- return Enum.TryParse<eUnderLineType>(text, true, out var result)
- ? result
- : eUnderLineType.None;
- }
- }
-
- private string TranslateUnderlineText(eUnderLineType value) {
- switch (value) {
- case eUnderLineType.Single:
- return "sng";
- case eUnderLineType.Double:
- return "dbl";
- default:
- string ret = value.ToString();
- return ret.Substring(0, 1).ToLower(CultureInfo.InvariantCulture)
- + ret.Substring(1, ret.Length - 1);
- }
- }
-
- private eStrikeType TranslateStrike(string text) {
- switch (text) {
- case "dblStrike":
- return eStrikeType.Double;
- case "sngStrike":
- return eStrikeType.Single;
- default:
- return eStrikeType.No;
- }
- }
-
- private string TranslateStrikeText(eStrikeType value) {
- switch (value) {
- case eStrikeType.Single:
- return "sngStrike";
- case eStrikeType.Double:
- return "dblStrike";
- default:
- return "noStrike";
- }
- }
-}
diff --git a/EPPlus/Style/XmlAccess/ExcelNumberFormatXml.cs b/EPPlus/Style/XmlAccess/ExcelNumberFormatXml.cs
index 6e5d10d..c67aed9 100644
--- a/EPPlus/Style/XmlAccess/ExcelNumberFormatXml.cs
+++ b/EPPlus/Style/XmlAccess/ExcelNumberFormatXml.cs
@@ -357,11 +357,8 @@
internal string NetFormatForWidth { get; private set; }
- //internal string FractionFormatInteger { get; private set; }
internal string FractionFormat { get; private set; }
- //internal string FractionFormat2 { get; private set; }
-
private void ToNetFormat(string excelFormat, bool forColWidth) {
DataType = eFormatType.Unknown;
int secCount = 0;
@@ -372,7 +369,6 @@
bool useMinute = false;
bool prevUnderScore = false;
bool ignoreNext = false;
- int fractionPos = -1;
string specialDateFormat = "";
bool containsAmPm = excelFormat.Contains("AM/PM");
List<int> lstDec = new List<int>();
@@ -511,7 +507,6 @@
sb.Append(' ');
} else if (c == '/') {
if (DataType == eFormatType.Number) {
- fractionPos = sb.Length;
int startPos = pos - 1;
while (startPos >= 0
&& (excelFormat[startPos] == '?'
diff --git a/EPPlus/Table/ExcelTable.cs b/EPPlus/Table/ExcelTable.cs
index 2438154..674bb73 100644
--- a/EPPlus/Table/ExcelTable.cs
+++ b/EPPlus/Table/ExcelTable.cs
@@ -32,9 +32,7 @@
using System;
using System.Collections.Generic;
-using System.Security;
-using System.Text;
-using System.Text.RegularExpressions;
+using System.Collections.Immutable;
using System.Xml;
using OfficeOpenXml.Packaging;
using OfficeOpenXml.Utils;
@@ -113,101 +111,37 @@
/// An Excel Table
/// </summary>
public class ExcelTable : XmlHelper, IEqualityComparer<ExcelTable> {
+ protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
+ "autoFilter",
+ "tableColumns",
+ "tableStyleInfo",
+ ];
+
internal ExcelTable(ZipPackageRelationship rel, ExcelWorksheet sheet)
: base(sheet.NameSpaceManager) {
WorkSheet = sheet;
TableUri = UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri);
RelationshipID = rel.Id;
- var pck = sheet._package.Package;
- Part = pck.GetPart(TableUri);
-
- TableXml = new();
- LoadXmlSafe(TableXml, Part.GetStream());
- Init();
+ TableXml = sheet._package.GetXmlDocument(TableUri);
+ TopNode = TableXml.DocumentElement;
Address = new(GetXmlNodeString("@ref"));
}
- internal ExcelTable(ExcelWorksheet sheet, ExcelAddressBase address, string name, int tblId)
- : base(sheet.NameSpaceManager) {
- WorkSheet = sheet;
- Address = address;
- TableXml = new();
- LoadXmlSafe(TableXml, GetStartXml(name, tblId), Encoding.UTF8);
- TopNode = TableXml.DocumentElement;
-
- Init();
-
- //If the table is just one row we can not have a header.
- if (address._fromRow == address._toRow) {
- ShowHeader = false;
- }
- }
-
- private void Init() {
- TopNode = TableXml.DocumentElement;
- SchemaNodeOrder = new[] { "autoFilter", "tableColumns", "tableStyleInfo" };
- }
-
- private string GetStartXml(string name, int tblId) {
- string xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>";
- xml += string.Format(
- "<table xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" id=\"{0}\" name=\"{1}\" displayName=\"{2}\" ref=\"{3}\" headerRowCount=\"1\">",
- tblId,
- name,
- CleanDisplayName(name),
- Address.Address);
- xml += string.Format("<autoFilter ref=\"{0}\" />", Address.Address);
-
- int cols = Address._toCol - Address._fromCol + 1;
- xml += string.Format("<tableColumns count=\"{0}\">", cols);
- var names = new Dictionary<string, string>();
- for (int i = 1; i <= cols; i++) {
- var cell = WorkSheet.Cells[Address._fromRow, Address._fromCol + i - 1];
- string colName;
- if (cell.Value == null || names.ContainsKey(cell.Value.ToString())) {
- //Get an unique name
- int a = i;
- do {
- colName = string.Format("Column{0}", a++);
- } while (names.ContainsKey(colName));
- } else {
- colName = SecurityElement.Escape(cell.Value.ToString());
- }
- names.Add(colName, colName);
- xml += string.Format("<tableColumn id=\"{0}\" name=\"{1}\" />", i, colName);
- }
- xml += "</tableColumns>";
- xml +=
- "<tableStyleInfo name=\"TableStyleMedium9\" showFirstColumn=\"0\" showLastColumn=\"0\" showRowStripes=\"1\" showColumnStripes=\"0\" /> ";
- xml += "</table>";
-
- return xml;
- }
-
- private string CleanDisplayName(string name) {
- return Regex.Replace(name, @"[^\w\.-_]", "_");
- }
-
- internal ZipPackagePart Part { get; set; }
-
/// <summary>
/// Provides access to the XML data representing the table in the package.
/// </summary>
- public XmlDocument TableXml { get; set; }
+ internal XmlDocument TableXml { get; }
/// <summary>
/// The package internal URI to the Table Xml Document.
/// </summary>
- public Uri TableUri { get; internal set; }
+ private Uri TableUri { get; }
internal string RelationshipID { get; set; }
private const string _idPath = "@id";
- internal int Id {
- get => GetXmlNodeInt(_idPath);
- set => SetXmlNodeString(_idPath, value.ToString());
- }
+ internal int Id => GetXmlNodeInt(_idPath);
private const string _namePath = "@name";
private const string _displayNamePath = "@displayName";
@@ -215,27 +149,12 @@
/// <summary>
/// The name of the table object in Excel
/// </summary>
- public string Name {
- get => GetXmlNodeString(_namePath);
- set {
- if (WorkSheet.Workbook.ExistsTableName(value)) {
- throw (new ArgumentException("Tablename is not unique"));
- }
- string prevName = Name;
- if (WorkSheet.Tables._tableNames.ContainsKey(prevName)) {
- int ix = WorkSheet.Tables._tableNames[prevName];
- WorkSheet.Tables._tableNames.Remove(prevName);
- WorkSheet.Tables._tableNames.Add(value, ix);
- }
- SetXmlNodeString(_namePath, value);
- SetXmlNodeString(_displayNamePath, CleanDisplayName(value));
- }
- }
+ public string Name => GetXmlNodeString(_namePath);
/// <summary>
/// The worksheet of the table
/// </summary>
- public ExcelWorksheet WorkSheet { get; set; }
+ public ExcelWorksheet WorkSheet { get; }
private ExcelAddressBase _address;
@@ -265,21 +184,6 @@
}
}
- private TableStyles _tableStyle = TableStyles.Medium6;
-
- /// <summary>
- /// The table style. If this property is cusom, the style from the StyleName propery is used.
- /// </summary>
- public TableStyles TableStyle {
- get => _tableStyle;
- set {
- _tableStyle = value;
- if (value != TableStyles.Custom) {
- SetXmlNodeString(_stylenamePath, "TableStyle" + value);
- }
- }
- }
-
private const string _headerrowcountPath = "@headerRowCount";
private const string _autofilterPath = "d:autoFilter/@ref";
@@ -341,21 +245,7 @@
/// <summary>
/// If the header row has an autofilter
/// </summary>
- public bool ShowFilter {
- get => ShowHeader && AutoFilterAddress != null;
- set {
- if (ShowHeader) {
- if (value) {
- WriteAutoFilter(ShowTotal);
- } else {
- DeleteAllNode(_autofilterPath);
- }
- } else if (value) {
- throw (new InvalidOperationException(
- "Filter can only be applied when ShowHeader is set to true"));
- }
- }
- }
+ public bool ShowFilter => ShowHeader && AutoFilterAddress != null;
private const string _totalsrowcountPath = "@totalsRowCount";
@@ -399,131 +289,56 @@
/// <summary>
/// The style name for custum styles
/// </summary>
- public string StyleName {
- get => GetXmlNodeString(_stylenamePath);
- set {
- if (value.StartsWith("TableStyle")) {
- try {
- _tableStyle = (TableStyles)
- Enum.Parse(typeof(TableStyles), value.Substring(10, value.Length - 10), true);
- } catch {
- _tableStyle = TableStyles.Custom;
- }
- } else if (value == "None") {
- _tableStyle = TableStyles.None;
- value = "";
- } else {
- _tableStyle = TableStyles.Custom;
- }
- SetXmlNodeString(_stylenamePath, value, true);
- }
- }
+ public string StyleName => GetXmlNodeString(_stylenamePath);
private const string _showfirstcolumnPath = "d:tableStyleInfo/@showFirstColumn";
/// <summary>
/// Display special formatting for the first row
/// </summary>
- public bool ShowFirstColumn {
- get => GetXmlNodeBool(_showfirstcolumnPath);
- set => SetXmlNodeBool(_showfirstcolumnPath, value, false);
- }
+ public bool ShowFirstColumn => GetXmlNodeBool(_showfirstcolumnPath);
private const string _showlastcolumnPath = "d:tableStyleInfo/@showLastColumn";
/// <summary>
/// Display special formatting for the last row
/// </summary>
- public bool ShowLastColumn {
- get => GetXmlNodeBool(_showlastcolumnPath);
- set => SetXmlNodeBool(_showlastcolumnPath, value, false);
- }
+ public bool ShowLastColumn => GetXmlNodeBool(_showlastcolumnPath);
private const string _showrowstripesPath = "d:tableStyleInfo/@showRowStripes";
/// <summary>
/// Display banded rows
/// </summary>
- public bool ShowRowStripes {
- get => GetXmlNodeBool(_showrowstripesPath);
- set => SetXmlNodeBool(_showrowstripesPath, value, false);
- }
+ public bool ShowRowStripes => GetXmlNodeBool(_showrowstripesPath);
private const string _showcolumnstripesPath = "d:tableStyleInfo/@showColumnStripes";
/// <summary>
/// Display banded columns
/// </summary>
- public bool ShowColumnStripes {
- get => GetXmlNodeBool(_showcolumnstripesPath);
- set => SetXmlNodeBool(_showcolumnstripesPath, value, false);
- }
+ public bool ShowColumnStripes => GetXmlNodeBool(_showcolumnstripesPath);
private const string _totalsrowcellstylePath = "@totalsRowCellStyle";
/// <summary>
/// Named style used for the total row
/// </summary>
- public string TotalsRowCellStyle {
- get => GetXmlNodeString(_totalsrowcellstylePath);
- set {
- if (WorkSheet.Workbook.Styles.NamedStyles.FindIndexById(value) < 0) {
- throw (new(string.Format("Named style {0} does not exist.", value)));
- }
- SetXmlNodeString(TopNode, _totalsrowcellstylePath, value, true);
-
- if (ShowTotal) {
- WorkSheet.Cells[Address._toRow,
- Address._fromCol,
- Address._toRow,
- Address._toCol].StyleName = value;
- }
- }
- }
+ public string TotalsRowCellStyle => GetXmlNodeString(_totalsrowcellstylePath);
private const string _datacellstylePath = "@dataCellStyle";
/// <summary>
/// Named style used for the data cells
/// </summary>
- public string DataCellStyleName {
- get => GetXmlNodeString(_datacellstylePath);
- set {
- if (WorkSheet.Workbook.Styles.NamedStyles.FindIndexById(value) < 0) {
- throw (new(string.Format("Named style {0} does not exist.", value)));
- }
- SetXmlNodeString(TopNode, _datacellstylePath, value, true);
-
- int fromRow = Address._fromRow + (ShowHeader ? 1 : 0),
- toRow = Address._toRow - (ShowTotal ? 1 : 0);
-
- if (fromRow < toRow) {
- WorkSheet.Cells[fromRow, Address._fromCol, toRow, Address._toCol].StyleName = value;
- }
- }
- }
+ public string DataCellStyleName => GetXmlNodeString(_datacellstylePath);
private const string _headerrowcellstylePath = "@headerRowCellStyle";
/// <summary>
/// Named style used for the header row
/// </summary>
- public string HeaderRowCellStyle {
- get => GetXmlNodeString(_headerrowcellstylePath);
- set {
- if (WorkSheet.Workbook.Styles.NamedStyles.FindIndexById(value) < 0) {
- throw (new(string.Format("Named style {0} does not exist.", value)));
- }
- SetXmlNodeString(TopNode, _headerrowcellstylePath, value, true);
-
- if (ShowHeader) {
- WorkSheet.Cells[Address._fromRow,
- Address._fromCol,
- Address._fromRow,
- Address._toCol].StyleName = value;
- }
- }
- }
+ public string HeaderRowCellStyle => GetXmlNodeString(_headerrowcellstylePath);
public bool Equals(ExcelTable x, ExcelTable y) {
return x.WorkSheet == y.WorkSheet && x.Id == y.Id && x.TableXml.OuterXml == y.TableXml.OuterXml;
diff --git a/EPPlus/Table/ExcelTableCollection.cs b/EPPlus/Table/ExcelTableCollection.cs
index 75c255d..5a7941c 100644
--- a/EPPlus/Table/ExcelTableCollection.cs
+++ b/EPPlus/Table/ExcelTableCollection.cs
@@ -58,95 +58,6 @@
}
}
- private ExcelTable Add(ExcelTable tbl) {
- _tables.Add(tbl);
- _tableNames.Add(tbl.Name, _tables.Count - 1);
- if (tbl.Id >= _ws.Workbook._nextTableID) {
- _ws.Workbook._nextTableID = tbl.Id + 1;
- }
- return tbl;
- }
-
- /// <summary>
- /// Create a table on the supplied range
- /// </summary>
- /// <param name="range">The range address including header and total row</param>
- /// <param name="name">The name of the table. Must be unique </param>
- /// <returns>The table object</returns>
- public ExcelTable Add(ExcelAddressBase range, string name) {
- if (range.WorkSheet != null && range.WorkSheet != _ws.Name) {
- throw new ArgumentException("Range does not belong to worksheet", "range");
- }
-
- if (string.IsNullOrEmpty(name)) {
- name = GetNewTableName();
- } else if (_ws.Workbook.ExistsTableName(name)) {
- throw (new ArgumentException("Tablename is not unique"));
- }
-
- ValidateTableName(name);
-
- foreach (var t in _tables) {
- if (t.Address.Collide(range) != ExcelAddressBase.eAddressCollition.No) {
- throw (new ArgumentException(string.Format("Table range collides with table {0}", t.Name)));
- }
- }
- return Add(new(_ws, range, name, _ws.Workbook._nextTableID));
- }
-
- private void ValidateTableName(string name) {
- if (string.IsNullOrEmpty(name)) {
- throw new ArgumentException("Tablename is null or empty");
- }
-
- char firstLetterOfName = name[0];
- if (Char.IsLetter(firstLetterOfName) == false
- && firstLetterOfName != '_'
- && firstLetterOfName != '\\') {
- throw new ArgumentException("Tablename start with invalid character");
- }
-
- if (name.Contains(" ")) {
- throw new ArgumentException("Tablename has spaces");
- }
- }
-
- public void Delete(int index, bool clearRange = false) {
- Delete(this[index], clearRange);
- }
-
- public void Delete(string name, bool clearRange = false) {
- if (this[name] == null) {
- throw new ArgumentOutOfRangeException(
- string.Format("Cannot delete non-existant table {0} in sheet {1}.", name, _ws.Name));
- }
- Delete(this[name], clearRange);
- }
-
- public void Delete(ExcelTable excelTable, bool clearRange = false) {
- if (!_tables.Contains(excelTable)) {
- throw new ArgumentOutOfRangeException(
- "excelTable",
- String.Format("Table {0} does not exist in this collection", excelTable.Name));
- }
- lock (this) {
- var range = _ws.Cells[excelTable.Address.Address];
- _tableNames.Remove(excelTable.Name);
- _tables.Remove(excelTable);
- foreach (var sheet in excelTable.WorkSheet.Workbook.Worksheets) {
- foreach (var table in sheet.Tables) {
- if (table.Id > excelTable.Id) {
- table.Id--;
- }
- }
- excelTable.WorkSheet.Workbook._nextTableID--;
- }
- if (clearRange) {
- range.Clear();
- }
- }
- }
-
internal string GetNewTableName() {
string name = "Table1";
int i = 2;
diff --git a/EPPlus/Table/ExcelTableColumnCollection.cs b/EPPlus/Table/ExcelTableColumnCollection.cs
index 57d59d8..e74adbe 100644
--- a/EPPlus/Table/ExcelTableColumnCollection.cs
+++ b/EPPlus/Table/ExcelTableColumnCollection.cs
@@ -104,7 +104,7 @@
internal string GetUniqueName(string name) {
if (_colNames.ContainsKey(name)) {
- var newName = name;
+ string newName;
var i = 2;
do {
newName = name + (i++).ToString(CultureInfo.InvariantCulture);
diff --git a/EPPlus/Table/PivotTable/ExcelPivotCacheDefinition.cs b/EPPlus/Table/PivotTable/ExcelPivotCacheDefinition.cs
index d25001f..44543ee 100644
--- a/EPPlus/Table/PivotTable/ExcelPivotCacheDefinition.cs
+++ b/EPPlus/Table/PivotTable/ExcelPivotCacheDefinition.cs
@@ -32,7 +32,6 @@
using System;
using System.Linq;
-using System.Text;
using System.Xml;
using OfficeOpenXml.Packaging;
using OfficeOpenXml.Utils;
@@ -75,7 +74,6 @@
var pck = pivotTable.WorkSheet._package.Package;
Part = pck.GetPart(CacheDefinitionUri);
- CacheDefinitionXml = new();
LoadXmlSafe(CacheDefinitionXml, Part.GetStream());
TopNode = CacheDefinitionXml.DocumentElement;
@@ -91,40 +89,6 @@
}
}
- internal ExcelPivotCacheDefinition(
- XmlNamespaceManager ns,
- ExcelPivotTable pivotTable,
- ExcelRangeBase sourceAddress,
- int tblId)
- : base(ns, null) {
- PivotTable = pivotTable;
-
- var pck = pivotTable.WorkSheet._package.Package;
-
- //CacheDefinition
- CacheDefinitionXml = new();
- LoadXmlSafe(CacheDefinitionXml, GetStartXml(sourceAddress), Encoding.UTF8);
- CacheDefinitionUri = GetNewUri(pck, "/xl/pivotCache/pivotCacheDefinition{0}.xml", tblId);
- Part = pck.CreatePart(CacheDefinitionUri, ExcelPackage._schemaPivotCacheDefinition);
- TopNode = CacheDefinitionXml.DocumentElement;
-
- //CacheRecord. Create an empty one.
- CacheRecordUri = GetNewUri(pck, "/xl/pivotCache/pivotCacheRecords{0}.xml", tblId);
- var cacheRecord = new XmlDocument();
- cacheRecord.LoadXml(
- "<pivotCacheRecords xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" count=\"0\" />");
- var recPart = pck.CreatePart(CacheRecordUri, ExcelPackage._schemaPivotCacheRecords);
- cacheRecord.Save(recPart.GetStream());
-
- RecordRelationship = Part.CreateRelationship(
- UriHelper.ResolvePartUri(CacheDefinitionUri, CacheRecordUri),
- TargetMode.Internal,
- ExcelPackage._schemaRelationships + "/pivotCacheRecords");
- RecordRelationshipID = RecordRelationship.Id;
-
- CacheDefinitionXml.Save(Part.GetStream());
- }
-
/// <summary>
/// Reference to the internal package part
/// </summary>
@@ -133,7 +97,7 @@
/// <summary>
/// Provides access to the XML data representing the cache definition in the package.
/// </summary>
- public XmlDocument CacheDefinitionXml { get; private set; }
+ public XmlDocument CacheDefinitionXml { get; private set; } = new();
/// <summary>
/// The package internal URI to the pivottable cache definition Xml Document.
diff --git a/EPPlus/Table/PivotTable/ExcelPivotTable.cs b/EPPlus/Table/PivotTable/ExcelPivotTable.cs
index 6ea4244..47031ca 100644
--- a/EPPlus/Table/PivotTable/ExcelPivotTable.cs
+++ b/EPPlus/Table/PivotTable/ExcelPivotTable.cs
@@ -31,7 +31,7 @@
*******************************************************************************/
using System;
-using System.Text;
+using System.Collections.Immutable;
using System.Text.RegularExpressions;
using System.Xml;
using OfficeOpenXml.Packaging;
@@ -43,21 +43,32 @@
/// An Excel Pivottable
/// </summary>
public class ExcelPivotTable : XmlHelper {
+ protected override ImmutableArray<string> SchemaNodeOrder { get; } = [
+ "location",
+ "pivotFields",
+ "rowFields",
+ "rowItems",
+ "colFields",
+ "colItems",
+ "pageFields",
+ "pageItems",
+ "dataFields",
+ "dataItems",
+ "formats",
+ "pivotTableStyleInfo",
+ ];
+
internal ExcelPivotTable(ZipPackageRelationship rel, ExcelWorksheet sheet)
: base(sheet.NameSpaceManager) {
WorkSheet = sheet;
PivotTableUri = UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri);
Relationship = rel;
- var pck = sheet._package.Package;
- Part = pck.GetPart(PivotTableUri);
-
- PivotTableXml = new();
- LoadXmlSafe(PivotTableXml, Part.GetStream());
- Init();
+ var package = sheet._package;
+ PivotTableXml = package.GetXmlDocument(PivotTableUri);
TopNode = PivotTableXml.DocumentElement;
Address = new(GetXmlNodeString("d:location/@ref"));
- _cacheDefinition = new(sheet.NameSpaceManager, this);
+ CacheDefinition = new(sheet.NameSpaceManager, this);
LoadFields();
//Add row fields.
@@ -103,72 +114,6 @@
}
}
- /// <summary>
- /// Add a new pivottable
- /// </summary>
- /// <param name="sheet">The worksheet</param>
- /// <param name="address">the address of the pivottable</param>
- /// <param name="sourceAddress">The address of the Source data</param>
- /// <param name="name"></param>
- /// <param name="tblId"></param>
- internal ExcelPivotTable(
- ExcelWorksheet sheet,
- ExcelAddressBase address,
- ExcelRangeBase sourceAddress,
- string name,
- int tblId)
- : base(sheet.NameSpaceManager) {
- WorkSheet = sheet;
- Address = address;
- var pck = sheet._package.Package;
-
- PivotTableXml = new();
- LoadXmlSafe(PivotTableXml, GetStartXml(name, tblId, address, sourceAddress), Encoding.UTF8);
- TopNode = PivotTableXml.DocumentElement;
- PivotTableUri = GetNewUri(pck, "/xl/pivotTables/pivotTable{0}.xml", tblId);
- Init();
-
- Part = pck.CreatePart(PivotTableUri, ExcelPackage._schemaPivotTable);
- PivotTableXml.Save(Part.GetStream());
-
- //Worksheet-Pivottable relationship
- Relationship = sheet.Part.CreateRelationship(
- UriHelper.ResolvePartUri(sheet.WorksheetUri, PivotTableUri),
- TargetMode.Internal,
- ExcelPackage._schemaRelationships + "/pivotTable");
-
- _cacheDefinition = new(sheet.NameSpaceManager, this, sourceAddress, tblId);
- _cacheDefinition.Relationship = Part.CreateRelationship(
- UriHelper.ResolvePartUri(PivotTableUri, _cacheDefinition.CacheDefinitionUri),
- TargetMode.Internal,
- ExcelPackage._schemaRelationships + "/pivotCacheDefinition");
-
- sheet.Workbook.AddPivotTable(CacheID.ToString(), _cacheDefinition.CacheDefinitionUri);
-
- LoadFields();
-
- using (var r = sheet.Cells[address.Address]) {
- r.Clear();
- }
- }
-
- private void Init() {
- SchemaNodeOrder = new[] {
- "location",
- "pivotFields",
- "rowFields",
- "rowItems",
- "colFields",
- "colItems",
- "pageFields",
- "pageItems",
- "dataFields",
- "dataItems",
- "formats",
- "pivotTableStyleInfo",
- };
- }
-
private void LoadFields() {
//Fields.Clear();
//int ix=0;
@@ -188,7 +133,7 @@
//Add fields.
index = 0;
- foreach (XmlElement fieldElem in _cacheDefinition.TopNode.SelectNodes(
+ foreach (XmlElement fieldElem in CacheDefinition.TopNode.SelectNodes(
"d:cacheFields/d:cacheField",
NameSpaceManager)) {
var fld = Fields[index++];
@@ -196,34 +141,34 @@
}
}
- private string GetStartXml(
+ private XmlDocument GetStartXml(
string name,
int id,
ExcelAddressBase address,
ExcelAddressBase sourceAddress) {
- string xml = string.Format(
- "<pivotTableDefinition xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" name=\"{0}\" cacheId=\"{1}\" dataOnRows=\"1\" applyNumberFormats=\"0\" applyBorderFormats=\"0\" applyFontFormats=\"0\" applyPatternFormats=\"0\" applyAlignmentFormats=\"0\" applyWidthHeightFormats=\"1\" dataCaption=\"Data\" createdVersion=\"4\" showMemberPropertyTips=\"0\" useAutoFormatting=\"1\" itemPrintTitles=\"1\" indent=\"0\" compact=\"0\" compactData=\"0\" gridDropZones=\"1\">",
- name,
- id);
+ string xml = $"""
+ <pivotTableDefinition xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" name="
+ {name}" cacheId="{id
+ }" dataOnRows="1" applyNumberFormats="0" applyBorderFormats="0" applyFontFormats="0" applyPatternFormats="0" applyAlignmentFormats="0" applyWidthHeightFormats="1" dataCaption="Data" createdVersion="4" showMemberPropertyTips="0" useAutoFormatting="1" itemPrintTitles="1" indent="0" compact="0" compactData="0" gridDropZones="1">
- xml += string.Format(
- "<location ref=\"{0}\" firstHeaderRow=\"1\" firstDataRow=\"1\" firstDataCol=\"1\" /> ",
- address.FirstAddress);
- xml += string.Format(
- "<pivotFields count=\"{0}\">",
- sourceAddress._toCol - sourceAddress._fromCol + 1);
+ """;
+ xml +=
+ $"""<location ref="{address.FirstAddress
+ }" firstHeaderRow="1" firstDataRow="1" firstDataCol="1" />""";
+ xml += $"""<pivotFields count="{sourceAddress._toCol - sourceAddress._fromCol + 1}">""";
for (int col = sourceAddress._fromCol; col <= sourceAddress._toCol; col++) {
- xml += "<pivotField showAll=\"0\" />"; //compact=\"0\" outline=\"0\" subtotalTop=\"0\" includeNewItemsInFilter=\"1\"
+ xml += """<pivotField showAll="0" />""";
}
-
xml += "</pivotFields>";
xml +=
- "<pivotTableStyleInfo name=\"PivotStyleMedium9\" showRowHeaders=\"1\" showColHeaders=\"1\" showRowStripes=\"0\" showColStripes=\"0\" showLastColumn=\"1\" />";
+ """<pivotTableStyleInfo name="PivotStyleMedium9" showRowHeaders="1" showColHeaders="1" showRowStripes="0" showColStripes="0" showLastColumn="1" />""";
xml += "</pivotTableDefinition>";
- return xml;
+ var result = new XmlDocument();
+ result.LoadXml(xml);
+ return result;
}
- internal ZipPackagePart Part { get; set; }
+ internal ZipPackagePart Part { get; }
/// <summary>
/// Provides access to the XML data representing the pivottable in the package.
@@ -272,19 +217,10 @@
}
}
- private ExcelPivotCacheDefinition _cacheDefinition;
-
/// <summary>
/// Reference to the pivot table cache definition object
/// </summary>
- public ExcelPivotCacheDefinition CacheDefinition {
- get {
- if (_cacheDefinition == null) {
- _cacheDefinition = new(NameSpaceManager, this, null, 1);
- }
- return _cacheDefinition;
- }
- }
+ public ExcelPivotCacheDefinition CacheDefinition { get; }
private string CleanDisplayName(string name) {
return Regex.Replace(name, @"[^\w\.-_]", "_");
diff --git a/EPPlus/Table/PivotTable/ExcelPivotTableCollection.cs b/EPPlus/Table/PivotTable/ExcelPivotTableCollection.cs
index c6c918f..fe9cc63 100644
--- a/EPPlus/Table/PivotTable/ExcelPivotTableCollection.cs
+++ b/EPPlus/Table/PivotTable/ExcelPivotTableCollection.cs
@@ -41,12 +41,9 @@
/// </summary>
public class ExcelPivotTableCollection : IEnumerable<ExcelPivotTable> {
private readonly List<ExcelPivotTable> _pivotTables = new();
- internal Dictionary<string, int> _pivotTableNames = new();
- private readonly ExcelWorksheet _ws;
+ internal readonly Dictionary<string, int> _pivotTableNames = new();
internal ExcelPivotTableCollection(ExcelWorksheet ws) {
- var pck = ws._package.Package;
- _ws = ws;
foreach (var rel in ws.Part.GetRelationships()) {
if (rel.RelationshipType == ExcelPackage._schemaRelationships + "/pivotTable") {
var tbl = new ExcelPivotTable(rel, ws);
@@ -56,49 +53,6 @@
}
}
- private ExcelPivotTable Add(ExcelPivotTable tbl) {
- _pivotTables.Add(tbl);
- _pivotTableNames.Add(tbl.Name, _pivotTables.Count - 1);
- if (tbl.CacheID >= _ws.Workbook._nextPivotTableID) {
- _ws.Workbook._nextPivotTableID = tbl.CacheID + 1;
- }
- return tbl;
- }
-
- /// <summary>
- /// Create a pivottable on the supplied range
- /// </summary>
- /// <param name="range">The range address including header and total row</param>
- /// <param name="source">The Source data range address</param>
- /// <param name="name">The name of the table. Must be unique </param>
- /// <returns>The pivottable object</returns>
- public ExcelPivotTable Add(ExcelAddressBase range, ExcelRangeBase source, string name) {
- if (string.IsNullOrEmpty(name)) {
- name = GetNewTableName();
- }
- if (range.WorkSheet != _ws.Name) {
- throw (new("The Range must be in the current worksheet"));
- }
- if (_ws.Workbook.ExistsTableName(name)) {
- throw (new ArgumentException("Tablename is not unique"));
- }
- foreach (var t in _pivotTables) {
- if (t.Address.Collide(range) != ExcelAddressBase.eAddressCollition.No) {
- throw (new ArgumentException(string.Format("Table range collides with table {0}", t.Name)));
- }
- }
- return Add(new(_ws, range, source, name, _ws.Workbook._nextPivotTableID++));
- }
-
- internal string GetNewTableName() {
- string name = "Pivottable1";
- int i = 2;
- while (_ws.Workbook.ExistsPivotTableName(name)) {
- name = string.Format("Pivottable{0}", i++);
- }
- return name;
- }
-
public int Count => _pivotTables.Count;
/// <summary>
diff --git a/EPPlus/Table/PivotTable/ExcelPivotTableField.cs b/EPPlus/Table/PivotTable/ExcelPivotTableField.cs
index 9869a11..05570f2 100644
--- a/EPPlus/Table/PivotTable/ExcelPivotTableField.cs
+++ b/EPPlus/Table/PivotTable/ExcelPivotTableField.cs
@@ -31,7 +31,6 @@
*******************************************************************************/
using System;
-using System.Collections.Generic;
using System.Globalization;
using System.Xml;
@@ -545,221 +544,6 @@
}
}
- internal ExcelPivotTableFieldDateGroup SetDateGroup(
- eDateGroupBy groupBy,
- DateTime startDate,
- DateTime endDate,
- int interval) {
- ExcelPivotTableFieldDateGroup group;
- group = new(NameSpaceManager, _cacheFieldHelper.TopNode);
- _cacheFieldHelper.SetXmlNodeBool("d:sharedItems/@containsDate", true);
- _cacheFieldHelper.SetXmlNodeBool("d:sharedItems/@containsNonDate", false);
- _cacheFieldHelper.SetXmlNodeBool("d:sharedItems/@containsSemiMixedTypes", false);
-
- group.TopNode.InnerXml += string.Format(
- "<fieldGroup base=\"{0}\"><rangePr groupBy=\"{1}\" /><groupItems /></fieldGroup>",
- BaseIndex,
- groupBy.ToString().ToLower(CultureInfo.InvariantCulture));
-
- if (startDate.Year < 1900) {
- _cacheFieldHelper.SetXmlNodeString(
- "d:fieldGroup/d:rangePr/@startDate",
- "1900-01-01T00:00:00");
- } else {
- _cacheFieldHelper.SetXmlNodeString(
- "d:fieldGroup/d:rangePr/@startDate",
- startDate.ToString("s", CultureInfo.InvariantCulture));
- _cacheFieldHelper.SetXmlNodeString("d:fieldGroup/d:rangePr/@autoStart", "0");
- }
-
- if (endDate == DateTime.MaxValue) {
- _cacheFieldHelper.SetXmlNodeString("d:fieldGroup/d:rangePr/@endDate", "9999-12-31T00:00:00");
- } else {
- _cacheFieldHelper.SetXmlNodeString(
- "d:fieldGroup/d:rangePr/@endDate",
- endDate.ToString("s", CultureInfo.InvariantCulture));
- _cacheFieldHelper.SetXmlNodeString("d:fieldGroup/d:rangePr/@autoEnd", "0");
- }
-
- int items = AddDateGroupItems(group, groupBy, startDate, endDate, interval);
- AddFieldItems(items);
-
- _grouping = group;
- return group;
- }
-
- internal ExcelPivotTableFieldNumericGroup SetNumericGroup(
- double start,
- double end,
- double interval) {
- ExcelPivotTableFieldNumericGroup group;
- group = new(NameSpaceManager, _cacheFieldHelper.TopNode);
- _cacheFieldHelper.SetXmlNodeBool("d:sharedItems/@containsNumber", true);
- _cacheFieldHelper.SetXmlNodeBool("d:sharedItems/@containsInteger", true);
- _cacheFieldHelper.SetXmlNodeBool("d:sharedItems/@containsSemiMixedTypes", false);
- _cacheFieldHelper.SetXmlNodeBool("d:sharedItems/@containsString", false);
-
- group.TopNode.InnerXml += string.Format(
- "<fieldGroup base=\"{0}\"><rangePr autoStart=\"0\" autoEnd=\"0\" startNum=\"{1}\" endNum=\"{2}\" groupInterval=\"{3}\"/><groupItems /></fieldGroup>",
- BaseIndex,
- start.ToString(CultureInfo.InvariantCulture),
- end.ToString(CultureInfo.InvariantCulture),
- interval.ToString(CultureInfo.InvariantCulture));
- int items = AddNumericGroupItems(group, start, end, interval);
- AddFieldItems(items);
-
- _grouping = group;
- return group;
- }
-
- private int AddNumericGroupItems(
- ExcelPivotTableFieldNumericGroup group,
- double start,
- double end,
- double interval) {
- if (interval < 0) {
- throw (new("The interval must be a positiv"));
- }
- if (start > end) {
- throw (new("Then End number must be larger than the Start number"));
- }
-
- XmlElement groupItems =
- group.TopNode.SelectSingleNode("d:fieldGroup/d:groupItems", group.NameSpaceManager)
- as XmlElement;
- int items = 2;
- //First date
- double index = start;
- double nextIndex = start + interval;
- AddGroupItem(groupItems, "<" + start.ToString(CultureInfo.InvariantCulture));
-
- while (index < end) {
- AddGroupItem(
- groupItems,
- string.Format(
- "{0}-{1}",
- index.ToString(CultureInfo.InvariantCulture),
- nextIndex.ToString(CultureInfo.InvariantCulture)));
- index = nextIndex;
- nextIndex += interval;
- items++;
- }
- AddGroupItem(groupItems, ">" + nextIndex.ToString(CultureInfo.InvariantCulture));
- return items;
- }
-
- private void AddFieldItems(int items) {
- XmlElement prevNode = null;
- XmlElement itemsNode = TopNode.SelectSingleNode("d:items", NameSpaceManager) as XmlElement;
- for (int x = 0; x < items; x++) {
- var itemNode = itemsNode.OwnerDocument.CreateElement("item", ExcelPackage._schemaMain);
- itemNode.SetAttribute("x", x.ToString());
- if (prevNode == null) {
- itemsNode.PrependChild(itemNode);
- } else {
- itemsNode.InsertAfter(itemNode, prevNode);
- }
- prevNode = itemNode;
- }
- itemsNode.SetAttribute("count", (items + 1).ToString());
- }
-
- private int AddDateGroupItems(
- ExcelPivotTableFieldGroup group,
- eDateGroupBy groupBy,
- DateTime startDate,
- DateTime endDate,
- int interval) {
- XmlElement groupItems =
- group.TopNode.SelectSingleNode("d:fieldGroup/d:groupItems", group.NameSpaceManager)
- as XmlElement;
- int items = 2;
- //First date
- AddGroupItem(
- groupItems,
- "<" + startDate.ToString("s", CultureInfo.InvariantCulture).Substring(0, 10));
-
- switch (groupBy) {
- case eDateGroupBy.Seconds:
- case eDateGroupBy.Minutes:
- AddTimeSerie(60, groupItems);
- items += 60;
- break;
- case eDateGroupBy.Hours:
- AddTimeSerie(24, groupItems);
- items += 24;
- break;
- case eDateGroupBy.Days:
- if (interval == 1) {
- DateTime dt = new DateTime(2008, 1, 1); //pick a year with 366 days
- while (dt.Year == 2008) {
- AddGroupItem(groupItems, dt.ToString("dd-MMM"));
- dt = dt.AddDays(1);
- }
- items += 366;
- } else {
- DateTime dt = startDate;
- items = 0;
- while (dt < endDate) {
- AddGroupItem(groupItems, dt.ToString("dd-MMM"));
- dt = dt.AddDays(interval);
- items++;
- }
- }
- break;
- case eDateGroupBy.Months:
- AddGroupItem(groupItems, "jan");
- AddGroupItem(groupItems, "feb");
- AddGroupItem(groupItems, "mar");
- AddGroupItem(groupItems, "apr");
- AddGroupItem(groupItems, "may");
- AddGroupItem(groupItems, "jun");
- AddGroupItem(groupItems, "jul");
- AddGroupItem(groupItems, "aug");
- AddGroupItem(groupItems, "sep");
- AddGroupItem(groupItems, "oct");
- AddGroupItem(groupItems, "nov");
- AddGroupItem(groupItems, "dec");
- items += 12;
- break;
- case eDateGroupBy.Quarters:
- AddGroupItem(groupItems, "Qtr1");
- AddGroupItem(groupItems, "Qtr2");
- AddGroupItem(groupItems, "Qtr3");
- AddGroupItem(groupItems, "Qtr4");
- items += 4;
- break;
- case eDateGroupBy.Years:
- if (startDate.Year >= 1900 && endDate != DateTime.MaxValue) {
- for (int year = startDate.Year; year <= endDate.Year; year++) {
- AddGroupItem(groupItems, year.ToString());
- }
- items += endDate.Year - startDate.Year + 1;
- }
- break;
- default:
- throw (new("unsupported grouping"));
- }
-
- //Lastdate
- AddGroupItem(
- groupItems,
- ">" + endDate.ToString("s", CultureInfo.InvariantCulture).Substring(0, 10));
- return items;
- }
-
- private void AddTimeSerie(int count, XmlElement groupItems) {
- for (int i = 0; i < count; i++) {
- AddGroupItem(groupItems, string.Format("{0:00}", i));
- }
- }
-
- private void AddGroupItem(XmlElement groupItems, string value) {
- var s = groupItems.OwnerDocument.CreateElement("s", ExcelPackage._schemaMain);
- s.SetAttribute("v", value);
- groupItems.AppendChild(s);
- }
-
internal ExcelPivotTableFieldCollectionBase<ExcelPivotTableFieldItem> _items;
/// <summary>
@@ -775,236 +559,8 @@
_items.AddInternal(item);
}
}
- //if (_grouping is ExcelPivotTableFieldDateGroup)
- //{
- // ExcelPivotTableFieldDateGroup dtgrp = ((ExcelPivotTableFieldDateGroup)_grouping);
-
- // ExcelPivotTableFieldItem minItem=null, maxItem=null;
- // foreach (var item in _items)
- // {
- // if (item.X == 0)
- // {
- // minItem = item;
- // }
- // else if (maxItem == null || maxItem.X < item.X)
- // {
- // maxItem = item;
- // }
- // }
- // if (dtgrp.AutoStart)
- // {
- // _items._list.Remove(minItem);
- // }
- // if (dtgrp.AutoEnd)
- // {
- // _items._list.Remove(maxItem);
- // }
-
- //}
}
return _items;
}
}
-
- /// <summary>
- /// Add numberic grouping to the field
- /// </summary>
- /// <param name="start">Start value</param>
- /// <param name="end">End value</param>
- /// <param name="interval">Interval</param>
- public void AddNumericGrouping(double start, double end, double interval) {
- ValidateGrouping();
- SetNumericGroup(start, end, interval);
- }
-
- /// <summary>
- /// Add a date grouping on this field.
- /// </summary>
- /// <param name="groupBy">Group by</param>
- public void AddDateGrouping(eDateGroupBy groupBy) {
- AddDateGrouping(groupBy, DateTime.MinValue, DateTime.MaxValue, 1);
- }
-
- /// <summary>
- /// Add a date grouping on this field.
- /// </summary>
- /// <param name="groupBy">Group by</param>
- /// <param name="startDate">Fixed start date. Use DateTime.MinValue for auto</param>
- /// <param name="endDate">Fixed end date. Use DateTime.MaxValue for auto</param>
- public void AddDateGrouping(eDateGroupBy groupBy, DateTime startDate, DateTime endDate) {
- AddDateGrouping(groupBy, startDate, endDate, 1);
- }
-
- /// <summary>
- /// Add a date grouping on this field.
- /// </summary>
- /// <param name="days">Number of days when grouping on days</param>
- /// <param name="startDate">Fixed start date. Use DateTime.MinValue for auto</param>
- /// <param name="endDate">Fixed end date. Use DateTime.MaxValue for auto</param>
- public void AddDateGrouping(int days, DateTime startDate, DateTime endDate) {
- AddDateGrouping(eDateGroupBy.Days, startDate, endDate, days);
- }
-
- private void AddDateGrouping(
- eDateGroupBy groupBy,
- DateTime startDate,
- DateTime endDate,
- int groupInterval) {
- if (groupInterval < 1 || groupInterval >= Int16.MaxValue) {
- throw (new ArgumentOutOfRangeException("Group interval is out of range"));
- }
- if (groupInterval > 1 && groupBy != eDateGroupBy.Days) {
- throw (new ArgumentException("Group interval is can only be used when groupBy is Days"));
- }
- ValidateGrouping();
-
- bool firstField = true;
- List<ExcelPivotTableField> fields = new List<ExcelPivotTableField>();
- //Seconds
- if ((groupBy & eDateGroupBy.Seconds) == eDateGroupBy.Seconds) {
- fields.Add(AddField(eDateGroupBy.Seconds, startDate, endDate, ref firstField));
- }
- //Minutes
- if ((groupBy & eDateGroupBy.Minutes) == eDateGroupBy.Minutes) {
- fields.Add(AddField(eDateGroupBy.Minutes, startDate, endDate, ref firstField));
- }
- //Hours
- if ((groupBy & eDateGroupBy.Hours) == eDateGroupBy.Hours) {
- fields.Add(AddField(eDateGroupBy.Hours, startDate, endDate, ref firstField));
- }
- //Days
- if ((groupBy & eDateGroupBy.Days) == eDateGroupBy.Days) {
- fields.Add(AddField(eDateGroupBy.Days, startDate, endDate, ref firstField, groupInterval));
- }
- //Month
- if ((groupBy & eDateGroupBy.Months) == eDateGroupBy.Months) {
- fields.Add(AddField(eDateGroupBy.Months, startDate, endDate, ref firstField));
- }
- //Quarters
- if ((groupBy & eDateGroupBy.Quarters) == eDateGroupBy.Quarters) {
- fields.Add(AddField(eDateGroupBy.Quarters, startDate, endDate, ref firstField));
- }
- //Years
- if ((groupBy & eDateGroupBy.Years) == eDateGroupBy.Years) {
- fields.Add(AddField(eDateGroupBy.Years, startDate, endDate, ref firstField));
- }
-
- if (fields.Count > 1) {
- _cacheFieldHelper.SetXmlNodeString("d:fieldGroup/@par", (_table.Fields.Count - 1).ToString());
- }
- if (groupInterval != 1) {
- _cacheFieldHelper.SetXmlNodeString(
- "d:fieldGroup/d:rangePr/@groupInterval",
- groupInterval.ToString());
- } else {
- _cacheFieldHelper.DeleteNode("d:fieldGroup/d:rangePr/@groupInterval");
- }
- _items = null;
- }
-
- private void ValidateGrouping() {
- if (!(IsColumnField || IsRowField)) {
- throw (new("Field must be a row or column field"));
- }
- foreach (var field in _table.Fields) {
- if (field.Grouping != null) {
- throw (new("Grouping already exists"));
- }
- }
- }
-
- private ExcelPivotTableField AddField(
- eDateGroupBy groupBy,
- DateTime startDate,
- DateTime endDate,
- ref bool firstField) {
- return AddField(groupBy, startDate, endDate, ref firstField, 1);
- }
-
- private ExcelPivotTableField AddField(
- eDateGroupBy groupBy,
- DateTime startDate,
- DateTime endDate,
- ref bool firstField,
- int interval) {
- if (firstField == false) {
- //Pivot field
- var topNode = _table.PivotTableXml.SelectSingleNode(
- "//d:pivotFields",
- _table.NameSpaceManager);
- var fieldNode = _table.PivotTableXml.CreateElement("pivotField", ExcelPackage._schemaMain);
- fieldNode.SetAttribute("compact", "0");
- fieldNode.SetAttribute("outline", "0");
- fieldNode.SetAttribute("showAll", "0");
- fieldNode.SetAttribute("defaultSubtotal", "0");
- topNode.AppendChild(fieldNode);
-
- var field = new ExcelPivotTableField(
- _table.NameSpaceManager,
- fieldNode,
- _table,
- _table.Fields.Count,
- Index);
- field.DateGrouping = groupBy;
-
- XmlNode rowColFields;
- if (IsRowField) {
- rowColFields = TopNode.SelectSingleNode("../../d:rowFields", NameSpaceManager);
- } else {
- rowColFields = TopNode.SelectSingleNode("../../d:colFields", NameSpaceManager);
- }
-
- var index = 0;
- foreach (XmlElement rowfield in rowColFields.ChildNodes) {
- if (int.TryParse(rowfield.GetAttribute("x"), out var fieldIndex)) {
- if (_table.Fields[fieldIndex].BaseIndex == BaseIndex) {
- var newElement = rowColFields.OwnerDocument.CreateElement(
- "field",
- ExcelPackage._schemaMain);
- newElement.SetAttribute("x", field.Index.ToString());
- rowColFields.InsertBefore(newElement, rowfield);
- break;
- }
- }
- index++;
- }
-
- if (IsRowField) {
- _table.RowFields.Insert(field, index);
- } else {
- _table.ColumnFields.Insert(field, index);
- }
-
- _table.Fields.AddInternal(field);
-
- AddCacheField(field, startDate, endDate, interval);
- return field;
- }
- firstField = false;
- DateGrouping = groupBy;
- Compact = false;
- SetDateGroup(groupBy, startDate, endDate, interval);
- return this;
- }
-
- private void AddCacheField(
- ExcelPivotTableField field,
- DateTime startDate,
- DateTime endDate,
- int interval) {
- //Add Cache definition field.
- var cacheTopNode = _table.CacheDefinition.CacheDefinitionXml.SelectSingleNode(
- "//d:cacheFields",
- _table.NameSpaceManager);
- var cacheFieldNode = _table.CacheDefinition.CacheDefinitionXml.CreateElement(
- "cacheField",
- ExcelPackage._schemaMain);
-
- cacheFieldNode.SetAttribute("name", field.DateGrouping.ToString());
- cacheFieldNode.SetAttribute("databaseField", "0");
- cacheTopNode.AppendChild(cacheFieldNode);
- field.SetCacheFieldNode(cacheFieldNode);
-
- field.SetDateGroup(field.DateGrouping, startDate, endDate, interval);
- }
}
diff --git a/EPPlus/XmlHelper.cs b/EPPlus/XmlHelper.cs
index a958baf..b311997 100644
--- a/EPPlus/XmlHelper.cs
+++ b/EPPlus/XmlHelper.cs
@@ -33,11 +33,11 @@
*******************************************************************************/
using System;
+using System.Collections.Immutable;
using System.Globalization;
using System.IO;
using System.Text;
using System.Xml;
-using OfficeOpenXml.Packaging;
using OfficeOpenXml.Style;
namespace OfficeOpenXml;
@@ -64,15 +64,10 @@
internal XmlNode TopNode { get; set; }
- private string[] _schemaNodeOrder;
-
/// <summary>
/// Schema order list
/// </summary>
- internal string[] SchemaNodeOrder {
- get => _schemaNodeOrder;
- set => _schemaNodeOrder = value;
- }
+ protected virtual ImmutableArray<string> SchemaNodeOrder => ImmutableArray<string>.Empty;
internal XmlNode CreateNode(string path) {
if (path == "") {
@@ -90,10 +85,10 @@
string nodeName;
string nodePrefix;
- string nameSpaceUri = "";
+ string nameSpaceUri;
string[] nameSplit = subPath.Split(':');
- if (SchemaNodeOrder != null && subPath[0] != '@') {
+ if (SchemaNodeOrder.Length > 0 && subPath[0] != '@') {
insertFirst = false;
prependNode = GetPrependNode(subPath, node);
}
@@ -176,16 +171,6 @@
}
/// <summary>
- /// Create a complex node. Insert the node according to SchemaOrder
- /// using the TopNode as the parent
- /// </summary>
- /// <param name="path"></param>
- /// <returns></returns>
- internal XmlNode CreateComplexNode(string path) {
- return CreateComplexNode(TopNode, path, eNodeInsertOrder.SchemaOrder, null);
- }
-
- /// <summary>
/// Create a complex node. Insert the node according to the <paramref name="path"/>
/// using the <paramref name="topNode"/> as the parent
/// </summary>
@@ -243,7 +228,6 @@
}
XmlNode node = topNode;
- string nameSpaceUri = string.Empty;
//TODO: BUG: when the "path" contains "/" in an attrribue value, it gives an error.
@@ -312,7 +296,7 @@
string nodeName;
string nodePrefix;
string[] nameSplit = subPath.Split(':');
- nameSpaceUri = string.Empty;
+ string nameSpaceUri;
// Check if the name has a prefix like "d:nodeName"
if (nameSplit.Length > 1) {
@@ -347,7 +331,7 @@
// Check if we need to use the "SchemaOrder"
if (nodeInsertOrder == eNodeInsertOrder.SchemaOrder) {
// Check if the Schema Order List is empty
- if ((SchemaNodeOrder == null) || (SchemaNodeOrder.Length == 0)) {
+ if (SchemaNodeOrder.Length == 0) {
// Use the "Insert Last" option when Schema Order List is empty
nodeInsertOrder = eNodeInsertOrder.Last;
} else {
@@ -428,8 +412,8 @@
if (ix > 0) {
nodeName = nodeName.Substring(ix + 1, nodeName.Length - (ix + 1));
}
- for (int i = 0; i < _schemaNodeOrder.Length; i++) {
- if (nodeName == _schemaNodeOrder[i]) {
+ for (int i = 0; i < SchemaNodeOrder.Length; i++) {
+ if (nodeName == SchemaNodeOrder[i]) {
return i;
}
}
@@ -464,10 +448,6 @@
}
}
- internal void DeleteTopNode() {
- TopNode.ParentNode.RemoveChild(TopNode);
- }
-
internal void SetXmlNodeString(string path, string value) {
SetXmlNodeString(TopNode, path, value, false, false);
}
@@ -476,10 +456,6 @@
SetXmlNodeString(TopNode, path, value, removeIfBlank, false);
}
- internal void SetXmlNodeString(XmlNode node, string path, string value) {
- SetXmlNodeString(node, path, value, false, false);
- }
-
internal void SetXmlNodeString(XmlNode node, string path, string value, bool removeIfBlank) {
SetXmlNodeString(node, path, value, removeIfBlank, false);
}
@@ -637,37 +613,6 @@
return GetXmlNodeString(TopNode, path);
}
- internal static Uri GetNewUri(ZipPackage package, string sUri) {
- return GetNewUri(package, sUri, 1);
- }
-
- internal static Uri GetNewUri(ZipPackage package, string sUri, int id) {
- Uri uri;
- do {
- uri = new(string.Format(sUri, id++), UriKind.Relative);
- } while (package.PartExists(uri));
- return uri;
- }
-
- /// <summary>
- /// Insert the new node before any of the nodes in the comma separeted list
- /// </summary>
- /// <param name="parentNode">Parent node</param>
- /// <param name="beforeNodes">comma separated list containing nodes to insert after. Left to right order</param>
- /// <param name="newNode">The new node to be inserterd</param>
- internal void InserAfter(XmlNode parentNode, string beforeNodes, XmlNode newNode) {
- string[] nodePaths = beforeNodes.Split(',');
-
- foreach (string nodePath in nodePaths) {
- XmlNode node = parentNode.SelectSingleNode(nodePath, NameSpaceManager);
- if (node != null) {
- parentNode.InsertAfter(newNode, node);
- return;
- }
- }
- parentNode.InsertAfter(newNode, null);
- }
-
internal static void LoadXmlSafe(XmlDocument xmlDoc, Stream stream) {
XmlReaderSettings settings = new XmlReaderSettings();
//Disable entity parsing (to aviod xmlbombs, External Entity Attacks etc).