Jacoco XML 解析

1 XML解析器对比

1. DOM解析器:

○ 优点:易于使用,提供完整的文档树,可以方便地修改和遍历XML文档。
○ 缺点:对大型文档消耗内存较多,加载整个文档可能会变慢。
○ 适用场景:适合小型XML文档或需要多次访问和修改XML内容的情况。

2. SAX解析器:

○ 优点:逐个处理XML元素,节省内存,适用于一次性遍历大型XML文档。
○ 缺点:编写处理事件的代码可能会相对复杂,不适合需要频繁修改XML内容的情况。
○ 适用场景:适合大型XML文档的读取、分析和提取数据。

3. StAX解析器:

○ 优点:结合了DOM和SAX的优点,提供了灵活的编程模型,适用于流式处理和部分内存加载。
○ 缺点:可能比纯粹的SAX稍微复杂一些。
○ 适用场景:适合需要处理中等大小的XML文档,同时保持较低内存占用的情况。

4. XPath解析器:

○ 优点:提供了强大的查询功能,能够方便地定位XML文档中的元素和数据。
○ 缺点:可能会稍微降低性能,特别是在复杂的查询情况下。
○ 适用场景:适合需要定位和提取特定数据的情况,可以减少手动遍历和解析的工作。

5. JSON对应XML解析器:

○ 优点:可以将XML数据转换为JSON格式,利用JSON解析器处理。
○ 缺点:可能会导致数据结构转换复杂性,不是所有情况下都适用。
○ 适用场景:当您的应用程序使用JSON格式处理数据,但需要处理XML数据时,可以考虑此类解析器。

解析的jacoco XML数据量较多 行数至几十万行 XML大小为 数十M
选择SAX解析器进行解析

2 解析思路

SAX可以逐行处理标签
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

/*** @author xieyan* @date 2023-08-22 16:13*/
public class JacocoXmlConstant {public static final String COUNTER = "counter";public static final String METHOD = "method";public static final String CLASS = "class";public static final String SOURCEFILE = "sourcefile";public static final String SOURCEFILE_NAME = "name";public static final String COUNTER_TYPE = "type";public static final String COUNTER_MISSED = "missed";public static final String COUNTER_COVERED = "covered";public static final String METHOD_NAME = "name";public static final String METHOD_DESC = "desc";public static final String CLASS_NAME = "name";public static final String CLASS_SOURCEFILENAME = "sourcefilename";public static final String REPORT_NAME = "name";public static final String PACKAGE_NAME = "name";public static final String REPORT = "report";public static final String PACKAGE = "package";public static final String SESSIONINFO = "sessioninfo";public static final String LINE = "line";public static final String INSTRUCTION_TYPE = "INSTRUCTION";public static final String BRANCH_TYPE = "BRANCH";public static final String LINE_TYPE = "LINE";public static final String COMPLEXITY_TYPE = "COMPLEXITY";public static final String METHOD_TYPE = "METHOD";public static final String CLASS_TYPE = "CLASS";}import lombok.Getter;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;import java.util.List;import static com.jacoco.xml.JacocoXmlConstant.*;/*** 解析xml文件** @author xieyan*/
@Getter
public class ParseXmlHandler extends DefaultHandler {private Report report;private Package currentPackage;private Clazz currentClass;private Method currentMethod;private Counter currentCounter;private String sourcefile;/*** 开始解析元素时触发*/@Overridepublic void startElement(String uri, String localName, String qName, Attributes attributes) {switch (qName) {// 跳过 sessioninfo 和 linecase SESSIONINFO:case LINE:return;// 解析reportcase REPORT:report = new Report();report.setName(attributes.getValue(REPORT_NAME));break;// 解析packagecase PACKAGE:currentPackage = new Package();currentPackage.setName(attributes.getValue(PACKAGE_NAME));if (report != null) {report.addPackage(currentPackage);}break;// 解析classcase CLASS:currentClass = new Clazz();currentClass.setName(attributes.getValue(CLASS_NAME));currentClass.setSourcefilename(attributes.getValue(CLASS_SOURCEFILENAME));if (currentPackage != null) {currentPackage.addClass(currentClass);}break;// 解析methodcase METHOD:currentMethod = new Method();currentMethod.setName(attributes.getValue(METHOD_NAME));currentMethod.setDesc(attributes.getValue(METHOD_DESC));if (currentClass != null) {currentClass.addMethod(currentMethod);}break;// 解析sourcefilecase SOURCEFILE:sourcefile = attributes.getValue(SOURCEFILE_NAME);break;// 解析countercase COUNTER:currentCounter = new Counter();currentCounter.setType(attributes.getValue(COUNTER_TYPE));currentCounter.setMissed(Integer.parseInt(attributes.getValue(COUNTER_MISSED)));currentCounter.setCovered(Integer.parseInt(attributes.getValue(COUNTER_COVERED)));// 绑定counter 到对应的元素bindCounter();break;default:break;}}/*** 结束解析元素时触发*/@Overridepublic void endElement(String uri, String localName, String qName) {switch (qName) {case SESSIONINFO:case LINE:// 跳过 sessioninfo 和 linereturn;case SOURCEFILE:// 避免重复加入 counter 到 pagesourcefile = null;break;case REPORT:// 计算总的覆盖率Coverage coverageReport = caculateCoverage(report.getReportCounters());report.setReportCoverage(coverageReport);break;case PACKAGE:// 计算 package 覆盖率if (currentPackage != null) {Coverage coveragePackage = caculateCoverage(currentPackage.getPackageCounters());currentPackage.setPackageCoverage(coveragePackage);currentPackage = null;}break;case CLASS:// 计算 class 覆盖率if (currentClass != null) {Coverage coverageClass = caculateCoverage(currentClass.getClazzCounters());currentClass.setClazzCoverage(coverageClass);currentClass = null;}break;case METHOD:// 计算 method 覆盖率if (currentMethod != null) {Coverage coverageMethod = caculateCoverage(currentMethod.getMethodCounters());currentMethod.setMethodCoverage(coverageMethod);currentMethod = null;}break;case COUNTER:currentCounter = null;break;default:break;}}/*** 绑定counter 到对应的元素*/private void bindCounter() {// counter 属于 methodif (currentMethod != null) {currentMethod.addCounter(currentCounter);}// counter 属于 classelse if (currentClass != null) {currentClass.addCounter(currentCounter);}// counter 属于 packageelse if (currentPackage != null) {// 跳过sourcefile里的counter 避免重复加入if (sourcefile == null) {currentPackage.addCounter(currentCounter);}}// counter 属于 reportelse if (report != null) {report.addCounter(currentCounter);}}/*** 计算覆盖率*/private Coverage caculateCoverage(List<Counter> counterList) {Coverage result = new Coverage();for (Counter counter : counterList) {String type = counter.getType().toUpperCase();String coverage = processResult(counter);setCoverageByType(result, type, coverage);}return result;}private void setCoverageByType(Coverage result, String type, String coverage) {switch (type) {// 指令覆盖率case INSTRUCTION_TYPE:result.setInstructionCoverage(coverage);break;// 行覆盖率case LINE_TYPE:result.setLineCoverage(coverage);break;// 分支覆盖率case BRANCH_TYPE:result.setBranchCoverage(coverage);break;// 圈复杂度覆盖率case COMPLEXITY_TYPE:result.setComplexityCoverage(coverage);break;// 方法覆盖率case METHOD_TYPE:result.setMethodCoverage(coverage);break;// 类覆盖率case CLASS_TYPE:result.setClassCoverage(coverage);break;default:break;}}/*** 处理覆盖率结果* 保留两位小数 例如 99.99%*/private String processResult(Counter counter) {int missed = counter.getMissed();int covered = counter.getCovered();double coverage = (double) covered / (missed + covered);double coveragePercentage = coverage * 100;return String.format("%.2f%%", coveragePercentage);}}import lombok.Data;import java.util.ArrayList;
import java.util.List;/*** @author xieyan*/
@Data
public class Clazz {private String name;private String sourcefilename;private final List<Method> methods = new ArrayList<>();private final List<Counter> clazzCounters = new ArrayList<>();private Coverage clazzCoverage;public void addMethod(Method method) {methods.add(method);}public void addCounter(Counter counter) {clazzCounters.add(counter);}}import lombok.Data;/*** @author xieyan*/
@Data
public class Counter {private String type;private int missed;private int covered;}import lombok.Data;/*** 覆盖率统计* @author xieyan* @date 2021-08-22 16:13*/
@Data
public class Coverage {/*** 指令覆盖率*/private String instructionCoverage;/** * 分支覆盖率*/private String branchCoverage;/*** 行覆盖率*/private String lineCoverage;/*** 圈复杂度覆盖率*/private String complexityCoverage;/*** 方法覆盖率 */private String methodCoverage;/*** 类覆盖率*/private String classCoverage;
}Method
import lombok.Data;import java.util.ArrayList;
import java.util.List;/*** @author xieyan*/
@Data
public class Method {private String name;private String desc;private final List<Counter> methodCounters = new ArrayList<>();private Coverage methodCoverage;public void addCounter(Counter counter) {methodCounters.add(counter);}}import lombok.Data;import java.util.ArrayList;
import java.util.List;/*** @author xieyan*/
@Data
public class Package {private String name;private final List<Clazz> classes = new ArrayList<>();private final List<Counter> packageCounters = new ArrayList<>();private Coverage packageCoverage;public void addClass(Clazz clazz) {classes.add(clazz);}public void addCounter(Counter counter) {packageCounters.add(counter);}}@Data
public class Report {private String name;private final List<Package> packages = new ArrayList<>();private final List<Counter> reportCounters = new ArrayList<>();private Coverage reportCoverage;public void addPackage(Package pkg) {packages.add(pkg);}public void addCounter(Counter counter) {reportCounters.add(counter);}}import lombok.extern.slf4j.Slf4j;
import org.xml.sax.SAXException;import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;/*** 解析jacoco覆盖率报告工具类* @author xieyan* @date 2023-08-22 16:38*/
@Slf4j
public class ParseJacocoXmlUtil {/*** 解析jacoco覆盖率报告** @param xmlPath jacoco覆盖率报告路径* @return 解析后的报告对象,解析失败时返回null*/public static Report parse(String xmlPath) {try {SAXParserFactory factory = SAXParserFactory.newInstance();// 禁用DTD验证factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);SAXParser saxParser = factory.newSAXParser();// 读取xml文件File xmlFile = new File(xmlPath);ParseXmlHandler handler = new ParseXmlHandler();try (InputStream inputStream = xmlFile.toURI().toURL().openStream()) {// 解析XML文件saxParser.parse(inputStream, handler);return handler.getReport();}} catch (ParserConfigurationException | SAXException | IOException e) {log.error("解析jacoco xml 覆盖率报告失败", e);}return null;}
}public class SaxParsingToJavaObjectExample {public static void main(String[] args) {// 指定XML文件路径String xmlFilePath = "D:\\tmp\\jacoco.xml";//String xmlFilePath = "F:\\temp\\a.xml";Report report = ParseJacocoXmlUtil.parse(xmlFilePath);Optional.ofNullable(report).ifPresent(SaxParsingToJavaObjectExample::export);}public static void export(Report report) {for (Package pkg : report.getPackages()) {System.out.println("Package Name: " + pkg.getName());for (Clazz clazz : pkg.getClasses()) {System.out.println("Class Name: " + clazz.getName());for (Method method : clazz.getMethods()) {System.out.println("Method Name: " + method.getName());System.out.println("Method Description: " + method.getDesc());for (Counter counter : method.getMethodCounters()) {System.out.println("Counter Type: " + counter.getType());System.out.println("Counter Missed: " + counter.getMissed());System.out.println("Counter Covered: " + counter.getCovered() + "\n");}System.out.println("==================== Method ==========================================");}}}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/112479.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

报错sql_mode=only_full_group_by

首发博客地址 https://blog.zysicyj.top/ 报错内容 ### The error may exist in file[D:\code\cppCode20221025\leader-system\target\classes\mapper\system\TJsonDataMapper.xml] ### The error may involve defaultParameterMap ### The error occurred while…

前端最能打的本地存储方案

产品的原话就是“要又大又全”。既然存储量大&#xff0c;也要覆盖全多种设备多种浏览器。 方案选择 既然要存储的数量大&#xff0c;得排除cookielocalStorage&#xff0c;虽然比cookie多&#xff0c;但是同样有上限&#xff08;5M&#xff09;左右&#xff0c;备选websql 使…

无涯教程-Python机器学习 - Extra Trees函数

它是袋装决策树集成方法的另一种扩展。在这种方法中,从训练数据集的样本中构建随机树。 在以下Python食谱中,我们将通过在Pima Indians糖尿病数据集上使用sklearn的ExtraTreesClassifier类来构建额外的树集成模型。 首先,导入所需的软件包,如下所示: from pandas import rea…

Centos7安装ZK-UI管理界面安装|Maven|Git|

一: JDK1.8安装 参考: Centos7卸载|安装JDK1.8|Xshell7批量控制多个终端 二&#xff1a;Maven安装 2.1&#xff1a;下载maven安装包 maven 下载地址&#xff1a;https://mirror.bit.edu.cn/apache/maven/maven-3/ [rootwww ~]# mkdir -p /usr/local/maven [rootwww ~]# …

HTTP:http上传文件的原理及java处理方法的介绍

为了说明原理&#xff0c;以下提供一个可以上传多个文件的例子&#xff0c;html页面代码如下&#xff1a; <!DOCTYPE html> <html> <head> <meta charset"UTF-8"> <title>http upload file</title> </head> <body>…

Http 1.0 1.1 2.0 3.0 版本差别

Http 1.0 发布年份&#xff1a;1996 非官方标准 短链接&#xff1a;每一次请求都对应一次TCP的连接与释放 开销大&#xff1a;每次请求都要TCP的连接与释放队头阻塞&#xff1a;每次请求都必须等上一次请求获得响应之后&#xff0c;才可以发送&#xff1b;效率低下 缓存&…

非煤矿山风险监测预警算法 yolov8

非煤矿山风险监测预警算法通过yolov8网络模型深度学习算法框架&#xff0c;非煤矿山风险监测预警算法在煤矿关键地点安装摄像机等设备利用智能化视频识别技术&#xff0c;能够实时分析人员出入井口的情况&#xff0c;人数变化并检测作业状态。YOLO的结构非常简单&#xff0c;就…

Typora mac版本安装

提示&#xff1a;文章介绍&#xff0c;Typora在Mac系统中免费安装使用 文章目录 一、官网下载二、安装 一、官网下载 官网地址&#xff1a;https://www.typoraio.cn/ 二、安装 安装好后按 command 空格键&#xff0c;找到 Typora的安装路径 /Applications/Typora.app/Con…

Linux特殊指令

目录 1.dd命令 2.mkfs格式化 3.df命令 4.mount实现硬盘的挂载 5.unshare 1.dd命令 dd命令可以用来读取转换并输出数据。 示例一&#xff1a; if表示infile&#xff0c;of表示outfile。这里的/dev/zero是一个特殊文件&#xff0c;会不断产生空白数据。 bs表示复制一块的大…

【Java架构-版本控制】-Git基础

本文摘要 Git作为版本控制工具&#xff0c;使用非常广泛&#xff0c;在此咱们由浅入深&#xff0c;分三篇文章&#xff08;Git基础、Git进阶、Gitlab搭那家&#xff09;来深入学习Git 文章目录 本文摘要1.Git仓库基本概念1.1 远程仓库(Remote)1.2 本地库(Repository) 2. Git仓库…

新兴崛起的优雅框架Mybatis-Flex

目录 介绍 基础使用 简单入门 插入数据 insertSelective insertOrUpdate insertBatch 注意事项 删除数据 ​编辑 条件删除 批量删除 注意事项 更新数据 ​编辑 条件更新 UpdateEntity使用 UpdaerWrapper使用 注意事项 查询数据 查询一条数据 selectOneById​编辑 …

Web开发模式、API接口、restful规范、序列化和反序列化、drf安装和快速使用、路由转换器(复习)

一 Web开发模式 1. 前后端混合开发模式 前后端混合开发模式是一种开发方式&#xff0c;将前端和后端的开发工作结合在一起&#xff0c;以加快项目的开发速度和 提高协作效率。这种模式通常用于快速原型开发、小型项目或敏捷开发中。在前后端混合开发模式中&#xff0c;前端和…

改进YOLOv8系列:原创改进创新点 SIoU-NMS,EIoU-NMS,DIoU-NMS,CIoU-NMS,GIoU-NMS改进

💡该教程为属于《芒果书》📚系列,包含大量的原创首发改进方式, 所有文章都是全网首发原创改进内容🚀 💡本篇文章为YOLOv8独家原创改进:原创改进创新点 DIoU-NMS,SIoU-NMS,EIoU-NMS,CIoU-NMS,GIoU-NMS改进。 💡对自己数据集改进有效的话,可以直接当做自己的原创改…

NSS [羊城杯 2020]easyser

NSS [羊城杯 2020]easyser 开题。很容易让人觉得环境坏了。 不要慌&#xff0c;无从下手时。看源码、扫目录、抓包。一套操作下来&#xff0c;发现几个可以下手的路由。 /index.php /robots.txt 访问 /star1.php&#xff0c;一说到百度&#xff0c;就猜测是否存在SSRF。 源码中…

Linux x86_64 C语言实现gdb断点机制

文章目录 前言一、trap指令简介二、调用ptrace三、创建breakpoints四、CONT 和 SINGLESTEP五、完整代码演示六、增加参数检测参考资料 前言 本文参考文章&#xff1a;Implementing breakpoints on x86 Linux 一、trap指令简介 将通过在断点地址向目标进程的内存中插入一条新…

图像二值化

目录 1.固定值二值化 2.自适应阈值二值化 3.Android JNI完整代码 1.固定值二值化 固定阈值二值化是OpenCV中一种简单而常用的图像处理技术&#xff0c;用于将图像转换为二值图像。在固定阈值二值化中&#xff0c;像素值根据一个预定义的阈值进行分类&#xff0c;大于阈值的…

c语言实现二叉树(链式结构)

文章目录 前言一、二叉树的遍历1、二叉树的层序遍历2、二叉树的前序遍历3、二叉树的中序遍历4、二叉树的后序遍历5、代码实现 二、二叉树的一些操作的实现1、求二叉树的结点个数2、求二叉树叶子结点个数3、求二叉树第k层结点个数4、求二叉树深度5、二叉树中查找值为x的结点6、二…

streamlit-高级功能

缓存 st.cache_data st.cache_resource 为应用程序添加会话状态 会话状态 会话状态应用到应用程序 会话状态和小部件关联 可序列化会话状态 注意事项和限制 命令行选项 应用程序菜单 菜单选项 开发者选项 streamlit配置 按钮行为和示例 连接到数据 数据框 形式 小部件语义 …

前端vue引入高德地图入门教程

距离上一篇关于前端项目中使用高德地图的文章已经将近5年之久&#xff0c; 这是我的第一篇关于高德地图的文章 这期间前端技术日新月异&#xff0c;5年前JQuery还如日中天&#xff0c;如今已经销声匿迹&#xff0c;很少有公司招聘还在要求JQuery&#xff0c;更多的是Vue、React…

keras深度学习框架构建LeNet5神经网络模型实现手写数字识别

之前两篇文章分别通过keras深度学习框架构建简单神经网络和卷积神经网络实现过手写数字识别实验。这篇文章分享我根据LeNet5模型构建的卷积神经网络来实现手写数字识别。 这个实验是根据LeNet5模型构建卷积神经网络&#xff0c;LeNet5模型的原理图如下所示&#xff1a; 相信大家…