首页 > 编程语言 >c#树结构转npoi复杂表头

c#树结构转npoi复杂表头

时间:2024-01-30 16:38:15浏览次数:19  
标签:Childrens Title c# 树结构 表头 int FirstRow new LastRow

Vue 前端框架框架中采用树结构打印表头,为了前后端适配NPOI导出。

这里重点做树结构转换 NPOI 复杂表头的结构数据( 跨行、跨列),其它具体导出功能请参考  https://www.cnblogs.com/lwk9527/p/17374291.html

 

导出后实际效果

 源数据 json 版

[
    {
        "Title":"账号",
        "Childrens":null
    },
    {
        "Title":"姓名",
        "Childrens":null
    },
    {
        "Title":"语文",
        "Childrens":[
            {
                "Title":"成绩",
                "Childrens":null
            },
            {
                "Title":"用时",
                "Childrens":null
            },
            {
                "Title":"完成次数",
                "Childrens":null
            }
        ]
    },
    {
        "Title":"数学",
        "Childrens":[
            {
                "Title":"成绩",
                "Childrens":null
            },
            {
                "Title":"用时",
                "Childrens":null
            },
            {
                "Title":"完成次数",
                "Childrens":null
            }
        ]
    }
]

转换后的到的数据 json 版

[
    {
        "FirstRow":0,
        "LastRow":1,
        "FirstCol":0,
        "LastCol":0,
        "Value":"账号"
    },
    {
        "FirstRow":0,
        "LastRow":1,
        "FirstCol":1,
        "LastCol":1,
        "Value":"姓名"
    },
    {
        "FirstRow":1,
        "LastRow":1,
        "FirstCol":2,
        "LastCol":2,
        "Value":"成绩"
    },
    {
        "FirstRow":1,
        "LastRow":1,
        "FirstCol":3,
        "LastCol":3,
        "Value":"用时"
    },
    {
        "FirstRow":1,
        "LastRow":1,
        "FirstCol":4,
        "LastCol":4,
        "Value":"完成次数"
    },
    {
        "FirstRow":0,
        "LastRow":0,
        "FirstCol":2,
        "LastCol":4,
        "Value":"语文"
    },
    {
        "FirstRow":1,
        "LastRow":1,
        "FirstCol":5,
        "LastCol":5,
        "Value":"成绩"
    },
    {
        "FirstRow":1,
        "LastRow":1,
        "FirstCol":6,
        "LastCol":6,
        "Value":"用时"
    },
    {
        "FirstRow":1,
        "LastRow":1,
        "FirstCol":7,
        "LastCol":7,
        "Value":"完成次数"
    },
    {
        "FirstRow":0,
        "LastRow":0,
        "FirstCol":5,
        "LastCol":7,
        "Value":"数学"
    }
]

c# 案例

public void TestMethod0()
        {
            //源数据
            List<HeadData> headDatas = new List<HeadData>();
            headDatas.Add(new HeadData() { Title= "账号" });
            headDatas.Add(new HeadData() { Title = "姓名" });
            List<HeadData> subHeadDatas = new List<HeadData>();
            subHeadDatas.Add(new HeadData() { Title = "成绩" });
            subHeadDatas.Add(new HeadData() { Title = "用时" });
            subHeadDatas.Add(new HeadData() { Title = "完成次数"});
            headDatas.Add(new HeadData() { Title = "语文",Childrens= subHeadDatas });
            List<HeadData> subHeadDatas2 = new List<HeadData>();
            subHeadDatas2.Add(new HeadData() { Title = "成绩" });
            subHeadDatas2.Add(new HeadData() { Title = "用时" });
            subHeadDatas2.Add(new HeadData() { Title = "完成次数" });
            headDatas.Add(new HeadData() { Title = "数学", Childrens = subHeadDatas2});
            //转换后数据集
            List<ExcelHeader> headers = new List<ExcelHeader>();
            int firstRow = 0;
            int firstCol = 0;
            //获取树最大层次深度 (用于计算跨行)
            int maxLevel= CalculateMaxLevel(headDatas);
            DataConvert(headDatas, headers, firstRow, firstCol, maxLevel);//初始化
            IWorkbook workbook = new HSSFWorkbook();
            //工作簿
            ISheet sheetTable = workbook.CreateSheet();
            //生成表头
            foreach (var item in headers)
            {
                IRow headerRow = sheetTable.GetRow(item.FirstRow);
                if (headerRow == null)
                {
                    headerRow = sheetTable.CreateRow(item.FirstRow);
                    //行高,避免自动换行的内容将行高撑开
                    headerRow.HeightInPoints = 24;
                }
                ICell headerCell = headerRow.CreateCell(item.FirstCol);
                headerCell.SetCellValue(item.Value);
                //设置跨行
                if (item.FirstRow != item.LastRow || item.LastCol != item.FirstCol)
                {
                    //CellRangeAddress(开始行,结束行,开始列,结束列)
                    //行列索引由0开始
                    var region = new CellRangeAddress(item.FirstRow, item.LastRow, item.FirstCol, item.LastCol);
                    sheetTable.AddMergedRegion(region);
                }
              // headerCell.CellStyle = HeaderStyle(workbook);
            }


            // 创建一个工作表
            ISheet sheet = workbook.CreateSheet("ComplexHeader");

            // 将工作簿写入文件
            using (var fileStream = new System.IO.FileStream("ComplexHeader.xlsx", System.IO.FileMode.Create, System.IO.FileAccess.Write))
            {
                workbook.Write(fileStream, true);
            }
        }
        /// <summary>
        /// 数据转换
        /// </summary>
        /// <param name="HeadDatas"></param>
        /// <param name="headers"></param>
        /// <param name="startRow"></param>
        /// <param name="startCol"></param>
        /// <param name="maxLevel"></param>
        /// <param name="level"></param>
        public void DataConvert(List<HeadData> HeadDatas, List<ExcelHeader> headers,int startRow, int startCol,int maxLevel=2,int level=0)
        {
            foreach (var head in HeadDatas)
            {
                int LastCol = startCol;
                int LastRow = startRow;
               
                if (head.Childrens != null && head.Childrens.Count > 0)
                {
                    DataConvert(head.Childrens, headers, startRow + 1, startCol, maxLevel,level+1);
                }
                else
                {
                    LastRow =startRow+(maxLevel - level);
                }
                int lastCol = startCol;
                int colLength = GetTotalChildrenCount(head);
                if (colLength > 0)
                {
                    lastCol= startCol + colLength-1;
                }
                headers.Add(new ExcelHeader() { FirstRow = startRow, LastRow = LastRow, FirstCol = startCol, LastCol = lastCol, Value = head.Title });

                startCol= lastCol+1;
            }
        }
        /// <summary>
        /// 获取树结构最大深度
        /// </summary>
        /// <param name="nodes"></param>
        /// <param name="level"></param>
        /// <returns></returns>
        static int CalculateMaxLevel(List<HeadData> nodes, int level=0)
        {
            int maxLevel = level; // 初始级别为当前级别  
            foreach (var node in nodes)
            {
                if (node.Childrens != null) // 检查是否有子节点  
                {
                    int childLevel = CalculateMaxLevel(node.Childrens, level + 1); // 递归调用以获取子节点的最大级别  
                    maxLevel = Math.Max(maxLevel, childLevel); // 更新最大级别值  
                }
            }
            return maxLevel;
        }
        /// <summary>
        /// 获取所有子节点数量
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        public static int GetTotalChildrenCount(HeadData node)
        {
            if (node == null) return 0; // 基础情况:节点为空,返回0  
            if (node.Childrens == null) return 0; // 基础情况:子节点列表为空,返回0  
            return node.Childrens.Count + node.Childrens.Sum(child => GetTotalChildrenCount(child)); // 递归调用  
        }

 

标签:Childrens,Title,c#,树结构,表头,int,FirstRow,new,LastRow
From: https://www.cnblogs.com/xiaobao6652/p/17997229

相关文章

  • 美赛2023C练习-做题笔记
    代码:clc;TC=ProblemCDataWordle;%数据处理noC=TC(:,1);wordC=TC(:,2);dataC=TC(:,3:11);no=cell2mat(noC);data=cell2mat(dataC);L=size(wordC);L=L(1);word=[];%原表格有错误,根据网络数据进行修正wordC{36}="clean";wordC{247}="trash";%修正endfori=1:L......
  • gitclone正常,但是git submodule报错Permission denied
    根本原因是,git这种形式没有权限参考https://www.hangge.com/blog/cache/detail_1561.html......
  • Qt QCustomPlot使用教程
    (一)——安装与配置1、下载去QtPlottingWidgetQCustomPlot-Download下载需要版本的QCustomPlot的压缩包QCustomPlot.tar.gz,下载解压后会得到qcustomplot的.cpp与.h文件,这两个文件是我们需要的。2、添加到项目①把这两个文件复制粘贴到项目下;②右键点击项目名......
  • Vulkan学习苦旅04:创建设备(逻辑设备VkDevice)
    设备是对物理设备的一种抽象,使我们更加方便地使用它。更准确地说,应该称其为“逻辑设备”,但由于逻辑设备在Vulkan中极为常用,后面几乎所有的API都需要它作为第一个参数,因此在Vulkan中直接简称为设备。1.实例、物理设备与设备的关系在之前的几篇文章中,我们依次创建了实例和物理设......
  • 分布式压测之locust和Jmeter的使用
    受限于单台机器的配置问题,我们在单台机器上达不到一个很高的压测并发数,那这个时候就需要引入分布式压测分布式压测原理:一般通过局域网把不同测试计算机链接到一起,达到测试共享、分散操作、集中管理的目的。选择一台作为调度机(MASTER),其他机器作为执行机(SLAVE)执行完成执行机会......
  • C语言学习第九天
    一、分支语句(if switch)语法结构:if(表达式)语句;if(表达式)语句1:else语句2;//多分支if(表达式)语句1;elseif(表达式)语句2;else语句3;示例代码:intmain(){ intage=0; printf("输入你的年龄:"); scanf_s("%d",&age); if(age<18) pr......
  • 【scikit-learn基础】--『回归模型评估』之损失分析
    分类模型评估中,通过各类损失(loss)函数的分析,可以衡量模型预测结果与真实值之间的差异。不同的损失函数可用于不同类型的分类问题,以便更好地评估模型的性能。本篇将介绍分类模型评估中常用的几种损失计算方法。1.汉明损失Hammingloss(汉明损失)是一种衡量分类模型预测错误率的指......
  • [USACO10FEB] Chocolate Eating
    原题链接很典型的二分答案题目。但是新颖点是他要输出每块巧克力在哪一天吃,很多人(包括我自己)就可能想当然的直接在累加的时候处理,如下:for(inti=1;i<=d;i++){sum/=2;while(sum<m){if(cnt>n)returnfalse;sum+=a[cnt];......
  • .Net Core3.1 升级到8.0(3.1升级到更高版本)
    NETCore3.1已经用了很长一段时间,其实在2022年的年底微软已经不提供支持了,后面的一个 LTS 版本.NET6也会在2024年11月终止支持,所以直接升级到.NET8是最好的选择。微软官方推出了升级工具:UpgradeAssistant,链接地址如下:https://dotnet.microsoft.com/zh-cn/plat......
  • P2870 [USACO07DEC] Best Cow Line G
    https://www.luogu.com.cn/problem/P2870字典序最小显然贪心,若当前串首比串尾小,则取串首;若当前串首比串尾大,则取串尾。那串首串尾一样呢?这个顺序显然会影响到后续操作。考虑继续往内递归,如果碰到一样的,那么当前取什么都无所谓;若碰到不一样的,我们肯定是要取更小的那一边,因为这样......