wef
wef

Reputation: 361

xmlstarlet to add exactly one element to a file

I have hundreds of xml files to process - some have a particular desired tag, some don't. If I just add the tag to all files then some files get 2 tags (no surprises there!). How do I do it in xmlstarlet without a clumsy grep to select the files to work on? eg:

I have this in some files: ...

<parent_tag>
    <another_tag/> <-- but not in all files
</parent_tag>

I want this (but some files already have it): ...

<parent_tag>
    <good_tag>foobar</good_tag>
    <another_tag/>
</parent_tag>

eg this works but I wish I could do it entirely in xmlstarlet without the grep:

grep -L good_tag */config.xml | while read i; do 
    xmlstarlet ed -P -S -s //parent_tag -t elem -n good_tag -v ""  $i > tmp || break
    \cp tmp $i
done

I got myself tangled up in some XPATH exoticism like:

xmlstarlet sel --text --template --match //parent_tag --match "//parent_tag/node()[not(self::good_tag)]" -f --nl */config.xml

... but it's not doing what I had hoped ...

Upvotes: 0

Views: 483

Answers (1)

Jens Erat
Jens Erat

Reputation: 38672

Just select only <parent_tag/> elements which do not contain a <good_tag/> for inserting:

xmlstarlet ed -P -S -s '//parent_tag[not(good_tag)]' -t elem -n good_tag -v ""

If you also want to test for the right contents of the tag:

xmlstarlet ed -P -S -s '//parent_tag[not(good_tag[.="foobar"])]' -t elem -n good_tag -v ""

Upvotes: 1

Related Questions