Как вставить элементы в XML с помощью xmlstarlet? - PullRequest
0 голосов
/ 14 ноября 2018

Я хочу вставить дополнительные элементы в некоторые варианты ввода 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

1 Ответ

0 голосов
/ 14 ноября 2018

Проблема в том, что вам нужно указать, какой узел вы хотите изменить.

  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()функция, указывающая, что мы просто хотим выбрать узлы, которые не содержат этот конкретный элемент.

Полезные ссылки:

...