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>