Я пытаюсь сгенерировать дерево из файла XML в Bash.
Это часть файла XML:
<ke3600-menu-file language="en" display="English" index="1">
<version major="0" minor="1" patch="0"/>
<locale name="en_EN" timezone="CET-1CEST,M3.5.0,M10.5.0/3"/>
<menu name="main_menu" display="Main Menu">
<menu name="broadband" display="Broadband" help="100_help_broadband">
<onenter proc="activateGfast"/>
<menu name="load_save_profiles" display="Load and Save Profiles" help="601_help_profiles">
<application name="load_profiles" display="Load Profile"/>
<application name="save_profiles" display="Save Profile"/>
<application name="remove_profiles" display="Delete Profile"/>
</menu>
<parameter type="list" name="wanInterface" display="Interface" help="101_help_wanInterface">
<value id="0" name="ifDSL" display="xDSL"/>
<value id="1" name="ifSFP" display="SFP"/>
<value id="2" name="ifETH" display="Ethernet"/>
<!-- <value i d="3" name="ifWLAN" display="WLAN"/> -->
<value id="4" name="ifSHDSL" display="SHDSL"/>
</parameter>
<menu name="xdslinterface" display="xDSL Interface" help="200_help_xDslInterface">
<parameter type="list" name="annex" display="xDSL Mode" help="201_help_xdslModi">
<value id="0" name="xdsl_line_annex_a" display="Annex A/M"/>
<value id="1" name="xdsl_line_annex_b" display="Annex B/J"/>
</parameter>
<application name="xdsl_macAddr" display="MAC Address" caption="MAC Address">
<param type="string" name="xdsl_mac_addr" display="MAC Address" length="25"/>
</application>
<parameter type="list" name="xdsl_vectoring_mode" display="Vectoring Mode" help="202_help_Vectoring">
<value id="0" name="xdsl_vectoring_mode_disabled" display="Disabled"/>
<value id="1" name="xdsl_vectoring_mode_enabled" display="Enabled"/>
<value id="2" name="xdsl_vectoring_mode_friendly" display="Friendly"/>
</parameter>
<parameter type="list" name="xdsl_gfast_mode" display="G.FAST">
<value id="0" name="xdsl_gfast_mode_disabled" display="Disabled"/>
<value id="1" name="xdsl_gfast_mode_enabled" display="Enabled"/>
</parameter>
<parameter type="list" name="resync" display="Auto Re-Sync">
<value id="1" name="re_sync_on" display="On"/>
<value id="0" name="re_sync_off" display="Off"/>
</parameter>
<parameter type="list" name="seamlessRateAdaption" display="Seamless Rate Adaption">
<value id="0" name="sra_off" display="Off"/>
<value id="1" name="sra_on" display="On"/>
</parameter>
<parameter type="list" name="xdsl_ginp" display="G.INP">
<value id="0" name="xdsl_ginp_none" display="Off"/>
<value id="1" name="xdsl_ginp_down" display="Down"/>
<value id="2" name="xdsl_ginp_up" display="Up"/>
<value id="3" name="xdsl_ginp_both" display="Down/Up"/>
</parameter>
<parameter type="list" name="power_cut_back" display="Power Cut Back">
<value id="0" name="power_cut_back_off" display="Off"/>
<value id="1" name="power_cut_back_on" display="On"/>
</parameter>
<parameter type="list" name="atmType" display="ATM Type">
<value id="0" name="atm_type_aal5" display="AAL5"/>
<value id="1" name="atm_type_aal0pkt" display="AAL0PKT"/>
<value id="2" name="atm_type_aal0cell" display="AAL0CELL"/>
</parameter>
<parameter type="list" name="voip_atmType" display="Voip Interface ATM Type">
<value id="0" name="voip_atm_type_aal5" display="AAL5"/>
<value id="1" name="voip_atm_type_aal0pkt" display="AAL0PKT"/>
<value id="2" name="voip_atm_type_aal0cell" display="AAL0CELL"/>
</parameter>
<parameter type="list" name="iptv_atmType" display="Iptv Interface ATM Type">
<value id="0" name="iptv_atm_type_aal5" display="AAL5"/>
<value id="1" name="iptv_atm_type_aal0pkt" display="AAL0PKT"/>
<value id="2" name="iptv_atm_type_aal0cell" display="AAL0CELL"/>
</parameter>
</menu>
<menu name="ethernetinterface" display="Ethernet Interface" help="300_help_ethernetInterface">
<parameter type="list" name="ethInterfaceAuto" display="Autonegotiation">
<value id="1" name="ethInterfaceAutoOn" display="On"/>
<value id="0" name="ethInterfaceAutoOff" display="Off"/>
</parameter>
<parameter type="list" name="ethInterfaceSpeed" display="Speed">
<value id="2" name="ethIf1000" display="1000MBit/s"/>
<value id="1" name="ethIf100" display="100MBit/s"/>
<value id="0" name="ethIf10" display="10MBit/s"/>
</parameter>
<parameter type="list" name="ethInterfaceDuplexMode" display="Duplex Mode">
<value id="1" name="ethIfFull" display="Full"/>
<value id="0" name="ethIfHalf" display="Half"/>
</parameter>
</menu>
Я попытался использовать CAT и GREP и AWK:
cat /home/mr/Desktop/git/KE3600_APP/menu.xml | grep menu\ name | awk -v FS="(display=\"|\" help)" '{print $2}' > menulist.txt
Я сначала GREPed, используя строки, которые имеют «Имя меню», а затем распечатал тесты между «display =» и «help» и вышел с этим выходом:
Main Menu">
Broadband
Load and Save Profiles
xDSL Interface
Но я хочу, чтобы Grep все строки, которые имеют «Имя меню», «Тип параметра», «Имя приложения» и «Идентификатор значения» и печатают их отображаемое имя в дереве вывод. Я не уверен, как я могу Grep несколько значений из нескольких строк и печатать определенную строку из него.
Затем я увидел, что это сравнительно просто сделать с помощью инструмента анализа XML. Поэтому я попытался с XMLStarlet:
xmlstarlet el /home/mr/Desktop/git/KE3600_APP/menu.xml|awk -F'/' 'BEGIN{print "digraph{"}{print $(NF-1)" -> "$NF}END{print"}"}'> menumenutxt.txt
Используя эту команду, я нашел следующий вывод:
ke3600-menu-file -> ke3600-menu-file
ke3600-menu-file -> version
ke3600-menu-file -> locale
ke3600-menu-file -> menu
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
-> Interface
-> Ethernet Interface
-> Terminal Mode
-> Telephony
-> Interface
-> On
-> Off
-> Copper Test
Или следующее:
Main Menu
-> Broadband
--> Load and Save Profiles
---> Load Profile
---> Save Profile
---> Delete Profile
--> Interface
--> Ethernet Interface
--> Terminal Mode
-> Telephony
--> Interface
---> On
---> Off
-> Copper Test
Моя цель - сделать выход максимально приближенным к нему. Может ли кто-нибудь предложить мне, как я должен продолжить это?
Адаптация одного из примеров из документов 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' в bash вы получите символ табуляции. напечатайте только для элементов, которые имеют атрибут display, поэтому -i '@display'Я сделал отступ указанной выше команды, чтобы сделать поток более четким.
Выход, который я получаю: [!d13 ]
$ 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
Адаптация одного из примеров из документов 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' в bash вы получите символ табуляции. напечатайте только для элементов, которые имеют атрибут 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
Адаптация одного из примеров из документов 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' в bash вы получите символ табуляции. напечатайте только для элементов, которые имеют атрибут 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 "-" (Если не установлено, установите xidel)
xidel ex.xml \
-e '//@display/concat(substring("------",1,count(ancestor::*)),">",.)'
substring("------",1,n) является грязным способом построения строки с n "-" (Если не установлено, установите xidel)
xidel ex.xml \
-e '//@display/concat(substring("------",1,count(ancestor::*)),">",.)'
substring("------",1,n) является грязным способом построения строки с n "-"