在 Bash 中从特定/通用 XML 文件生成树输出

Rus*_*sso 7 command-line xml text-processing

我正在尝试从 Bash 中的 XML 文件生成一棵树。

这是 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>
Run Code Online (Sandbox Code Playgroud)

我尝试过使用 CAT、GREP 和 AWK:

cat menu.xml | grep menu\ name | awk -v FS="(display=\"|\" help)" '{print $2}' > menulist.txt
Run Code Online (Sandbox Code Playgroud)

我首先使用具有“菜单名称”的行进行 GREPed,然后打印“display =”和“help”之间的测试并输出以下输出:

Main Menu">
Broadband
Load and Save Profiles
xDSL Interface
Run Code Online (Sandbox Code Playgroud)

但我想要的是 Grep 所有具有“菜单名称”、“参数类型”、“应用程序名称”和“值 id”的行,并在树状输出中打印它们的显示名称。我不确定如何从多行中 Grep 多个值并从中打印特定字符串。

然后我发现使用 XML 解析器工具来完成此操作相对容易一些。所以我尝试过 XMLStarlet:

xmlstarlet el menu.xml | awk -F'/' 'BEGIN{print "digraph{"}{print $(NF-1)" -> "$NF}END{print"}"}' > menumenutxt.txt
Run Code Online (Sandbox Code Playgroud)

使用此命令我发现以下输出:

menu -> menu
menu -> onenter
menu -> menu
menu -> application
menu -> application
menu -> application
menu -> parameter
parameter -> value
parameter -> value
Run Code Online (Sandbox Code Playgroud)

这绝对看起来更好,更接近我想要的。但它不打印显示名称。

我想要打印的是这样的:

 Main Menu -> 
           -> Broadband 
                        -> Load and Save Profiles
                                                  -> Load Profile
                                                  -> Save Profile
                                                  -> Delete Profile
Run Code Online (Sandbox Code Playgroud)

或者以下内容:

Main Menu 
-> Broadband 
--> Load and Save Profiles
---> Load Profile
---> Save Profile
---> Delete Profile
Run Code Online (Sandbox Code Playgroud)

我的目标是获得尽可能接近的输出。谁能建议我应该如何进行此操作?

mur*_*uru 5

改编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
Run Code Online (Sandbox Code Playgroud)

例子是:

使用 xml sel 打印 XML 元素的结构(高级 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
Run Code Online (Sandbox Code Playgroud)

结果输出:

a1
a1.a11
a1.a11.a111
a1.a11.a111.a1111
a1.a11.a112
a1.a11.a112.a1121
a1.a12
a1.a13
a1.a13.a131
Run Code Online (Sandbox Code Playgroud)

从这里开始,我们需要修改的内容是:

  • 打印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
Run Code Online (Sandbox Code Playgroud)

经过一番思考,下面的内容就更简单了:

xmlstarlet sel -T -t -m '//*' \
    -i '@display' \
        -m 'ancestor::*' \
            -o $'\t' -b \
        -o '-> ' -v '@display' -n foo.xml
Run Code Online (Sandbox Code Playgroud)

使用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
Run Code Online (Sandbox Code Playgroud)