Скрипт оболочки для извлечения значения тега

Скрипт оболочки для извлечения значения тега

Предположим, у меня есть один XML-файл, как указано ниже, и я хочу извлечь из него имя приложения, компьютер и значение тега состояния с помощью команд Unix и представить его в формате, разделенном запятыми.

XML-файл:-

 <?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>

Выход:-

Adapter/Code1,123,Running

Adapter/Code1,456,Running

Adapter/Code2,123,Running

Adapter/Code2,456,Running

Можете ли вы помочь мне, предоставив скрипт unixcommand/shell для выполнения этой задачи?

Заранее спасибо!!!

решение1

Питон3.x решение (сxml.etree.ElementTreeмодуль):

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))

Выход:

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(используется для группировки дочерних узлов для каждого applicationэлемента) решение:

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 }}'

Выход:

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

  • "//application/@name| .//machine/text()| .//status/text()"- Выражение XPath для получения необходимых узлов

  • /Adapter/{app=$0; r=app; c=0; next}- захват каждого applicationимени для дальнейшей конкатенации

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

решение2

Установитьксидельи используйте xpath.

По моему мнению, лучшая точка зрения такова 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

решение3

xmlstarletДля обхода каждого узла используется serviceInstance:

xmlstarlet sel -t \
    -m '//application/service/serviceInstance' \
    -v '../../@name' -o , \
    -v 'machine' -o , \
    -v 'status' -nl \
    file.xml

Это сопоставляет serviceInstanceузлы, и для каждого такого узла он извлекает nameатрибут его прародительского узла, machineзначение узла и statusзначение узла. Они выводятся с запятыми между ними ( -o ,) и новой строкой в ​​конце ( -nl).

Вы также можете получить цитируемый CSV-вывод из xq(изhttps://kislyuk.github.io/yq/):

xq -r '
    .applications.application[] | ."@name" as $name |
    .service.serviceInstance[]  | [ $name, .machine, .status ] | @csv' file.xml

решение4

Если у вас есть веские причины не использовать инструменты XML, вы можете использовать низкоуровневый синтаксический анализ, при условии, что ваше приложение останется таким же тривиальным, как ваш пример:

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

Связанный контент