如何使用 xmlstarlet 将元素插入 xml?
how to insert elements into xml with xmlstarlet?
我想在 XML 输入的一些变体中插入额外的元素。此脚本尝试演示输入,以及我尝试将代码插入现有的 XML。可以看出,修改 a.xml
给出了预期的输出。但在 b.xml
和 c.xml
中,结果是假的。在 b.xml
中,现有的 <c/>
被更改并创建了另一个 <b/>
的块。在c.xml
中,结果是d=""
被赋值了两次
应该只有一个<a><b>
,有几个<c>
。
知道如何实现吗?
#!/bin/bash
# insert <a><b><c d="2"/>
set -e
td=`mktemp --directory --tmpdir=/dev/shm XXX`
trap "rm -rf '${td}'" EXIT
xmlstarlet --version
pushd "${td}"
cat > a.xml <<_EOX_
<a>
</a>
_EOX_
cat > b.xml <<_EOX_
<a>
<b>
<c/>
</b>
</a>
_EOX_
cat > c.xml <<_EOX_
<a>
<b>
<c d="1"/>
</b>
</a>
_EOX_
for i in *.xml
do
echo "$i"
cat "$i" | \
xmlstarlet ed -O \
-s 'a' -t elem -n b \
-s 'a/b' -t elem -n c \
-i 'a/b/c' -t attr -n d -v '2' |
xmlstarlet fo -o || echo "$?"
done
这会产生以下输出:
1.6.1
compiled against libxml2 2.9.7, linked with 20907
compiled against libxslt 1.1.32, linked with 10132
/dev/shm/tpX ~/work
a.xml
<a>
<b>
<c d="2"/>
</b>
</a>
37
b.xml
<a>
<b>
<c d="2"/>
<c d="2"/>
</b>
<b>
<c d="2"/>
</b>
</a>
80
c.xml
-:3.19: Attribute d redefined
<c d="1" d="2"/>
^
2
问题是您需要告诉您要更改哪个节点。
仅当 b
在 a
中不存在时添加 child b
:
-s "/a[not(b)]" -t elem -n "b"
在a/b
中添加一个新的childc
:
-s "/a/b[not(c)]" -t elem -n "c"
将属性d
添加到新添加的节点c
,它在最后一个地方:
-s "/a/b/c[last()]" -t attr -n "d" -v "2"
所以现在完整的命令是:
xmlstarlet ed -O \
-s "/a[not(b)]" -t elem -n "b" \
-s "/a/b" -t elem -n "c" \
-s "/a/b/c[last()]" -t attr -n "d" -v "2"
这里我们使用 not()
函数来表示我们只想 select 不包含该特定项目的节点。
有用的链接:
我想在 XML 输入的一些变体中插入额外的元素。此脚本尝试演示输入,以及我尝试将代码插入现有的 XML。可以看出,修改 a.xml
给出了预期的输出。但在 b.xml
和 c.xml
中,结果是假的。在 b.xml
中,现有的 <c/>
被更改并创建了另一个 <b/>
的块。在c.xml
中,结果是d=""
被赋值了两次
应该只有一个<a><b>
,有几个<c>
。
知道如何实现吗?
#!/bin/bash
# insert <a><b><c d="2"/>
set -e
td=`mktemp --directory --tmpdir=/dev/shm XXX`
trap "rm -rf '${td}'" EXIT
xmlstarlet --version
pushd "${td}"
cat > a.xml <<_EOX_
<a>
</a>
_EOX_
cat > b.xml <<_EOX_
<a>
<b>
<c/>
</b>
</a>
_EOX_
cat > c.xml <<_EOX_
<a>
<b>
<c d="1"/>
</b>
</a>
_EOX_
for i in *.xml
do
echo "$i"
cat "$i" | \
xmlstarlet ed -O \
-s 'a' -t elem -n b \
-s 'a/b' -t elem -n c \
-i 'a/b/c' -t attr -n d -v '2' |
xmlstarlet fo -o || echo "$?"
done
这会产生以下输出:
1.6.1
compiled against libxml2 2.9.7, linked with 20907
compiled against libxslt 1.1.32, linked with 10132
/dev/shm/tpX ~/work
a.xml
<a>
<b>
<c d="2"/>
</b>
</a>
37
b.xml
<a>
<b>
<c d="2"/>
<c d="2"/>
</b>
<b>
<c d="2"/>
</b>
</a>
80
c.xml
-:3.19: Attribute d redefined
<c d="1" d="2"/>
^
2
问题是您需要告诉您要更改哪个节点。
仅当
b
在a
中不存在时添加 childb
:-s "/a[not(b)]" -t elem -n "b"
在
a/b
中添加一个新的childc
:-s "/a/b[not(c)]" -t elem -n "c"
将属性
d
添加到新添加的节点c
,它在最后一个地方:-s "/a/b/c[last()]" -t attr -n "d" -v "2"
所以现在完整的命令是:
xmlstarlet ed -O \
-s "/a[not(b)]" -t elem -n "b" \
-s "/a/b" -t elem -n "c" \
-s "/a/b/c[last()]" -t attr -n "d" -v "2"
这里我们使用 not()
函数来表示我们只想 select 不包含该特定项目的节点。
有用的链接: