groovy XmlParser 递归遍历 xml 文件,修改并保存

news2024/11/19 3:45:07

在这里插入图片描述

使用 groovy.util.XmlParser 解析 xml 文件,对文件进行修改(新增标签),然后保存。

是不是 XmlParser 没有提供方法遍历每个节点,难道要自己写?

什么是递归?

不用说,想必都懂得~

import ***.XmlNodeCallback;
import ***.PluginLog;

import org.xml.sax.SAXException;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;

import groovy.util.Node;
import groovy.util.XmlParser;
import groovy.xml.XmlUtil;


public class PluginXmlUtil {
	 /**
     * 
     * @param xmlFile   需要解析的 xml 文件
     * @param callback  回调每一个标签 node,可以对 node 进行 CURD
     * @return
     */
    public static Node parseXml(File xmlFile, XmlNodeCallback callback) {
        if (CommUtils.isEmptyOrNoExists(xmlFile)) {
            return null;
        }

        try {
            Node rootNode = new XmlParser().parse(xmlFile);
            traverseNode(rootNode, callback);
            return rootNode;
        } catch (IOException e) {
        } catch (SAXException e) {
        } catch (ParserConfigurationException e) {
        }

        return null;
    }

    /**
     * 
     * @param node          需要保存的往往是根节点 node(当然保存你想要的任意节点也是可以)
     * @param targetFile    保存文件
     * @return
     */
    public static boolean saveNodeToFile(Node node, File targetFile) {
        if (node == null || targetFile == null) {
            return false;
        }

        try {
        	// 使用 groovy 提供的 xml 序列化工具获得原始字符串
            String finalContent = XmlUtil.serialize(node);
            if (CommUtils.isEmptyOrNoExists(finalContent)) {
                return false;
            }
            // 使用 TRUNCATE_EXISTING,如果文件存在,那么截取长度为0(也就是覆盖文件内容),然后写入新内容
            Files.write(targetFile.toPath(), finalContent.getBytes(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
            return true;
        } catch (IOException e) {
        }
        return false;
    }


    /**
     * 递归会写吧~
     * 
     * @param rootNode      根节点
     * @param callback      把每个 node 回调返回给外部,在回调中可操作 node 等
     */
    private static void traverseNode(Node node, XmlNodeCallback callback) {
        if (node == null) {
            return;
        }

        if (callback != null) {
            callback.onNode(node);
        }

        List<Object> children = node.children();
        boolean hasChildren = children != null && !children.isEmpty();
        if (hasChildren) {
            for (Object child : children) {
            	// 仅遍历 node 类型,因为 children 可存在 String 等,调用递归就不合适了
            	// 比如存在 <name>lf</name>,其中值 lf 也是作为 children 的一个元素,
            	// 目前不对他进行递归(如果需要回调给外部,也可以在 XmlNodeCallback 新增一个接口,通过 callback 回调数据) 
                if (child instanceof Node) {
                    traverseNode((Node) child, callback);
                } else {
                    PluginLog.d("traverseNode: " + child.getClass() + "  val:" + child);
                }
            }
        }
    }
}

使用接口,回调每一个递归遍历到的 node,在回调中处理逻辑

public interface XmlNodeCallback {
    void onNode(Node node);
}

直接使用

  File xmlFile = new File(****)
  def rootNode = PluginXmlUtil.parseXml(xmlFile, new XmlNodeCallback() {
     @Override
     void onNode(Node node) {
         if (node == null) {
             return
         }

         String nodeName = node.name()
         String[] nodeAttr = node.attributes()
         if (CommUtils.isEmptyOrNoExists(nodeName)) {
             return
         }
         PluginLog.d("nodeName:" + nodeName + "  nodeAttr:  " + nodeAttr + " value: " + node.value)
		
		// TODO: 2024/1/10  处理你的逻辑

     }
 })

  // 比如,我要在跟节点下面添加一个标签
 rootNode.append(ArgUtil.genDefaultBaseConfigNode())
 //然后保存修改
 def saveSuccess = PluginXmlUtil.saveNodeToFile(rootNode, xmlFile)

默认配置

package ***.utils;

import org.xml.sax.SAXException;

import java.io.IOException;

import javax.xml.parsers.ParserConfigurationException;

import groovy.util.Node;
import groovy.util.XmlParser;


public class ArgUtil {
    public static Node genDefaultBaseConfigNode() throws ParserConfigurationException, SAXException, IOException {
        return new XmlParser().parseText("<base-config cleartextTrafficPermitted=\"true\">\n" +
                "        <trust-anchors>\n" +
                "            <certificates src=\"user\" />\n" +
                "            <certificates src=\"system\" />\n" +
                "        </trust-anchors>\n" +
                "    </base-config>");
    }

    public static Node genDefaultTrustAnchorsNode() throws ParserConfigurationException, SAXException, IOException {
        return new XmlParser().parseText("<trust-anchors>\n" +
                "            <certificates src=\"user\" />\n" +
                "            <certificates src=\"system\" />\n" +
                "        </trust-anchors>");
    }

    public static Node genDefaultCertificatesNode(String value) throws ParserConfigurationException, SAXException, IOException {
        return new XmlParser().parseText("<certificates src=" + value + " />");
    }
}

学会了新增,删除、修改都不是问题吧~

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ERROR in Plugin “react“ was conflicted .... 天坑留念-turborepo、eslint plugin

前两天项目代码拉下来&#xff0c;装完依赖启动的时候直接报错&#xff1a; [eslint] Plugin "react" was conflicted between ".eslintrc.js eslint-config-custom eslint-config-alloy/react" and "BaseConfig D:\pan\erp\test\business-servic…

Java21 如何使用switch case

1. Java8 和 Java21 Java8 引入字符串和枚举 Java21 可以返回值, yield关键字, switch 表达式, 模式匹配, null值处理 2. 代码案例 1. Java8 public static void java8() {String day "tuesday";switch (day) {case "monday":System.out.println("w…

vue3+vite+ts+pinia新建项目(略详细版)

1、新建项目 npm create vite@latest 2、安装依赖 yarn add vue-router yarn add -D @types/node vite-plugin-pages sass sass-loader 3、配置别名 //vite.config.ts import { defineConfig } from vite import path from node:path export default defineConfig({ plu…

基于ssm快餐店点餐结算系统的设计与实现+vue论文

摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装快餐店点餐结算系统软件来发挥其高效地信息处理的作用&…

Python-基础语法

标识符 第一个字符必须是字母表中字母或下划线 _ 。标识符的其他的部分由字母、数字和下划线组成。标识符对大小写敏感。在 Python 3 中&#xff0c;可以用中文作为变量名&#xff0c;非 ASCII 标识符也是允许的了。 python保留字 保留字即关键字&#xff0c;我们不能把它们用…

php大型酒店管理系统源码(多酒店版)带安装手册

php大型酒店管理系统源码(多酒店版&#xff09;带安装手册 系统的运行环境要求PHP7.2以上 功能介绍&#xff1a; 房间动态、房间管理、优惠活动、预定信息、商品管理、营业查询、交班管理 会员营销、查看房价、数据统计、客房服务、物品租借、夜审设置、系统设置 酒店设置、计费…

代码随想录day25 回溯算法加强练习

216.组合总和III 题目 找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数&#xff0c;并且每种组合中不存在重复的数字。 说明&#xff1a; 所有数字都是正整数。解集不能包含重复的组合。 示例 1: 输入: k 3, n 7 输出: [[1,2,4]] 示例 2: 输入…

金融中介管理系统,助您高效管理金融中介业务!

金融中介管理系统是一种用于有效管理金融中介业务的软件系统。它提供了一系列工具和功能&#xff0c;帮助金融中介机构简化和优化其日常运营和管理流程。 金融中介管理系统通常具有以下特点和功能&#xff1a; 1. 客户管理 系统可以帮助机构记录和管理客户信息、需求和交互历…

PDF修改技巧之:如何简单方便的编辑PDF文件?

在当今精通技术的世界中&#xff0c;PDF 的使用已变得普遍&#xff0c;尤其是在商业和教育方面。如果您在审阅 PDF 文件时遇到语法或其他错误怎么办&#xff1f; 尽管 PDF 文件不像 Word 或在线文档那样容易编辑&#xff0c;但借助高级工具&#xff0c;您一定可以进行编辑。 …

CodeWave智能开发平台--03--目标:应用创建--09供应商详情页面下

摘要 本文是网易数帆CodeWave智能开发平台系列的第13篇&#xff0c;主要介绍了基于CodeWave平台文档的新手入门进行学习&#xff0c;实现一个完整的应用&#xff0c;本文主要完成09供应商详情页面下主营产品展示及权限管理 CodeWave智能开发平台的13次接触 CodeWave参考资源…

使用ffmpeg实现音频静音修剪

1 silenceremove介绍 本文主要介绍在 FFmpeg 命令中使用 silenceremove filter 进行音频静音的修剪。 1.1 start_x参数 参数名说明取值范围默认值start_periods设置是否应在音频开头修剪音频。0 表示不应从一开始就修剪静音。当指定一个非 0 值时&#xff0c;它会修剪音频直…

搜索与图论第二期 BFS

前言 BFS跟DFS同样重要&#xff0c;也一定要熟练的掌握&#xff01;&#xff01;&#xff01; 一、BFS的基本内容 BFS是从根节点开始&#xff0c;沿着树(图)的宽度遍历树(图)的节点。 如果所有节点均被访问&#xff0c;则算法中止。 BFS同样属于盲目搜索。 一般用队列数据结…

2. Presto应用

该笔记来源于网络&#xff0c;仅用于搜索学习&#xff0c;不保证所有内容正确。文章目录 1、Presto安装使用2、事件分析3、漏斗分析4、漏斗分析UDAF开发开发UDF插件开发UDAF插件 5、漏斗测试 1、Presto安装使用 参考官方文档&#xff1a;https://prestodb.io/docs/current/ P…

Hugging Face Datasets文本质量分析,识别低质量内容、垃圾数据、偏见内容、识别毒性内容、检测重复文档、识别测试集污染数据、识别过短的内容

Hugging Face Datasets文本质量分析,识别低质量内容、垃圾数据、偏见内容、识别毒性内容、检测重复文档、识别测试集污染数据、识别过短的内容。 在机器学习和自然语言处理的世界中,数据的质量至关重要。Hugging Face提供了大量的文本数据集,但是如何评估这些数据集的质量呢…

提升办公效率用微服务快速开发平台怎么样?

如果想实现高效率的办公&#xff0c;采用专业的微服务快速开发平台可以达到事半功倍的效果。什么是微服务快速开发平台&#xff1f;又有哪些优势和特点&#xff1f;可以用在哪些领域&#xff1f;流辰信息是专业的低代码技术平台服务商&#xff0c;具有丰富的研发经验&#xff0…

HTML--文本

文本一般存在于 body下 段落标签&#xff1a;<p> </p> 换行标签&#xff1a;<br/> 放在一句话里可以换行 <p>这是一段话<br/>这是另一段话</p>文本标签分以下几种&#xff1a; 粗体标签&#xff1a;strong&#xff0c;b 斜体标签&#xf…

React18-树形菜单-递归

文章目录 案例分析技巧通信展示效果实现代码技巧点技巧点 Refer to 案例分析 https://github.com/dL-hx/manager-fe/commit/85faf3b1ae9a925513583feb02b9a1c87fb462f7 从接口获取城市数据,渲染出一个树形菜单 要求: 可以展开和收起 技巧 学会递归渲染出一个树形菜单, 并点击后…

Windows开机后,Docker失败:Commoncauses include access rights issues

这种错误看似已经跟你说很清楚了&#xff0c;但是看国外docker社区也提到这个问题&#xff0c;一大堆回答解决了别人的问题&#xff0c;但未必解决你的。我写自己的方案&#xff0c;可能也未必适合你&#xff0c;如果要说Root Cause根源就是windows的虚拟化功能开启的问题。 An…

(vue)el-table表格最小/自动高度设置

(vue)el-table表格最小/自动高度设置 <el-table:data"tableData"size"mini"borderstyle"min-height:100px" //重点 ><el-table-column align"center" label"参数名称" prop"parametersName" />... &l…

web网页首页布局

效果展示&#xff1a; html代码&#xff1a; <!doctype html> <html> <head><meta charset"utf-8"><meta http-equiv"X-UA-Compatible" content"IEedge,chrome1"> <meta name"viewport" content&qu…