0

Suppose I have one xml file as mentioned below and I want to extract the application name, machine and status tag value using unix commands and present it in comma separated format.

XML file:-

 <?xml version="1.0" encoding="UTF-8"?>
<applications>
<application name="Adapter/Code1">
<service name="Code1.par">
<deploymentStatus>Success</deploymentStatus>
<serviceInstance name="Code1-One">
    <machine>123</machine>
    <status>Running</status>
</serviceInstance>
<serviceInstance name="Code1-Two">
    <machine>456</machine>
    <status>Running</status>
</serviceInstance>
</service>
</application>
<application name="Adapter/Code2">
<service name="Code2.par">
<deploymentStatus>Success</deploymentStatus>
<serviceInstance name="Code2-One">
    <machine>123</machine>
    <status>Running</status>
</serviceInstance>
<serviceInstance name="Code2-Two">
    <machine>456</machine>
    <status>Running</status>
</serviceInstance>
</service>
</application>
</applications>

Output:-

Adapter/Code1,123,Running

Adapter/Code1,456,Running

Adapter/Code2,123,Running

Adapter/Code2,456,Running

Can you please help me in giving unixcommand/shell script for doing this activity.?

Thanks in advance!!!

  • 6
    Do what every question tagged xml here suggests: use an XML parser. – jasonwryan May 24 '17 at 7:54
2

Python 3.x solution (with xml.etree.ElementTree module):

import xml.etree.ElementTree as ET

tree = ET.parse("test.xml")
root = tree.getroot()
for app in root.findall('application'):
    for m,s in zip(app.iter('machine'), app.iter('status')):
        print("%s,%s,%s" % (app.get('name'), m.text, s.text))

The output:

Adapter/Code1,123,Running
Adapter/Code1,456,Running
Adapter/Code2,123,Running
Adapter/Code2,456,Running

https://docs.python.org/3.6/library/xml.etree.elementtree.html?highlight=etree#module-xml.etree.ElementTree


xmlstarlet + awk (used to group child nodes for each application element) solution:

xmlstarlet sel -t -v "//application/@name| .//machine/text()| .//status/text()" -n input.xml 
 | awk '/Adapter/{app=$0; r=app; c=0; next}
   { if(++c==2){ c=0; print r","$0; r=app } else { r=r","$0 }}'

The output:

Adapter/Code1,123,Running
Adapter/Code1,456,Running
Adapter/Code2,123,Running
Adapter/Code2,456,Running

  • "//application/@name| .//machine/text()| .//status/text()" - XPath expression to get the needed nodes

  • /Adapter/{app=$0; r=app; c=0; next} - capturing each application name for further concatenation

http://xmlstar.sourceforge.net/doc/UG/xmlstarlet-ug.html

  • cool ! ( +1 ) ( python version also works in Python2 ?) – JJoao May 24 '17 at 18:16
  • 1
    @JJoao, as for Python 2 - it has print function call without parenthesis (i.e. print <arg>), but I hope Python 2.x will die someday ) – RomanPerekhrest May 24 '17 at 19:44
1

Install xidel and use xpath.

In my opinion the best point of view is from serviceInstance:

xidel f.xml -e '//serviceInstance/string-join((../../@name, machine, status),",")'
Adapter/Code1,123,Running
Adapter/Code1,456,Running
Adapter/Code2,123,Running
Adapter/Code2,456,Running
0

If you have good reason for not using xml tools, you can use low-level parsing, as long as your application stays trivial as your example:

sed 's/<application name="\([^"]*\)">/\1/
Ta
h
d
:a
/<machine>/!d
G
N
s_.*<machine>\(.*\)</machine>\n\(.*\)\n.*<status>\(.*\)</status>.*_\2,\1,\3_' yourfile.xml

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.