如何使用xmlstarlet将元素插入xml?

时间:2018-11-14 15:38:42

标签: xml shell xpath xmlstarlet

我想在XML输入的某些变体中插入其他元素。该脚本试图演示输入,并且尝试将代码插入现有XML。可以看出,修改a.xml可以得到预期的输出。但是在b.xmlc.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

1 个答案:

答案 0 :(得分:0)

问题在于您需要告诉您要更改的节点。

  1. 仅在b中不存在b时添加子项a

    -s "/a[not(b)]" -t elem -n "b"
    
  2. c中添加新的孩子a/b

    -s "/a/b[not(c)]" -t elem -n "c"
    
  3. 向最后添加的节点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()函数来表示我们只想选择不包含该特定项目的节点。

有用的链接: