Я пытаюсь генерировать дерево от XML-файла в Bash.
Это - часть XML-файла:
<menu name="main_menu" display="Main Menu">
<application name="load_profiles" display="Load Profile"/>
<application name="save_profiles" display="Save Profile"/>
<application name="remove_profiles" display="Delete Profile"/>
</menu>
Я попытался использовать CAT и GREP и AWK:
cat menu.xml | grep menu\ name | awk -v FS="(display=\"|\" help)" '{print $2}' > menulist.txt
У меня есть первый GREPed использование строк, который имеет "Название меню" и затем распечатал Тесты между 'дисплеем ="' и '"справкой' и выпустил этот вывод:
Main Menu">
Broadband
Load and Save Profiles
xDSL Interface
Но то, что я хочу, является к Grep всеми строками, который имеет "Название меню", "типу параметра", "имя приложения" и "идентификатор значения" и печатают их отображаемое имя в дереве, нравится вывод. Я не уверен, как я могу Grep несколько значений от нескольких строк и печатать определенную строку от него.
Затем я видел, что сравнительно легче сделать это с инструментом синтаксического анализатора XML. Таким образом, я попробовал XMLStarlet:
xmlstarlet el menu.xml|awk -F'/' 'BEGIN{print "digraph{"}{print $(NF-1)" -> "$NF}END{print"}"}'> menumenutxt.txt
Используя эту команду я нашел следующий вывод:
menu -> menu
menu -> onenter
menu -> menu
menu -> application
menu -> application
menu -> application
menu -> parameter
parameter -> value
parameter -> value
Который определенно выглядит лучше и ближе к тому, что я хочу. Но это не печатает отображаемое имя.
То, что я пытаюсь распечатать, является чем-то вроде этого:
Main Menu ->
-> Broadband
-> Load and Save Profiles
-> Load Profile
-> Save Profile
-> Delete Profile
Или следующее:
Main Menu
-> Broadband
--> Load and Save Profiles
---> Load Profile
---> Save Profile
---> Delete Profile
Моя цель к получить вывод максимально близко к нему. Кто-либо может предложить меня, как я должен возобновить это?
Адаптация одного из примеров из xmlstarlet документов:
xmlstarlet sel -T -t -m '//*' \
-i '@display' \
-m 'ancestor-or-self::*' \
-i '(position()=last())' \
-o '-> ' -v '@display' -b \
-o $'\t' -b \
-n foo.xml
Пример:
Структура печати элемента XML с помощью xml sel (усовершенствованные выражения XPath и xml sel управляют использованием),
xml sel -T -t -m '//*' \ -m 'ancestor-or-self::*' -v 'name()' -i 'not(position()=last())' -o . -b -b -n \ xml/structure.xml
Вывод результата:
a1 a1.a11 a1.a11.a111 a1.a11.a111.a1111 a1.a11.a112 a1.a11.a112.a1121 a1.a12 a1.a13 a1.a13.a131
Отсюда, вещи, которые мы должны изменить:
display
атрибут вместо name
, так @display
вместо name()
.
для всех кроме последнего элемента, таким образом, легко инвертировать это.-o $'\t'
. $'\t'
в ударе получит Вас символ табуляции.display
атрибут, таким образом, -i '@display'
Я расположил команду с отступом выше для создания потока более ясным.
Вывод я добираюсь:
$ xmlstarlet sel -T -t -m '//*' -i '@display' -m 'ancestor-or-self::*' -i '(position()=last())' -o '-> ' -v '@display' -b -o $'\t' -b -n foo.xml
-> English
-> Main Menu
-> Broadband
-> Load and Save Profiles
-> Load Profile
-> Save Profile
-> Delete Profile
-> Interface
-> xDSL
-> SFP
-> Ethernet
-> SHDSL
-> xDSL Interface
-> xDSL Mode
-> Annex A/M
-> Annex B/J
-> MAC Address
-> MAC Address
-> Vectoring Mode
-> Disabled
-> Enabled
-> Friendly
-> G.FAST
-> Disabled
-> Enabled
После размышления немного, следующее более просто:
xmlstarlet sel -T -t -m '//*' \
-i '@display' \
-m 'ancestor::*' \
-o $'\t' -b \
-o '-> ' -v '@display' -n foo.xml
Используя ancestor::*
вместо ancestor-or-self::*
делает печать вкладок правильно легче, и устраняет дополнительный тест для последнего элемента.
Подобный вывод, но без запаздывающих вкладок:
-> English
-> Main Menu
-> Broadband
-> Load and Save Profiles
-> Load Profile
-> Save Profile
-> Delete Profile
-> Interface
-> xDSL
-> SFP
-> Ethernet
-> SHDSL
-> xDSL Interface
-> xDSL Mode
-> Annex A/M
-> Annex B/J
-> MAC Address
-> MAC Address
-> Vectoring Mode
-> Disabled
-> Enabled
-> Friendly
-> G.FAST
-> Disabled
-> Enabled
(Если не уже установленный, установите xidel)
xidel ex.xml \
-e '//@display/concat(substring("------",1,count(ancestor::*)),">",.)'
substring("------",1,n)
грязный способ создать строку с n "-"