Home > Net >  Edit value under specific tag using awk
Edit value under specific tag using awk

Time:09-26

I'm trying to understand AWK command. The problem that I'm trying to solve is as follow: I have XML file with structure:

<root>
...
<elem_name name='type1'>
...
<prop name='a' type="xxx" value="000"/>
<prop name='b' type="xxx" value="000"/>
<prop name='c' type="xxx" value="000"/>
...
</elem_name>
<elem_name name='type2'>
....
<prop name='a' type="xxx" value="000"/>
<prop name='b' type="xxx" value="000"/>
<prop name='c' type="xxx" value="000"/>
...
</elem_name>
...
</root>

And I have to edit value of prop 'b' under 'type1' root. As I mentioned I would like to do it with awk or sed. I'm aware of better tools to do it.

For now, I created following command, but it is not working properly.

gawk '/elem_name name="type1"/ {for(i=1; i<=4; i  ) {getline;found=index($0,"a");if(found != 0){sub("value=", "test", $0)}; print > "test.xml"}} {print > "test.xml"    }' original_file.xml

Firstly, I the value is not changed after script execution, the 'name="type1" is removed from output file.

CodePudding user response:

I have to edit value of prop 'b' under 'type1' root

Since I assume you have python in the OS you are running I share the below solution.

import xml.etree.ElementTree as ET

FILE_NAME = 'myxml.xml'

root = ET.parse(FILE_NAME)
ele = root.find(".//elem_name[@name='type1']")
b = ele.find(".//prop[@name='b']")
b.attrib['value'] = 'new_value_goes_here'
root.write(FILE_NAME)

CodePudding user response:

Update attribute with xmlstarlet:

xmlstarlet edit --omit-decl \
  --update '//root/elem_name[@name="type1"]/prop[@name="b"]/@value' \
  --value "test" file.xml

Output with removed ...:

<root>
  <elem_name name="type1">
    <prop name="a" type="xxx" value="000"/>
    <prop name="b" type="xxx" value="test"/>
    <prop name="c" type="xxx" value="000"/>
  </elem_name>
  <elem_name name="type2">
    <prop name="a" type="xxx" value="000"/>
    <prop name="b" type="xxx" value="000"/>
    <prop name="c" type="xxx" value="000"/>
  </elem_name>
</root>

See: xmlstarlet edit

CodePudding user response:

It can be done with xmllint in one-liner taking advantage of its --shell option as

 (echo 'cd //elem_name[@name="type1"]/prop[@name="b"]/@value' ; echo "set some other xxxxx value"; echo "save test-e.xml" ; echo "bye") | xmllint --shell test.xml

The commands to xmllint are intuitive, "shell" alike

Change directory to the desired node expressed as an XPath expression:
cd //elem_name[@name="type1"]/prop[@name="b"]/@value

Set element value (no quotes):
set some other xxxxx value

Save xml doc to a new file:
save test-e.xml

Result:

<?xml version="1.0"?>
<root>
  <elem_name name="type1">
    <prop name="a" type="xxx" value="000"/>
    <prop name="b" type="xxx" value="some other xxxxx value"/>
    <prop name="c" type="xxx" value="000"/>
  </elem_name>
  <elem_name name="type2">
    <prop name="a" type="xxx" value="000"/>
    <prop name="b" type="xxx" value="000"/>
    <prop name="c" type="xxx" value="000"/>
  </elem_name>
</root>

The whole node content could be changed also

xmllint --shell test.xml 

Commands at prompt

/ > cd //elem_name[@name="type1"]
elem_name > set <new>cdvfbg</new>
elem_name > cat
<elem_name name="type1">
  <new>cdvfbg</new>
</elem_name>
elem_name > save test-e.xml

To get an interactive prompt and play around any xml/html file do:

xmllint --shell test.xml

Same commands above could be executed there. Try help to get a list of possible commands.

CodePudding user response:

You can give this sed a try

sed -E "/type1/,/\/elem_name/ s/(.*name='b'.*value=.).[^\"]*(.*)/\1New-value\2/" input_file

/type1/,/\/elem_name/ - Match between text block matching type1 and /elem_name

(.*name='b'.*value=.).[^\"]*(.*)/\1New-value\2/ - Substitute within the matched block the grouped () match

\1...\2 - Return the grouped match

Output

$ sed -E "/type1/,/\/elem_name/ s/(.*name='b'.*value=.).[^\"]*(.*)/\1New-value\2/" input_file
<root>
...
<elem_name name='type1'>
...
<prop name='a' type="xxx" value="000"/>
<prop name='b' type="xxx" value="New-value"/>
<prop name='c' type="xxx" value="000"/>
...
</elem_name>
<elem_name name='type2'>
....
<prop name='a' type="xxx" value="000"/>
<prop name='b' type="xxx" value="000"/>
<prop name='c' type="xxx" value="000"/>
...
</elem_name>
...
</root>
  • Related