C# 如何使用openXML深度克隆.xlsx文件中的行?
我有template.xlsx文件,我必须通过在特定索引中添加一行的几个副本来修改该文件。当我尝试使用克隆方法进行此操作时,我添加了一行,但每行都会相互修改。我需要创建opemxml行对象的深度克隆,但当我尝试此操作时,我出现了一个错误,openxml行对象未序列化。如何使用带序列化的openXML对.xlsx文件中的行进行深度克隆,或者如果有其他方法对openXML行对象进行深度克隆?您可以在OpenXmlElement上使用C# 如何使用openXML深度克隆.xlsx文件中的行?,c#,xml,excel,openxml,C#,Xml,Excel,Openxml,我有template.xlsx文件,我必须通过在特定索引中添加一行的几个副本来修改该文件。当我尝试使用克隆方法进行此操作时,我添加了一行,但每行都会相互修改。我需要创建opemxml行对象的深度克隆,但当我尝试此操作时,我出现了一个错误,openxml行对象未序列化。如何使用带序列化的openXML对.xlsx文件中的行进行深度克隆,或者如果有其他方法对openXML行对象进行深度克隆?您可以在OpenXmlElement上使用.CloneNode(true)进行深度克隆 因此,如果要在表中复制
.CloneNode(true)
进行深度克隆
因此,如果要在表中复制一行,它将如下所示
// suppose table an OpenXml Table and row the row you want to clone
table.Append(row.CloneNode(true));
编辑:
将其插入到特定行之前
// suppose r is the row you want to insert it before
r.InsertBeforeSelf(row.CloneNode(true));
在我的例子中,我需要复制工作表末尾的几行。 我确实需要克隆特定范围的行,即值、样式和公式、合并的单元格。在复制和粘贴几行的问题上花费了许多小时之后,我终于找到了一个解决方案。我能够将第18行复制到第26行,并将它们从第27行粘贴 示例如下: 代码如下:
public static void CopyRowRange(SpreadsheetDocument document, string sheetName,
int srcRowFrom, int srcRowTo, int destRowFrom)
{
WorkbookPart workbookPart = document.WorkbookPart;
if (srcRowTo < srcRowFrom || destRowFrom < srcRowFrom) return;
int destRowFromBase = destRowFrom;
WorksheetPart worksheetPart = GetWorksheetPartByName(document, sheetName);
SheetData sheetData = worksheetPart.Worksheet.GetFirstChild<SheetData>();
IList<Cell> cells = sheetData.Descendants<Cell>().Where(c =>
GetRowIndex(c.CellReference) >= srcRowFrom &&
GetRowIndex(c.CellReference) <= srcRowTo).ToList<Cell>();
if (cells.Count() == 0) return;
int copiedRowCount = srcRowTo - srcRowFrom + 1;
MoveRowIndex(document, sheetName, destRowFrom - 1, srcRowTo, srcRowFrom);
IDictionary<int, IList<Cell>> clonedCells = null;
IList<Cell> formulaCells = new List<Cell>();
IList<Row> cloneRelatedRows = new List<Row>();
destRowFrom = destRowFromBase;
int changedRowsCount = destRowFrom - srcRowFrom;
formulaCells.Clear();
clonedCells = new Dictionary<int, IList<Cell>>();
foreach (Cell cell in cells)
{
Cell newCell = (Cell)cell.CloneNode(true);
int index = Convert.ToInt32(GetRowIndex(cell.CellReference));
int rowIndex = index - changedRowsCount;
newCell.CellReference = GetColumnName(cell.CellReference) + rowIndex.ToString();
IList<Cell> rowCells = null;
if (clonedCells.ContainsKey(rowIndex))
rowCells = clonedCells[rowIndex];
else
{
rowCells = new List<Cell>();
clonedCells.Add(rowIndex, rowCells);
}
rowCells.Add(newCell);
if (newCell.CellFormula != null && newCell.CellFormula.Text.Length > 0)
{
formulaCells.Add(newCell);
}
}
foreach (int rowIndex in clonedCells.Keys)
{
Row row = sheetData.Elements<Row>().Where(r => r.RowIndex == rowIndex).FirstOrDefault();
if (row == null)
{
row = new Row() { RowIndex = (uint)rowIndex };
Row refRow = sheetData.Elements<Row>().Where(r => r.RowIndex > rowIndex).OrderBy(r => r.RowIndex).FirstOrDefault();
if (refRow == null)
sheetData.AppendChild<Row>(row);
else
sheetData.InsertBefore<Row>(row, refRow);
}
row.Append(clonedCells[rowIndex].ToArray());
cloneRelatedRows.Add(row);
}
ChangeFormulaRowNumber(worksheetPart.Worksheet, formulaCells, changedRowsCount);
foreach (Row row in cloneRelatedRows)
{
IList<Cell> cs = row.Elements<Cell>().OrderBy(c => c.CellReference.Value).ToList<Cell>();
row.RemoveAllChildren();
row.Append(cs.ToArray());
}
MergeCells mcells = worksheetPart.Worksheet.GetFirstChild<MergeCells>();
if (mcells != null)
{
IList<MergeCell> newMergeCells = new List<MergeCell>();
IEnumerable<MergeCell> clonedMergeCells = mcells.Elements<MergeCell>().
Where(m => MergeCellInRange(m, srcRowFrom, srcRowTo)).ToList<MergeCell>();
foreach (MergeCell cmCell in clonedMergeCells)
{
MergeCell newMergeCell = CreateChangedRowMergeCell(worksheetPart.Worksheet, cmCell, changedRowsCount);
newMergeCells.Add(newMergeCell);
}
uint count = mcells.Count.Value;
mcells.Count = new UInt32Value(count + (uint)newMergeCells.Count);
mcells.Append(newMergeCells.ToArray());
}
}
private static WorksheetPart
GetWorksheetPartByName(SpreadsheetDocument document,
string sheetName)
{
IEnumerable<Sheet> sheets =
document.WorkbookPart.Workbook.GetFirstChild<Sheets>().
Elements<Sheet>().Where(s => s.Name == sheetName);
if (sheets.Count() == 0)
{
return null;
}
string relationshipId = sheets.First().Id.Value;
WorksheetPart worksheetPart = (WorksheetPart)
document.WorkbookPart.GetPartById(relationshipId);
return worksheetPart;
}
private static void MoveRowIndex(SpreadsheetDocument document, string sheetName, int destRowFrom, int srcRowTo, int srcRowFrom)
{
WorksheetPart worksheetPart = GetWorksheetPartByName(document, sheetName);
SheetData sheetData = worksheetPart.Worksheet.GetFirstChild<SheetData>();
uint newRowIndex;
IEnumerable<Row> rows = sheetData.Descendants<Row>().Where(r => r.RowIndex.Value >= srcRowFrom && r.RowIndex.Value <= srcRowTo);
foreach (Row row in rows)
{
newRowIndex = Convert.ToUInt32(destRowFrom + 1);
foreach (Cell cell in row.Elements<Cell>())
{
string cellReference = cell.CellReference.Value;
cell.CellReference = new StringValue(cellReference.Replace(row.RowIndex.Value.ToString(), newRowIndex.ToString()));
}
row.RowIndex = new UInt32Value(newRowIndex);
destRowFrom++;
}
}
private static void ChangeFormulaRowNumber(Worksheet worksheet, IList<Cell> formulaCells, int changedRowsCount)
{
foreach (Cell formulaCell in formulaCells)
{
Regex regex = new Regex(@"\d+");
var rowIndex = Convert.ToInt32(regex.Match(formulaCell.CellReference).Value);
Regex regex2 = new Regex("[A-Za-z]+");
var columnIndex = regex2.Match(formulaCell.CellReference).Value;
int newRowIndex = rowIndex + changedRowsCount;
Cell cell = GetCell(worksheet, columnIndex, newRowIndex);
cell.CellFormula = new CellFormula(cell.CellFormula.Text.Replace($"{rowIndex}",$"{newRowIndex}"));
}
}
private static MergeCell CreateChangedRowMergeCell(Worksheet worksheet, MergeCell cmCell, int changedRows)
{
string[] cells = cmCell.Reference.Value.Split(':', 2, StringSplitOptions.RemoveEmptyEntries);
Regex regex = new Regex(@"\d+");
var rowIndex1 = Convert.ToInt32(regex.Match(cells[0]).Value);
var rowIndex2 = Convert.ToInt32(regex.Match(cells[1]).Value);
Regex regex2 = new Regex("[A-Za-z]+");
var columnIndex1 = regex2.Match(cells[0]).Value;
var columnIndex2 = regex2.Match(cells[1]).Value;
var cell1Name = $"{columnIndex1}{rowIndex1 + changedRows}";
var cell2Name = $"{columnIndex2}{rowIndex2 + changedRows}";
CreateSpreadsheetCellIfNotExist(worksheet, cell1Name);
CreateSpreadsheetCellIfNotExist(worksheet, cell2Name);
return new MergeCell() { Reference = new StringValue(cell1Name + ":" + cell2Name) };
}
private static bool MergeCellInRange(MergeCell mergeCell, int srcRowFrom, int srcRowTo)
{
string[] cells = mergeCell.Reference.Value.Split(':', 2, StringSplitOptions.RemoveEmptyEntries);
Regex regex = new Regex(@"\d+");
var cellIndex1 = Convert.ToInt32(regex.Match(cells[0]).Value);
var cellIndex2 = Convert.ToInt32(regex.Match(cells[1]).Value);
if (srcRowFrom <= cellIndex1 && cellIndex1 <= srcRowTo &&
srcRowFrom <= cellIndex2 && cellIndex2 <= srcRowTo)
return true;
else
return false;
}
private static uint GetRowIndex(string cellName)
{
Regex regex = new Regex(@"\d+");
Match match = regex.Match(cellName);
return uint.Parse(match.Value);
}
private static string GetColumnName(string cellName)
{
Regex regex = new Regex("[A-Za-z]+");
Match match = regex.Match(cellName);
return match.Value;
}
private static void CreateSpreadsheetCellIfNotExist(Worksheet worksheet, string cellName)
{
string columnName = GetColumnName(cellName);
uint rowIndex = GetRowIndex(cellName);
IEnumerable<Row> rows = worksheet.Descendants<Row>().Where(r => r.RowIndex.Value == rowIndex);
if (rows.Count() == 0)
{
Row row = new Row() { RowIndex = new UInt32Value(rowIndex) };
Cell cell = new Cell() { CellReference = new StringValue(cellName) };
row.Append(cell);
worksheet.Descendants<SheetData>().First().Append(row);
worksheet.Save();
}
else
{
Row row = rows.First();
IEnumerable<Cell> cells = row.Elements<Cell>().Where(c => c.CellReference.Value == cellName);
if (cells.Count() == 0)
{
Cell cell = new Cell() { CellReference = new StringValue(cellName) };
row.Append(cell);
worksheet.Save();
}
}
}
public static void CopyRowRange(电子表格文档、字符串sheetName、,
int srcRowFrom、int srcRowTo、int destRowFrom)
{
WorkbookPart WorkbookPart=document.WorkbookPart;
if(srcRowTo
GetRowIndex(c.CellReference)>=srcRowFrom&&
GetRowIndex(c.CellReference)0)
{
公式化单元格。添加(newCell);
}
}
foreach(clonedcell.Keys中的int行索引)
{
Row Row=sheetData.Elements()。其中(r=>r.RowIndex==RowIndex)。FirstOrDefault();
if(行==null)
{
行=新行(){RowIndex=(uint)RowIndex};
Row refRow=sheetData.Elements()。其中(r=>r.RowIndex>RowIndex).OrderBy(r=>r.RowIndex).FirstOrDefault();
如果(refRow==null)
sheetData.AppendChild(行);
其他的
sheetData.InsertBefore(行,再行);
}
Append(克隆细胞[rowIndex].ToArray());
cloneRelatedRows.Add(行);
}
ChangeFormulaRowNumber(工作表部分工作表、formulaCells、ChangedRowCount);
foreach(cloneRelatedRows中的行)
{
IList cs=row.Elements().OrderBy(c=>c.CellReference.Value).ToList();
row.RemoveAllChildren();
Append(cs.ToArray());
}
MergeCells mcells=worksheetPart.Worksheet.GetFirstChild();
如果(mcells!=null)
{
IList newMergeCells=新列表();
IEnumerable clonedMergeCells=mcells.Elements()。
其中(m=>MergeCellInRange(m,srcRowFrom,srcRowTo)).ToList();
foreach(克隆合并细胞中的合并细胞)
{
MergeCell newMergeCell=CreateChangedRowMergeCell(工作表部分,cmCell,changedRowsCount);
newMergeCells.Add(newMergeCell);
}
uint count=mcells.count.Value;
mcells.Count=新的uint32值(Count+(uint)newMergeCells.Count);
Append(newMergeCells.ToArray());
}
}
专用静态工作表部件
GetWorksheetPartByName(电子表格文档、,
字符串(名称)
{
可数床单=
document.WorkbookPart.Workbook.GetFirstChild()。
元素(),其中(s=>s.Name==sheetName);
如果(sheets.Count()==0)
{
返回null;
}
string relationshipId=sheets.First().Id.Value;
工作表部件工作表部件=(工作表部件)
document.WorkbookPart.GetPartById(relationshipId);
返回工作表部件;
}
私有静态void MoveRowIndex(电子表格文档、字符串sheetName、int-destRowFrom、int-srcRowTo、int-srcRowFrom)
{
WorksheetPart WorksheetPart=GetWorksheetPartByName(文档,图纸名称);
SheetData SheetData=worksheetPart.Worksheet.GetFirstChild();
uint-newRowIndex;
IEnumerable rows=sheetData.subjections()。其中(r=>r.RowIndex.Value>=srcRowFrom&&r.RowIndex.Value)我编辑我的问题,我添加了:“特定索引中的行”。我需要在其他行之间添加。缺少在工作表末尾添加行的追加函数。GetCell