Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/329.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用openXML深度克隆.xlsx文件中的行?_C#_Xml_Excel_Openxml - Fatal编程技术网

C# 如何使用openXML深度克隆.xlsx文件中的行?

C# 如何使用openXML深度克隆.xlsx文件中的行?,c#,xml,excel,openxml,C#,Xml,Excel,Openxml,我有template.xlsx文件,我必须通过在特定索引中添加一行的几个副本来修改该文件。当我尝试使用克隆方法进行此操作时,我添加了一行,但每行都会相互修改。我需要创建opemxml行对象的深度克隆,但当我尝试此操作时,我出现了一个错误,openxml行对象未序列化。如何使用带序列化的openXML对.xlsx文件中的行进行深度克隆,或者如果有其他方法对openXML行对象进行深度克隆?您可以在OpenXmlElement上使用.CloneNode(true)进行深度克隆 因此,如果要在表中复制

我有template.xlsx文件,我必须通过在特定索引中添加一行的几个副本来修改该文件。当我尝试使用克隆方法进行此操作时,我添加了一行,但每行都会相互修改。我需要创建opemxml行对象的深度克隆,但当我尝试此操作时,我出现了一个错误,openxml行对象未序列化。如何使用带序列化的openXML对.xlsx文件中的行进行深度克隆,或者如果有其他方法对openXML行对象进行深度克隆?

您可以在OpenXmlElement上使用
.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