Using SED with variable to replace strings in while loop

Hi guys,

Hi have this input (Menu.xml)

<?xml version="1.0" encoding="ISO-8859-1"?> 
<breakfast_menu> 
    <food> 
        <name>Berry-Berry Belgian Waffles</name> 
        <price>$8.95</price> 
        <calories>900</calories> 
    </food> 
    <food> 
        <name>French Toast</name> 
        <price>$4.50</price> 
        <calories>600</calories> 
    </food> 
</breakfast_menu>

and the required output is as below (basically replace text between <>, the text in red remains equal)

    <Catg> 
        <Unit><Data :Value="String">Berry-Berry Belgian Waffles</Data></Unit> 
        <Unit><Data :Value="String">$8.95</Data></Unit> 
        <Unit><Data :Value="String">900</Data></Unit> 
    </Catg> 
    <Catg> 
        <Unit><Data :Value="String">French Toast</Data></Unit> 
        <Unit><Data :Value="String">$4.50</Data></Unit> 
        <Unit><Data :Value="String">600</Data></Unit> 
    </Catg>

I'm trying with the code below to replace the values between "<>" to right, but is not working I'm not sure why.

Myfile=Menu.xml

awk -F "[<>]" '{print $2}' ${Myfile} | while read data
do
  cat <<-TEXT1
     if ["${data}" -eq "food"]; then
         sed "s/${data}/Catg/" ${Myfile}
     else
         sed "s/${data}/Unit><Data :Value="String"/" ${Myfile}
     fi
  TEXT1
done

May somebody help me please.

Thanks in advance.

Try this

sed '/^<.*>[ ]*$/{d}; s/food/Catg/g; 
s/<[^<].*>\(.*\)<\/.*>/<Unit><Data :Value="String">\1<\/Data><\/Unit>/g ' input_file

--ahamed

Using awk:

awk -F'[<>]' '
  $2 == "food" { sub("<.*", "<Catg>"); print }
  $2 == "/food" { sub("<.*", "</Catg>"); print }
  $2 == "name" || $2 == "price" || $2 == "calories" { sub("<.*", "<unit><Data :Value=\"String\">" $3 "</Unit></Cell>") ; print }
' Menu.xml

--Edit--

Few reasons why your method dosn't work:

  1. sed dosn't change file in place unless you use the -i option
  2. it's never a good idea to read and write to the same file at one (ie sed changes file awk is still reading)
  3. The double quotes in your 2nd sed command need to be quoted to protect from the shell. Good general rule of thumb is to use single quotes for sed/awk code

Hi ahamed,

Works great!!

But, how can I add a text line after each <Catg>?

I have the code below, but how to include it in your code?

Var="Today Breakfast"
sed '/<Catg>/a\<Unit><Data :Value="String">${Var}</Data></Unit>' Menu.xml

To get this:

    <Catg>
        <Unit><Data :Value="String">Today Breakfast</Data></Unit> 
        <Unit><Data :Value="String">Berry-Berry Belgian Waffles</Data></Unit> 
        <Unit><Data :Value="String">$8.95</Unit></Cell> 
        <Unit><Data :Value="String">900</Unit></Cell> 
    </Catg> 
    <Catg>
        <Unit><Data :Value="String">Today Breakfast</Data></Unit> 
        <Unit><Data :Value="String">French Toast</Unit></Cell> 
        <Unit><Data :Value="String">$4.50</Unit></Cell> 
        <Unit><Data :Value="String">600</Unit></Cell> 
    </Catg>

Thanks for your help.

Var="Today Breakfast"
sed "/<Catg>/a\<Unit><Data :Value=\"String\">${Var}</Data></Unit>" input_file

--ahamed

---------- Post updated at 09:14 PM ---------- Previous update was at 09:12 PM ----------

sed '...' input_file | sed "..."

--ahamed

---------- Post updated at 09:16 PM ---------- Previous update was at 09:14 PM ----------

sed '/^<.*>[ ]*$/{d};s/food/Catg/g;s/<[^<].*>\(.*\)<\/.*>/<Unit><Data :Value="String">\1<\/Data><\/Unit>/g ' input_file 
| sed "/<Catg>/a\<Unit><Data :Value=\"String\">${Var}</Data></Unit>"

--ahamed

awk -v N="Today Breakfast" -F'[<>]' '
    $2 == "food" { sub("<.*", "<Catg>"); print ; $0="    <"N"<"N }
    $2 == "/food" { sub("<.*", "</Catg>"); print }
    $2==N || $2=="name" || $2=="price" || $2=="calories" { sub("<.*", "<unit><Data :Value=\"String\">" $3 "</Unit></Cell>") ; print } ' Menu.xml

Thanks ahmed works great, only I'm figure it out how to print only the "<food>" blocks removing the others lines that could be
present ("<? xml...", "<breakfast_menu", "</breakfast_menu" etc).

Hi Chubler_XL for both options, both work great, but if the xml file contains more lines between <food's> blocks the code will not
consider them and if the lines between <food> and </food> are different to "name", "price" and "calories" etc, will not be consider either.
It could be more lines than those 3, and could be different from file to file than in the sample.

For example:

<?xml version="1.0" encoding="ISO-8859-1"?> 
<breakfast_menu> 
    <food> 
        <name>Berry-Berry Belgian Waffles</name> 
        <price>$8.95</price> 
        <calories>900</calories> 
        <description>Description text..</description>
    </food> 
    <food> 
        <name>French Toast</name> 
        <price>$4.50</price> 
        <calories>600</calories> 
        <description>Description text..</description> 
    </food> 
</breakfast_menu>

Thanks for help so far.

Regards.