使用 Bash 脚本在 UNIX 中对 XML 文件进行排序?

pal*_*ing 2 xml awk sort

我正在尝试按字母顺序对看起来像这样的 XML 文件进行排序。这是一个更大的 bash 脚本的一部分,因此它需要在该脚本中工作:

<Module>
    <Settings>
        <Dimensions>
            <Volume>13000</Volume>
            <Width>5000</Width>
            <Length>2000</Length>
        </Dimensions>
        <Stats>
            <Mean>1.0</Mean>
            <Max>3000</Max>
            <Median>250</Median>
        </Stats>
    </Settings>
    <Debug>
        <Errors>
            <Strike>0</Strike>
            <Wag>1</Wag>
            <MagicMan>0</MagicMan>
        </Errors>
    </Debug>
</Module>
Run Code Online (Sandbox Code Playgroud)

我希望最终结果看起来像这样,我只希望对最里面的标签进行排序:

<Module>
    <Settings>
        <Dimensions>
            <Length>2000</Length>
            <Volume>13000</Volume>
            <Width>5000</Width>
        </Dimensions>
        <Stats>
            <Max>3000</Max>
            <Mean>1.0</Mean>
            <Median>250</Median>
        </Stats>
    </Settings>
    <Debug>
        <Errors>
            <MagicMan>0</MagicMan>
            <Strike>0</Strike>
            <Wag>1</Wag>
        </Errors>
    </Debug>
</Module>
Run Code Online (Sandbox Code Playgroud)

我正在尝试使用这样的排序,其中 -t 按 > 分隔符排序,然后按第 4 列排序,这将在内部,但它不起作用。

sort -t'>' -k4 file > final.xml
Run Code Online (Sandbox Code Playgroud)

我得到时髦的输出,它用排序的内部标签对其他列进行排序。

任何帮助,将不胜感激

ste*_*ver 8

[在Kusalananda的慷慨协助]

您可以使用做到这一点xq从包装YQ(一个jq杠杆的YAML / XML包装)jq的排序功能:

$ xq -x 'getpath([paths(scalars)[0:-1]] | unique | .[])
    |= (to_entries|sort_by(.key)|from_entries)' file.xml
<Module>
  <Settings>
    <Dimensions>
      <Length>2000</Length>
      <Volume>13000</Volume>
      <Width>5000</Width>
    </Dimensions>
    <Stats>
      <Max>3000</Max>
      <Mean>1.0</Mean>
      <Median>250</Median>
    </Stats>
  </Settings>
  <Debug>
    <Errors>
      <MagicMan>0</MagicMan>
      <Strike>0</Strike>
      <Wag>1</Wag>
    </Errors>
  </Debug>
</Module>
Run Code Online (Sandbox Code Playgroud)

解释:

  • paths(scalars)生成从根到叶的所有路径的列表,然后数组 slice[0,-1]删除叶节点,从而生成到最深非叶节点的路径列表:

    ["Module","Settings","Dimensions"]
    ["Module","Settings","Dimensions"]
    ["Module","Settings","Dimensions"]
    ["Module","Settings","Stats"]
    ["Module","Settings","Stats"]
    ["Module","Settings","Stats"]
    ["Module","Debug","Errors"]
    ["Module","Debug","Errors"]
    ["Module","Debug","Errors"]
    
    Run Code Online (Sandbox Code Playgroud)
  • [paths(scalars)[0:-1]] | unique | .[]将列表放入一个数组中,以便它可以通过unique. 迭代器.[]将其转回列表:

    ["Module","Debug","Errors"]
    ["Module","Settings","Dimensions"]
    ["Module","Settings","Stats"]
    
    Run Code Online (Sandbox Code Playgroud)
  • getpath()将去重列表转换为底层对象,其内容可以使用|=update-assign 运算符进行排序和更新

-x选项告诉xq将结果转换回 XML 而不是将其保留为 JSON。

请注意,如果键不唯一,则 whilesort在这里代替sort_by(.key)前者隐式按值和键排序。