我尝试创建一个shell脚本,在XML文件中搜索属性,如果不存在则创建具有给定属性的元素,或者如果属性存在则删除元素。
这是XML文件:
<configuration name="distributor.conf" description="Distributor Configuration">
<lists>
<list name="CRproductionLoadshare">
<node name="fs100" weight="2"/>
<node name="fs101" weight="2"/>
</list>
<list name="AnyOtherGroup">
<node name="fs100" weight="2"/>
</list>
</lists>
</configuration>
到目前为止,这是我的Shellscript:
fs_name=fs
cnt=102
xmlstarlet ed \
--var fs "'$fs_name$cnt'" \
-a '//list' -t elem -n node -v "$fs_name$cnt" \
-i '//node' -t attr -n name -v "$fs_name$cnt" \
-i '//node' -t attr -n weight -v 2 \
-d '//node[.=$fs]/text()' <distributor.conf.xml
预期的输出
<configuration name="distributor.conf" description="Distributor Configuration">
<lists>
<list name="CRproductionLoadshare">
<node name="fs100" weight="2"/>
<node name="fs101" weight="2"/>
<node name="fs102" weight="2"/>
</list>
<list name="AnyOtherGroup">
<node name="fs100" weight="2"/>
</list>
</lists>
</configuration>
但我的脚本是这样的:
<?xml version="1.0"?>
<configuration name="distributor.conf" description="Distributor Configuration">
<lists>
<list name="CRproductionLoadshare">
<node name="fs100" weight="2" name="fs102" weight="2"/>
<node name="fs101" weight="2" name="fs102" weight="2"/>
</list>
<list name="AnyOtherGroup">
<node name="fs100" weight="2" name="fs102" weight="2"/>
</list>
<node name="fs102" weight="2"/>
</lists>
</configuration>
如何更改shell脚本以达到目标。首先,我想添加节点名称=“fs102”,以防该节点不存在。
答案 0 :(得分:2)
在XML文件中搜索属性,如果没有,则创建它 存在
fs_name="fs"
cnt=102
node_exists=$(xmlstarlet sel -t --var fs="'${fs_name}$cnt'" -v 'boolean(//list[@name="CRproductionLoadshare"]/node[@name=$fs])' distributor.conf.xml)
[ "$node_exists" = "false" ] && xmlstarlet ed -O -s '//list[@name="CRproductionLoadshare"]' \
-t elem -n node -i '//list[@name="CRproductionLoadshare"]/node[last()]' \
-t attr -n name -v "${fs_name}$cnt" \
-i '//list[@name="CRproductionLoadshare"]/node[last()]' -t attr -n weight -v 2 distributor.conf.xml
输出:
<configuration name="distributor.conf" description="Distributor Configuration">
<lists>
<list name="CRproductionLoadshare">
<node name="fs100" weight="2"/>
<node name="fs101" weight="2"/>
<node name="fs102" weight="2"/>
</list>
<list name="AnyOtherGroup">
<node name="fs100" weight="2"/>
</list>
</lists>
</configuration>
体系:
node_exists
被赋予布尔值,表示所需节点存在[ "$node_exists" = "false" ] && xmlstarlet ed ...
- 仅当xmlstarlet
不等于node_exists
false
编辑命令
答案 1 :(得分:1)
这里最困难的任务是构建选择正确节点的XPath。
示例1:选择名为list
的节点,该节点具有属性@name="CRproductionLoadshare"
,并且具有名为node
的子节点,其属性为@name="fs100"
。< / p>
因此,您可以搜索名为node
的特定节点的父节点。
$ xmlstarlet sel -t \
-m '//node[@name="fs100"]/parent::list[@name="CRproductionLoadshare"]' \
-c . -n foo.xml
<list name="CRproductionLoadshare">
<node name="fs100" weight="2"/>
<node name="fs101" weight="2"/>
</list>
或者更容易:
$ xmlstarlet sel -t \
-m '//list[@name="CRproductionLoadshare" and node[@name="fs100"]]' \
-c . -n foo.xml
示例2 :选择名为list
的节点,其属性为@name="CRproductionLoadshare"
且不的子节点为node
属性@name="fs102"
。
这里我们可以使用XPath not
- 函数
$ xmlstarlet sel -t \
-m '//list[@name="CRproductionLoadshare" and not(node[@name="fs102"])]' \
-c . -n foo.xml
<list name="CRproductionLoadshare">
<node name="fs100" weight="2"/>
<node name="fs101" weight="2"/>
</list>
因此,既然您现在知道选择节点的正确XPath,您可以通过首先插入子节点-s
然后用-i
更新其值和属性来相应地编辑XML文件p>
$ xpath1='//list[@name="CRproductionLoadshare" and not(node[@name="fs102"])]'
$ xpath2='//list[@name="CRproductionLoadshare" and not(node[@name="fs102" and @weight="2"])]/node[last()]'
$ xmlstarlet ed -s ${xpath1} -t elem -n "node" -v "" \
-i ${xpath2} -t attr -n "name" -v "fs102" \
-i ${xpath2} -t attr -n "weight" -v "2" \
foo.xml
输出
<configuration name="distributor.conf" description="Distributor Configuration">
<lists>
<list name="CRproductionLoadshare">
<node name="fs100" weight="2"/>
<node name="fs101" weight="2"/>
<node name="fs102" weight="2"/>
</list>
<list name="AnyOtherGroup">
<node name="fs100" weight="2"/>
</list>
</lists>
</configuration>
切换可以通过添加假属性来完成,然后删除具有该属性的节点:
$ xpath0='//list[@name="CRproductionLoadshare"]/node[@name="fs102"]'
$ xpath1='//list[@name="CRproductionLoadshare" and not(node[@name="fs102" and @delete="1"])]'
$ xpath2='//list[@name="CRproductionLoadshare" and not(node[@name="fs102" and @delete="1"])]/node[last()]'
$ xpath3='//list[@name="CRproductionLoadshare"]/node[@name="fs102" and @delete="1"]'
$ xmlstarlet ed -i ${xpath0} -t attr -n "delete" -v "1" \
-s ${xpath1} -t elem -n "node" -v "" \
-i ${xpath2} -t attr -n "name" -v "fs102" \
-i ${xpath2} -t attr -n "weight" -v "2" \
-d ${xpath3} \
foo.xml
答案 2 :(得分:0)
用于切换节点的shell脚本如下所示:
template<typename T>
class A {};
class A {}; //compilation fails when uncommented
template<typename T>
void func(); //No problem compiling
void func();
int main() {
}
每次运行该脚本时,inputfile仅在名为CRproductionLoadshare的list元素中切换节点(添加/删除)。