626

相关:如何在(unix)shell 脚本中漂亮地打印 JSON?

是否有(unix)shell 脚本以人类可读的形式格式化 XML?

基本上,我希望它转换以下内容:

<root><foo a="b">lorem</foo><bar value="ipsum" /></root>

...变成这样的东西:

<root>
    <foo a="b">lorem</foo>
    <bar value="ipsum" />
</root>
4

11 回答 11

1076

xmllint

该实用程序附带libxml2-utils

echo '<root><foo a="b">lorem</foo><bar value="ipsum" /></root>' |
    xmllint --format -

Perl 的XML::Twig

此命令附带XML::Twig 模块,有时xml-twig-tools打包:

echo '<root><foo a="b">lorem</foo><bar value="ipsum" /></root>' |
    xml_pp

xmlstarlet

此命令附带xmlstarlet

echo '<root><foo a="b">lorem</foo><bar value="ipsum" /></root>' |
    xmlstarlet format --indent-tab

tidy

检查tidy包装:

echo '<root><foo a="b">lorem</foo><bar value="ipsum" /></root>' |
    tidy -xml -i -

Python

Pythonxml.dom.minidom可以格式化 XML(也适用于旧版 python2):

echo '<root><foo a="b">lorem</foo><bar value="ipsum" /></root>' |
    python -c 'import sys; import xml.dom.minidom; s=sys.stdin.read(); print(xml.dom.minidom.parseString(s).toprettyxml())'

saxon-lint

你需要saxon-lint

echo '<root><foo a="b">lorem</foo><bar value="ipsum" /></root>' |
    saxon-lint --indent --xpath '/' -

saxon-HE

你需要saxon-HE

 echo '<root><foo a="b">lorem</foo><bar value="ipsum" /></root>' |
    java -cp /usr/share/java/saxon/saxon9he.jar net.sf.saxon.Query \
    -s:- -qs:/ '!indent=yes'
于 2013-04-18T18:51:29.917 回答
183

xmllint --format yourxmlfile.xml

xmllint是一个命令行 XML 工具,包含在libxml2( http://xmlsoft.org/ ) 中。

=================================================

注意:如果您还没有libxml2安装,您可以通过执行以下操作来安装它:

中央操作系统

cd /tmp
wget ftp://xmlsoft.org/libxml2/libxml2-2.8.0.tar.gz
tar xzf libxml2-2.8.0.tar.gz
cd libxml2-2.8.0/
./configure
make
sudo make install
cd

Ubuntu

sudo apt-get install libxml2-utils

赛格温

apt-cyg install libxml2

苹果系统

要使用 Homebrew 在 MacOS 上安装它,只需执行以下操作: brew install libxml2

吉特

如果你想要代码,也可以在 Git 上找到: git clone git://git.gnome.org/libxml2

于 2013-11-15T15:34:53.020 回答
45

您也可以使用tidy,它可能需要先安装(例如在 Ubuntu 上: sudo apt-get install tidy)。

为此,您将发出如下内容:

tidy -xml -i your-file.xml > output.xml

注意:有许多额外的可读性标志,但自动换行行为有点烦人(http://tidy.sourceforge.net/docs/quickref.html)。

于 2014-10-12T16:29:08.500 回答
19

无需在 macOS / 大多数 Unix 上安装任何东西。

采用tidy

cat filename.xml | tidy -xml -iq

使用 cat 重定向查看文件以整齐指定 xml 的文件类型并在安静输出时缩进将抑制错误输出。JSON 也适用于-json.

于 2019-05-09T20:12:35.320 回答
15

您没有提到文件,所以我假设您想在命令行上提供 XML 字符串作为标准输入。在这种情况下,请执行以下操作:

$ echo '<root><foo a="b">lorem</foo><bar value="ipsum" /></root>' | xmllint --format -
于 2013-04-18T19:09:58.267 回答
11

xmllint 支持就地格式化

for f in *.xml; do xmllint -o $f --format $f; done

正如 Daniel Veillard 所写:

我认为 xmllint -o tst.xml --format tst.xml 应该是安全的,因为解析器会在打开输出以对其进行序列化之前将输入完全加载到树中。

缩进级别XMLLINT_INDENT由默认为 2 个空格的环境变量控制。示例如何将缩进更改为 4 个空格:

XMLLINT_INDENT='    '  xmllint -o out.xml --format in.xml

--recover当您的 XML 文档损坏时,您可能缺少选项。或者尝试使用严格的 XML 输出的弱 HTML 解析器:

xmllint --html --xmlout <in.xml >out.xml

--nsclean, --nonet,--nocdata--noblanks可能有用。阅读手册页。

apt-get install libxml2-utils
apt-cyg install libxml2
brew install libxml2
于 2018-05-28T20:18:09.667 回答
3

我花了很长时间才找到可以在我的 Mac 上运行的东西。这对我有用:

brew install xmlformat
cat unformatted.html | xmlformat
于 2020-03-16T06:31:46.853 回答
2

这种简单的(st)解决方案不提供压痕,但在人眼上却容易得多。它还允许通过简单的工具(如 grep、head、awk 等)更轻松地处理 xml。

用于sed将 '<' 替换为自身,前面带有换行符。

正如 Gilles 所提到的,在生产中使用它可能不是一个好主意。

# check you are getting more than one line out
sed 's/</\n</g' sample.xml | wc -l

# check the output looks generally ok
sed 's/</\n</g' sample.xml | head

# capture the pretty xml in a different file
sed 's/</\n</g' sample.xml > prettySample.xml
于 2020-12-10T12:39:13.103 回答
0

编辑:

免责声明:您通常应该更喜欢安装像xmllint这样的工作这样的成熟工具。XML/HTML 可能是一个可怕的残缺不全的混乱。但是,在某些情况下,使用现有工具比手动安装新工具更可取,并且可以肯定的是,XML 的源代码是有效的(足够了)。我已经为其中一种情况编写了此脚本,但它们很少见,因此请谨慎行事。


我想添加一个纯 Bash 解决方案,因为手动完成并不难,有时您不想安装额外的工具来完成这项工作。

#!/bin/bash

declare -i currentIndent=0
declare -i nextIncrement=0
while read -r line ; do
  currentIndent+=$nextIncrement
  nextIncrement=0
  if [[ "$line" == "</"* ]]; then # line contains a closer, just decrease the indent
    currentIndent+=-1
  else
    dirtyStartTag="${line%%>*}"
    dirtyTagName="${dirtyStartTag%% *}"
    tagName="${dirtyTagName//</}"
    # increase indent unless line contains closing tag or closes itself
    if [[ ! "$line" =~ "</$tagName>" && ! "$line" == *"/>"  ]]; then
      nextIncrement+=1
    fi
  fi

  # print with indent
  printf "%*s%s" $(( $currentIndent * 2 )) # print spaces for the indent count
  echo $line
done <<< "$(cat - | sed 's/></>\n</g')" # separate >< with a newline

将其粘贴到脚本文件中,然后通过管道输入 xml。这假设 xml 都在一行上,并且任何地方都没有多余的空格。人们可以很容易地在正则表达式中添加一些额外\s*的内容来解决这个问题。

于 2020-05-06T17:10:40.417 回答
0

我会:

nicholas@mordor:~/flwor$ 
nicholas@mordor:~/flwor$ cat ugly.xml 


<root><foo a="b">lorem</foo><bar value="ipsum" /></root>

nicholas@mordor:~/flwor$ 
nicholas@mordor:~/flwor$ basex
BaseX 9.0.1 [Standalone]
Try 'help' to get more information.
> 
> create database pretty
Database 'pretty' created in 231.32 ms.
> 
> open pretty
Database 'pretty' was opened in 0.05 ms.
> 
> set parser xml
PARSER: xml
> 
> add ugly.xml
Resource(s) added in 161.88 ms.
> 
> xquery .
<root>
  <foo a="b">lorem</foo>
  <bar value="ipsum"/>
</root>
Query executed in 179.04 ms.
> 
> exit
Have fun.
nicholas@mordor:~/flwor$ 

如果只是因为它“在”一个数据库中,而不是“只是”一个文件。在我看来,更容易使用。

相信其他人已经解决了这个问题。如果您愿意,毫无疑问eXist甚至可能在格式化方面“更好” xml,或者一样好。

当然,您始终可以以各种不同的方式查询数据。我尽量保持简单。您也可以只使用 GUI,但您指定了控制台。

于 2020-11-22T11:16:32.640 回答
0

使用

xidel -s input.xml -se . --output-node-format=xml --output-node-indent
<root>
  <foo a="b">lorem</foo>
  <bar value="ipsum"/>
</root>

或者file:write("output.xml",.,{"indent":true()})保存到文件。

于 2020-11-28T16:11:28.207 回答