John Al
John Al

Reputation: 159

How to find a string, delete corresponding node and append two nodes using xmlstarlet

I have a file called FILE.XML

It looks like this

      <File>${IB}/OP/views/ACCOUNT.xml</File>
      <File>${IB}/OP/views/EMPLOYEES.xml</File
      <File>${IB}/OP/views/STATUS.xml</File>

I need to use xmlstarlet to look at FILE.XML and determine if there's a match for ACCOUNT.xml. If there is, append two additional lines beneath it. Including the tags and the full path as seen below.

<File>${IB}/OP/views/ACCOUNT_MAIN.xml</File>
<File>${IB}/OP/views/ACCOUNT_SECONDARY.xml</File>

Then delete ACCOUNT.xml line

<File>${IB}/OP/views/ACCOUNT.xml</File>

So I came up with a way to delete the line but not sure how to append the new ones before or after I delete.

Here's my delete command.

xmlstarlet ed -L -d '//rules/File[contains(text(),"{IB}/OP/view/ACCOUNT.xml")]' ${HOME}/file.xml

The final result in FILE.xml should look like this

      <File>${IB}/OP/views/ACCOUNT_MAIN.xml</File>
      <File>${IB}/OP/views/ACCOUNT_SECONDARY.xml</File>
      <File>${IB}/OP/views/EMPLOYEES.xml</File
      <File>${IB}/OP/views/STATUS.xml</File>

Upvotes: 1

Views: 59

Answers (2)

Gilles Qu&#233;not
Gilles Qu&#233;not

Reputation: 185690

Input

<root>
  <File>${IB}/OP/views/ACCOUNT_MAIN.xml</File>
  <File>${IB}/OP/views/ACCOUNT_SECONDARY.xml</File>
  <File>${IB}/OP/views/EMPLOYEES.xml</File
  <File>${IB}/OP/views/STATUS.xml</File>
</root>

What I would do:

xmlstarlet ed -L \
  -a '//File[contains(., "ACCOUNT.xml")]' -t elem -n File \
  -v '${IB}/OP/views/ACCOUNT_SECONDARY.xml' \
  -a '//File[contains(., "ACCOUNT.xml")]' -t elem -n File \
  -v '${IB}/OP/views/ACCOUNT_MAIN.xml' \
  -d '//File[contains(., "ACCOUNT.xml")]' file.xml

Output

<?xml version="1.0"?>
<root>
  <File>${IB}/OP/views/ACCOUNT_MAIN.xml</File>
  <File>${IB}/OP/views/ACCOUNT_SECONDARY.xml</File>
  <File>${IB}/OP/views/EMPLOYEES.xml</File>
  <File>${IB}/OP/views/STATUS.xml</File>
</root>

Upvotes: 1

urznow
urznow

Reputation: 1811

Given this input,

<rules>
  <File>${IB}/OP/views/ACCOUNT.xml</File>
  <File>${IB}/OP/views/EMPLOYEES.xml</File>
  <File>${IB}/OP/views/STATUS.xml</File>
</rules>

this should do what you're after:

# shellcheck shell=sh disable=SC2016
xmlstarlet edit \
  --var T '//rules/File[contains(text(),"${IB}/OP/views/ACCOUNT.xml")]' \
  -a '$T' -t elem -n 'File' -v '${IB}/OP/views/ACCOUNT_SECONDARY.xml' \
  -a '$T' -t elem -n 'File' -v '${IB}/OP/views/ACCOUNT_MAIN.xml' \
  -d '$T' \
file.xml

--var defines a named variable, see examples in xmlstarlet.txt. If the T variable matches nothing then input is not modified.

Upvotes: 2

Related Questions