关于Shell:如何使用xmlstarlet将元素插入xml?

how to insert elements into xml with xmlstarlet?

我想在XML输入的某些变体中插入其他元素。该脚本试图演示输入,并且尝试将代码插入现有XML。可以看出,修改a.xml给出了预期的输出。但是在b.xmlc.xml中,结果是伪造的。在b.xml中,更改现有的<c/>,并创建另一个<b/>块。在c.xml中,结果是d=""被分配了两次。

应该只有一个,有几个<c>

有什么想法要实现吗?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#!/bin/bash
# insert <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_


_EOX_
cat > b.xml <<_EOX_


 <c/>
 

_EOX_
cat > c.xml <<_EOX_


 <c d="1"/>
 

_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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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

 
    <c d="2"/>
 

37
b.xml

 
    <c d="2"/>
    <c d="2"/>
 
 
    <c d="2"/>
 

80
c.xml
-:3.19: Attribute d redefined
    <c d="1" d="2"/>
                  ^
2


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

  • 仅当a中不存在b时添加子b

    1
    -s"/a[not(b)]" -t elem -n"b"
  • a/b中添加新的子级c

    1
    -s"/a/b[not(c)]" -t elem -n"c"
  • 将属性d添加到位于最后位置的新添加的节点c中:

    1
    -s"/a/b/c[last()]" -t attr -n"d" -v"2"
  • 因此完整的命令现在显示为:

    1
    2
    3
    4
    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()函数来表示我们只想选择不包含该特定项目的节点。

    有用的链接:

    • 一个非常方便的XPath教程
    • XPath 1.0规范