C# OpenXML 将 Excel 工作表复制并粘贴到新工作簿

Mik*_*e F 1 c# openxml

我有多个具有相同工作表名称的工作簿。我想将所有单独的工作表复制到一本工作簿中。到目前为止,我的代码复制了文本,但它不保持格式,所以我丢失了颜色、边框等。有人可以建议任何改进来包含样式并保持格式吗?谢谢

using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
using System.Linq;
namespace openxmlExcelTryout
{


class OpenXMLCopySheet
{
    private static int tableId;

    public static void CopySheet(string filename, string sheetName, string clonedSheetName, string destFileName)
    {

        //Open workbook
        using (SpreadsheetDocument mySpreadsheet = SpreadsheetDocument.Open(filename, true))
        {
            WorkbookPart workbookPart = mySpreadsheet.WorkbookPart;
            //Get the source sheet to be copied
            WorksheetPart sourceSheetPart = GetWorkSheetPart(workbookPart, sheetName);
            SharedStringTablePart sharedStringTable = workbookPart.SharedStringTablePart;
            //Take advantage of AddPart for deep cloning
            using (SpreadsheetDocument newXLFile = SpreadsheetDocument.Create(destFileName, SpreadsheetDocumentType.Workbook))
            {
                WorkbookPart newWorkbookPart = newXLFile.AddWorkbookPart();
                SharedStringTablePart newSharedStringTable = newWorkbookPart.AddPart<SharedStringTablePart>(sharedStringTable);
                WorksheetPart newWorksheetPart = newWorkbookPart.AddPart<WorksheetPart>(sourceSheetPart);
                //Table definition parts are somewhat special and need unique ids...so let's make an id based on count
                int numTableDefParts = sourceSheetPart.GetPartsCountOfType<TableDefinitionPart>();
                tableId = numTableDefParts;

                //Clean up table definition parts (tables need unique ids)
                if (numTableDefParts != 0)
                    FixupTableParts(newWorksheetPart, numTableDefParts);
                //There should only be one sheet that has focus
                CleanView(newWorksheetPart);

                var fileVersion = new FileVersion { ApplicationName = "Microsoft Office Excel" };

                //Worksheet ws = newWorksheetPart.Worksheet;
                Workbook wb = new Workbook();
                wb.Append(fileVersion);

                //Add new sheet to main workbook part
                Sheets sheets = null;
                //int sheetCount = wb.Sheets.Count();
                if (wb.Sheets != null)
                { sheets = wb.GetFirstChild<Sheets>(); }
                else
                { sheets = new Sheets(); }

                Sheet copiedSheet = new Sheet
                {
                    Name = clonedSheetName,
                    Id = newWorkbookPart.GetIdOfPart(newWorksheetPart)
                };
                if (wb.Sheets != null)
                { copiedSheet.SheetId = (uint)sheets.ChildElements.Count + 1; }
                else { copiedSheet.SheetId = 1; }

                sheets.Append(copiedSheet);
                newWorksheetPart.Worksheet.Save();

                wb.Append(sheets);
                //Save Changes
                newWorkbookPart.Workbook = wb;
                wb.Save();
                newXLFile.Close();
            }
        }
    }
    static void CleanView(WorksheetPart worksheetPart)
    {
        //There can only be one sheet that has focus
        SheetViews views = worksheetPart.Worksheet.GetFirstChild<SheetViews>();

        if (views != null)
        {
            views.Remove();
            worksheetPart.Worksheet.Save();
        }
    }

    static void FixupTableParts(WorksheetPart worksheetPart, int numTableDefParts)
    {
        //Every table needs a unique id and name
        foreach (TableDefinitionPart tableDefPart in worksheetPart.TableDefinitionParts)
        {
            tableId++;
            tableDefPart.Table.Id = (uint)tableId;
            tableDefPart.Table.DisplayName = "CopiedTable" + tableId;
            tableDefPart.Table.Name = "CopiedTable" + tableId;
            tableDefPart.Table.Save();
        }
    }
    static WorksheetPart GetWorkSheetPart(WorkbookPart workbookPart, string sheetName)
    {
        //Get the relationship id of the sheetname
        string relId = workbookPart.Workbook.Descendants<Sheet>()
            .Where(s => s.Name.Value.Equals(sheetName))
            .First()
            .Id;

        return (WorksheetPart)workbookPart.GetPartById(relId);
    }
}
}
Run Code Online (Sandbox Code Playgroud)

小智 6

在花了很多时间来解决复制整张纸的问题后,我终于找到了解决方案。CloneSheet 方法将整个工作表(内容 + 样式)复制到具有新名称的新工作表。

    static void CloneSheet(SpreadsheetDocument spreadsheetDocument, string sheetName, string clonedSheetName)
    {
        WorkbookPart workbookPart = spreadsheetDocument.WorkbookPart;
        WorksheetPart sourceSheetPart = GetWorkSheetPart(workbookPart, sheetName);
        Sheets sheets = workbookPart.Workbook.GetFirstChild<Sheets>();

        SpreadsheetDocument tempSheet = SpreadsheetDocument.Create(new MemoryStream(), spreadsheetDocument.DocumentType);
        WorkbookPart tempWorkbookPart = tempSheet.AddWorkbookPart();
        WorksheetPart tempWorksheetPart = tempWorkbookPart.AddPart(sourceSheetPart);
        WorksheetPart clonedSheet = workbookPart.AddPart(tempWorksheetPart);

        Sheet copiedSheet = new Sheet();
        copiedSheet.Name = clonedSheetName;
        copiedSheet.Id = workbookPart.GetIdOfPart(clonedSheet);
        copiedSheet.SheetId = (uint)sheets.ChildElements.Count + 1;
        sheets.Append(copiedSheet);
    }
Run Code Online (Sandbox Code Playgroud)


Mik*_*e F 5

我找到了解决方案并将其发布在这里也许有人会从中得到一些帮助。

public static void MergeXSLX(string spreadSheetPathSource, string spreadSheetPathDestination)
    {
        //string[] staticSheets = new string[] { "Index", "Proj Info", "Project Report", "Cust Proj Rpt", "Issues Register", "Risk Register", "Change Register", "Milestones Register", "Add Optional Sheets ==>" };

        string[] staticSheets = new string[] { "Summaries", "limits" };

        FileStream spreadSheetStreamSource = null;
        FileStream spreadSheetStreamDestination = null;
        try
        {
            if (!File.Exists(spreadSheetPathSource)) throw new Exception("Source excel document not found!");
            if (!File.Exists(spreadSheetPathDestination)) throw new Exception("Destination excel document not found!");
            spreadSheetStreamSource = new FileStream(spreadSheetPathSource, FileMode.Open, FileAccess.Read);
            spreadSheetStreamDestination = new FileStream(spreadSheetPathDestination, FileMode.Open, FileAccess.ReadWrite);

            using (SpreadsheetDocument spreadsheetDocumentSource = SpreadsheetDocument.Open(spreadSheetStreamSource, false))
            {
                using (SpreadsheetDocument spreadsheetDocumentDestination = SpreadsheetDocument.Open(spreadSheetStreamDestination, true))
                {
                    WorkbookPart workbookPartSource = spreadsheetDocumentSource.WorkbookPart;
                    WorkbookPart workbookPartDestination = spreadsheetDocumentDestination.WorkbookPart;

                    foreach (Sheet sheet in workbookPartSource.Workbook.Sheets)
                    {
                        if (staticSheets.ToList().Contains(sheet.Name))
                        {
                            uint replaced = 0;
                            int index = 0;

                            if (workbookPartDestination.Workbook.Sheets.Elements<Sheet>().Count(s => s.Name.ToString().Equals(sheet.Name)) == 1)
                            {
                                Sheet org;
                                foreach (Sheet s in workbookPartDestination.Workbook.Sheets.Elements<Sheet>())
                                {
                                    if (s.Name.ToString().Equals(sheet.Name))
                                    {
                                        org = s;
                                        break;
                                    }
                                    index++;
                                }

                                replaced = sheet.SheetId;

                                DeleteWorkSheet(workbookPartDestination, sheet.Name);
                            }

                            //WorkbookPart workbookPart = mySpreadsheet.WorkbookPart;
                            ////Get the source sheet to be copied
                            WorksheetPart sourceSheetPart = GetWorkSheetPart(workbookPartSource, sheet.Name);

                            //Take advantage of AddPart for deep cloning
                            SpreadsheetDocument tempSheet = SpreadsheetDocument.Create(new MemoryStream(), spreadsheetDocumentDestination.DocumentType);
                            WorkbookPart tempWorkbookPart = tempSheet.AddWorkbookPart();
                            WorksheetPart tempWorksheetPart = tempWorkbookPart.AddPart<WorksheetPart>(sourceSheetPart);

                            if(workbookPartDestination.SharedStringTablePart == null)
                            {
                                workbookPartDestination.AddPart<SharedStringTablePart>(workbookPartSource.SharedStringTablePart);
                            }

                            //Add cloned sheet and all associated parts to workbook
                            WorksheetPart clonedSheet = workbookPartDestination.AddPart<WorksheetPart>(tempWorksheetPart);

                            //Table definition parts are somewhat special and need unique ids...so let's make an id based on count
                            int numTableDefParts = sourceSheetPart.GetPartsCountOfType<TableDefinitionPart>();
                            int tableId = numTableDefParts;

                            //Clean up table definition parts (tables need unique ids)
                            if (numTableDefParts != 0)
                                FixupTableParts(clonedSheet, numTableDefParts);
                            //There should only be one sheet that has focus
                            CleanView(clonedSheet);

                            var values = workbookPartSource.SharedStringTablePart.SharedStringTable.Elements<SharedStringItem>().ToArray();

                            Dictionary<uint, uint> cacheCellFormat = new Dictionary<uint, uint>();
                            Dictionary<uint, uint> cacheCellStyleFormat = new Dictionary<uint, uint>();
                            Dictionary<uint, uint> cacheBorder = new Dictionary<uint, uint>();
                            Dictionary<uint, uint> cacheFill = new Dictionary<uint, uint>();
                            Dictionary<uint, uint> cacheFont = new Dictionary<uint, uint>();
                            Dictionary<uint, uint> cacheNumberFormat = new Dictionary<uint, uint>();
                            foreach (Cell cell in clonedSheet.Worksheet.Descendants<Cell>())
                            {
                                if (cell.DataType != null && cell.DataType == CellValues.SharedString)
                                {
                                    var ssindex = int.Parse(cell.CellValue.Text);
                                    cell.CellValue = new CellValue(InsertSharedStringItem_(values[ssindex].InnerText, workbookPartDestination.SharedStringTablePart).ToString());
                                }

                                if (cell.StyleIndex != null)
                                {
                                    cell.StyleIndex = GetCellFormat(workbookPartSource, workbookPartDestination, cacheCellFormat, cacheCellStyleFormat, cacheBorder, cacheFill, cacheFont, cacheNumberFormat, cell);
                                }
                            }

                            //Add new sheet to main workbook part
                            Sheets sheets = workbookPartDestination.Workbook.GetFirstChild<Sheets>();
                            Sheet copiedSheet = new Sheet
                            {
                                Name = sheet.Name,
                                Id = workbookPartDestination.GetIdOfPart(clonedSheet),
                                SheetId = (uint)sheets.ChildElements.Count + 1
                            };

                            if (replaced != 0)
                            {
                                copiedSheet.SheetId = replaced;
                                sheets.InsertAt(copiedSheet, index);
                            }
                            else
                            {
                                sheets.Append(copiedSheet);
                            }

                            //Save Changes
                            workbookPartDestination.Workbook.Save();
                        }
                    }
                }
            }
        }
        finally
        {
            if (spreadSheetStreamSource != null)
                spreadSheetStreamSource.Close();
            if (spreadSheetStreamDestination != null)
                spreadSheetStreamDestination.Close();
        }



    }



    private static uint GetCellFormat(WorkbookPart workbookPartSource, WorkbookPart workbookPartDestination, Dictionary<uint, uint> cacheCellFormat, Dictionary<uint, uint> cacheCellStyleFormat, Dictionary<uint, uint> cacheBorder, Dictionary<uint, uint> cacheFill, Dictionary<uint, uint> cacheFont, Dictionary<uint, uint> cacheNumberFormat, Cell cell)

    {

        uint cellFormatIndex, cellStyleFormatIndex;

        if (cacheCellFormat.Keys.Contains(cell.StyleIndex.Value))

        {

            cellFormatIndex = cacheCellFormat[cell.StyleIndex.Value];

        }

        else

        {

            CellFormat cellFormat = workbookPartSource.WorkbookStylesPart.Stylesheet.CellFormats.Descendants<CellFormat>().ToList()[int.Parse(cell.StyleIndex)];

            CellFormat cellFormatClone = CellFormatClone(workbookPartSource, workbookPartDestination, cacheBorder, cacheFill, cacheFont, cacheNumberFormat, cellFormat);

            if (cellFormat.FormatId != 0)

            {

                if (cacheCellStyleFormat.Keys.Contains(cellFormat.FormatId.Value))

                {

                    cellStyleFormatIndex = cacheCellStyleFormat[cellFormat.FormatId.Value];

                }

                else

                {

                    CellFormat cellStyleFormat = workbookPartSource.WorkbookStylesPart.Stylesheet.CellStyleFormats.Descendants<CellFormat>().ToList()[int.Parse(cellFormat.FormatId)];

                    if (workbookPartDestination.WorkbookStylesPart.Stylesheet.CellStyleFormats.Descendants<CellFormat>().ToList().Count > int.Parse(cellFormat.FormatId) &&

                        workbookPartDestination.WorkbookStylesPart.Stylesheet.CellStyleFormats.Descendants<CellFormat>().ToList()[int.Parse(cellFormat.FormatId)].OuterXml == cellStyleFormat.OuterXml)

                    {

                        cellStyleFormatIndex = (uint)int.Parse(cellFormat.FormatId);

                    }

                    else

                    {

                        CellFormat cellStyleFormatClone = CellFormatClone(workbookPartSource, workbookPartDestination, cacheBorder, cacheFill, cacheFont, cacheNumberFormat, cellStyleFormat);

                        workbookPartDestination.WorkbookStylesPart.Stylesheet.CellStyleFormats.Append(cellStyleFormatClone);

                        cellStyleFormatIndex = (uint)workbookPartDestination.WorkbookStylesPart.Stylesheet.CellStyleFormats.Descendants<CellFormat>().ToList().IndexOf(cellStyleFormatClone);

                        cacheCellStyleFormat.Add(cellFormat.FormatId.Value, cellStyleFormatIndex);

                    }

                }

                cellFormatClone.FormatId = cellStyleFormatIndex;

            }

            workbookPartDestination.WorkbookStylesPart.Stylesheet.CellFormats.Append(cellFormatClone);

            cellFormatIndex = (uint)workbookPartDestination.WorkbookStylesPart.Stylesheet.CellFormats.Descendants<CellFormat>().ToList().IndexOf(cellFormatClone);

            cacheCellFormat.Add(cell.StyleIndex.Value, cellFormatIndex);



        }

        return cellFormatIndex;

    }



    private static CellFormat CellFormatClone(WorkbookPart workbookPartSource, WorkbookPart workbookPartDestination, Dictionary<uint, uint> cacheBorder, Dictionary<uint, uint> cacheFill, Dictionary<uint, uint> cacheFont, Dictionary<uint, uint> cacheNumberFormat, CellFormat cellFormat)

    {

        CellFormat cellFormatClone = new CellFormat();

        cellFormatClone.ApplyAlignment = cellFormat.ApplyAlignment;

        cellFormatClone.ApplyBorder = cellFormat.ApplyBorder;

        cellFormatClone.ApplyFill = cellFormat.ApplyFill;

        cellFormatClone.ApplyFont = cellFormat.ApplyFont;

        cellFormatClone.ApplyNumberFormat = cellFormat.ApplyNumberFormat;

        cellFormatClone.ApplyProtection = cellFormat.ApplyProtection;

        cellFormatClone.PivotButton = cellFormat.PivotButton;

        cellFormatClone.QuotePrefix = cellFormat.QuotePrefix;

        GetBorder(workbookPartSource, workbookPartDestination, cacheBorder, cellFormat, cellFormatClone);

        GetFill(workbookPartSource, workbookPartDestination, cacheFill, cellFormat, cellFormatClone);

        GetFont(workbookPartSource, workbookPartDestination, cacheFont, cellFormat, cellFormatClone);

        GetNumberFormat(workbookPartSource, workbookPartDestination, cacheNumberFormat, cellFormat, cellFormatClone);

        if (cellFormat.Protection != null)

            cellFormatClone.Protection = (Protection)cellFormat.Protection.Clone();

        if (cellFormat.Alignment != null)

            cellFormatClone.Alignment = (Alignment)cellFormat.Alignment.Clone();

        return cellFormatClone;

    }



    private static void GetNumberFormat(WorkbookPart workbookPartSource, WorkbookPart workbookPartDestination, Dictionary<uint, uint> cacheNumberFormat, CellFormat cellFormat, CellFormat cellFormatClone)

    {

        uint numberFormatIndex = 0;

        if (cellFormat.NumberFormatId.Value != 0)

        {

            if (cacheNumberFormat.Keys.Contains(cellFormat.NumberFormatId.Value))

            {

                numberFormatIndex = cacheNumberFormat[cellFormat.NumberFormatId.Value];

            }

            else

            {

                NumberingFormat numberFormat = workbookPartSource.WorkbookStylesPart.Stylesheet.NumberingFormats.Descendants<NumberingFormat>().Where(nf => nf.NumberFormatId.Value == uint.Parse(cellFormat.NumberFormatId)).FirstOrDefault();

                if (numberFormat != null)
                {
                    if (workbookPartDestination.WorkbookStylesPart.Stylesheet.NumberingFormats != null)
                    {
                        if (workbookPartDestination.WorkbookStylesPart.Stylesheet.NumberingFormats.Descendants<NumberingFormat>().ToList().Count > int.Parse(cellFormat.NumberFormatId) &&
                        workbookPartDestination.WorkbookStylesPart.Stylesheet.NumberingFormats.Descendants<NumberingFormat>().ToList()[int.Parse(cellFormat.NumberFormatId)].OuterXml == numberFormat.OuterXml)
                        {
                            cellFormatClone.NumberFormatId = (uint)int.Parse(cellFormat.NumberFormatId);
                            return;
                        }

                        NumberingFormat nfclone = new NumberingFormat();
                        nfclone.FormatCode = numberFormat.FormatCode;
                        nfclone.NumberFormatId = workbookPartDestination.WorkbookStylesPart.Stylesheet.Descendants<NumberingFormat>().Max(nf => nf.NumberFormatId.Value) + 1;

                        workbookPartDestination.WorkbookStylesPart.Stylesheet.NumberingFormats.Append(nfclone);
                        numberFormatIndex = nfclone.NumberFormatId;
                        cacheNumberFormat.Add(cellFormat.NumberFormatId.Value, numberFormatIndex);
                    }
                }
                else
                {
                    numberFormatIndex = cellFormat.NumberFormatId;
                }
            }

            cellFormatClone.NumberFormatId = numberFormatIndex;
        }
        else
        {
            cellFormatClone.NumberFormatId = 0;
        }
    }



    private static void GetFont(WorkbookPart workbookPartSource, WorkbookPart workbookPartDestination, Dictionary<uint, uint> cacheFont, CellFormat cellFormat, CellFormat cellFormatClone)

    {

        uint fontIndex;

        if (cellFormat.FontId.Value != 0)

        {

            if (cacheFont.Keys.Contains(cellFormat.FontId.Value))

            {

                fontIndex = cacheFont[cellFormat.FontId.Value];

            }

            else

            {

                Font font = workbookPartSource.WorkbookStylesPart.Stylesheet.Fonts.Descendants<Font>().ToList()[int.Parse(cellFormat.FontId)];

                if (workbookPartDestination.WorkbookStylesPart.Stylesheet.Fonts.Descendants<Font>().ToList().Count > int.Parse(cellFormat.FontId) &&

               workbookPartDestination.WorkbookStylesPart.Stylesheet.Fonts.Descendants<Font>().ToList()[int.Parse(cellFormat.FontId)].OuterXml == font.OuterXml)

                {

                    cellFormatClone.FontId = (uint)int.Parse(cellFormat.FontId);

                    return;

                }

                Font fontClone = new Font();

                if (font.Bold != null)

                    fontClone.Bold = (Bold)font.Bold.Clone();

                if (font.Color != null)

                    fontClone.Color = (Color)font.Color.Clone();

                if (font.Condense != null)

                    fontClone.Condense = (Condense)font.Condense.Clone();

                if (font.Extend != null)

                    fontClone.Extend = (Extend)font.Extend.Clone();

                if (font.FontCharSet != null)

                    fontClone.FontCharSet = (FontCharSet)font.FontCharSet.Clone();

                if (font.FontName != null)

                    fontClone.FontName = (FontName)font.FontName.Clone();

                if (font.FontScheme != null)

                    fontClone.FontScheme = (FontScheme)font.FontScheme.Clone();

                if (font.FontSize != null)

                    fontClone.FontSize = (FontSize)font.FontSize.Clone();

                if (font.Italic != null)

                    fontClone.Italic = (Italic)font.Italic.Clone();

                if (font.Outline != null)

                    fontClone.Outline = (Outline)font.Outline.Clone();

                if (font.Shadow != null)

                    fontClone.Shadow = (Shadow)font.Shadow.Clone();

                if (font.Strike != null)

                    fontClone.Strike = (Strike)font.Strike.Clone();

                if (font.Underline != null)

                    fontClone.Underline = (Underline)font.Underline.Clone();

                if (font.VerticalTextAlignment != null)

                    fontClone.VerticalTextAlignment = (VerticalTextAlignment)font.VerticalTextAlignment.Clone();

                if (font.FontFamilyNumbering != null)

                    fontClone.FontFamilyNumbering = (FontFamilyNumbering)font.FontFamilyNumbering.Clone();





                workbookPartDestination.WorkbookStylesPart.Stylesheet.Fonts.Append(fontClone);

                fontIndex = (uint)workbookPartDestination.WorkbookStylesPart.Stylesheet.Fonts.Descendants<Font>().ToList().IndexOf(fontClone);

                cacheFont.Add(cellFormat.FontId.Value, fontIndex);

            }

            cellFormatClone.FontId = fontIndex;

        }

        else

        {

            cellFormatClone.FontId = 0;

        }

    }



    private static void GetFill(WorkbookPart workbookPartSource, WorkbookPart workbookPartDestination, Dictionary<uint, uint> cacheFill, CellFormat cellFormat, CellFormat cellFormatClone)

    {

        uint fillIndex;

        if (cellFormat.FillId.Value != 0)

        {

            if (cacheFill.Keys.Contains(cellFormat.FillId.Value))

            {

                fillIndex = cacheFill[cellFormat.FillId.Value];

            }

            else

            {

                Fill fill = workbookPartSource.WorkbookStylesPart.Stylesheet.Fills.Descendants<Fill>().ToList()[int.Parse(cellFormat.FillId)];

                if (workbookPartDestination.WorkbookStylesPart.Stylesheet.Fills.Descendants<Fill>().ToList().Count > int.Parse(cellFormat.FillId) &&

                  workbookPartDestination.WorkbookStylesPart.Stylesheet.Fills.Descendants<Fill>().ToList()[int.Parse(cellFormat.FillId)].OuterXml == fill.OuterXml)

                {

                    cellFormatClone.FillId = (uint)int.Parse(cellFormat.FillId);

                    return;

                }

                Fill fillclone = new Fill();

                if (fill.GradientFill != null)

                    fillclone.GradientFill = (GradientFill)fill.GradientFill.Clone();

                if (fill.PatternFill != null)

                    fillclone.PatternFill = (PatternFill)fill.PatternFill.Clone();



                workbookPartDestination.WorkbookStylesPart.