如何使用xmlstarlet搜索XML节点并实现新增或删除操作
解决你的XML节点切换问题
看起来你的脚本现在遇到了几个关键问题,导致输出不符合预期:
- 它给所有现有
<node>元素都加上了重复的name和weight属性——这是因为-i '//node'会匹配XML里的每一个<node>,而不是只针对你新创建的节点。 - 新节点被添加到了
<lists>标签下(作为<list>的兄弟节点),而不是你想要的<list name="CRproductionLoadshare">内部——这是因为-a是添加兄弟元素,不是子元素。 - 完全没有实现“存在则删除,不存在则添加”的判断逻辑,只是无条件执行添加操作。
针对特定列表的修正脚本
假设你需要给**name="CRproductionLoadshare"这个特定列表**来切换节点(存在就删,不存在就加),可以用下面的脚本:
fs_name=fs cnt=102 target_list="CRproductionLoadshare" node_name="${fs_name}${cnt}" xmlstarlet ed \ --var target_list "'$target_list'" \ --var node_name "'$node_name'" \ # 先检查目标列表里有没有这个节点,有就删掉 --if "/configuration/lists/list[@name=\$target_list]/node[@name=\$node_name]" \ -d "/configuration/lists/list[@name=\$target_list]/node[@name=\$node_name]" \ # 没有的话,就在目标列表内部加新节点 --else \ # -s 是给指定节点添加子元素,而不是兄弟元素,这才是正确的位置 -s "/configuration/lists/list[@name=\$target_list]" -t elem -n node -v "" \ # 给刚添加的最后一个node设置name属性(用last()定位最新的节点) -i "/configuration/lists/list[@name=\$target_list]/node[last()]" -t attr -n name -v "$node_name" \ # 再设置weight属性 -i "/configuration/lists/list[@name=\$target_list]/node[last()]" -t attr -n weight -v "2" \ distributor.conf.xml
脚本为什么能工作?
- 精准定位:所有操作都限定在目标列表内部,不会影响其他列表或原有节点。
- 条件判断:用
--if和--else实现了“存在则删,不存在则加”的核心逻辑。 - 正确添加子元素:用
-s(subnode)代替-a(append sibling),把新节点放到<list>内部,而不是外面。
如果要给所有列表执行相同操作
如果你需要对XML里**所有<list>**都做这个切换逻辑,只需要调整一下XPath路径即可:
fs_name=fs cnt=102 node_name="${fs_name}${cnt}" xmlstarlet ed \ --var node_name "'$node_name'" \ # 先删掉所有列表里的目标节点(如果存在) -d "/configuration/lists/list/node[@name=\$node_name]" \ # 给每个列表都添加新节点 --var all_lists "/configuration/lists/list" \ -s "\$all_lists" -t elem -n node -v "" \ -i "\$all_lists/node[last()]" -t attr -n name -v "$node_name" \ -i "\$all_lists/node[last()]" -t attr -n weight -v "2" \ distributor.conf.xml
这个版本会先清理所有列表中已存在的目标节点,再给每个列表添加新节点,完美实现切换效果。
内容的提问来源于stack exchange,提问作者kockiren
相关产品推荐
相关产品推荐

