使用 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 等,调用递归就不合适了// 比如存在 lf,其中值 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("\n" +"\n" +"\n" +"\n" +"\n" +"");}public static Node genDefaultTrustAnchorsNode() throws ParserConfigurationException, SAXException, IOException {return new XmlParser().parseText("\n" +"\n" +"\n" +"");}public static Node genDefaultCertificatesNode(String value) throws ParserConfigurationException, SAXException, IOException {return new XmlParser().parseText("<certificates src=" + value + " />");}}

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