如何从命令行漂亮地打印 XML?

Posted

技术标签:

【中文标题】如何从命令行漂亮地打印 XML?【英文标题】:How to pretty print XML from the command line? 【发布时间】:2013-04-12 00:50:40 【问题描述】:

相关:How can I pretty-print JSON in (unix) shell script?

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

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

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

...变成这样的:

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

【问题讨论】:

要在 Debian 系统上使用 xmllint,您需要安装软件包 libxml2-utilslibxml2 不提供此工具,至少在 Debian 5.0 "Lenny" 和 6.0 "Squeeze 上不提供")。 【参考方案1】:

xmllint

此实用程序附带libxml2-utils

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

Perl 的XML::Twig

此命令带有XML::Twig perl 模块,有时是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

Python 的 xml.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'

【讨论】:

好,快速的回答。第一个选项似乎在现代 *nix 安装中会更加普遍。一个小问题;但是可以在不通过中间文件的情况下调用它吗?即echo '&lt;xml .. /&gt;' | xmllint --some-read-from-stdn-option? 我漂亮的 ubuntu 中的包是 libxml2-utils 请注意,“cat data.xml | xmllint --format - | tee data.xml”不起作用。在我的系统上,它有时适用于小文件,但总是截断大文件。如果您真的想做任何事情,请阅读backreference.org/2011/01/29/in-place-editing-of-files 解决UnicodeDecodeError: 'ascii' codec can't decode byte 0xc5 in position 805: ordinal not in range(128)在python版本中要定义PYTHONIOENCODING="UTF-8":cat some.xml | PYTHONIOENCODING="UTF-8" python -c 'import sys;import xml.dom.minidom;s=sys.stdin.read();print xml.dom.minidom.parseString(s).toprettyxml()' &gt; pretty.xml 请注意,tidy 也可以格式化没有根元素的 xml。这对于通过管道格式化 xml 部分(例如从日志中提取)很有用。 echo '&lt;x&gt;&lt;/x&gt;&lt;y&gt;&lt;/y&gt;' | tidy -xml -iq【参考方案2】:

xmllint --format yourxmlfile.xml

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

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

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

CentOS

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

MacOS

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

Git

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

【讨论】:

sputnick 的回答包含此信息,但 crmpicco 的回答是关于如何漂亮打印 XML 的一般问题的最有用的回答。 我们可以将格式化后的 xml 输出写入其他 xml 文件并使用它。例如 xmllint --format yourxmlfile.xml >> new-file.xml 在 Ubuntu 16.04 上,您可以使用以下内容:sudo apt-get install libxml2-utils 这也适用于 Windows; git for Windows download 甚至安装了最新版本的xmllint。示例:"C:\Program Files\Git\usr\bin\xmllint.exe" --format QCScaper.test@borland.com.cds.xml &gt; QCScaper.test@borland.com.pretty-printed.cds.xml 来自 MacOS,通过 brew 安装了 libxml2。要为我取消最小化 xml 并将其保存到一个新文件中,它可以使用此命令 xmllint --format in.xml &gt; out.xml【参考方案3】:

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

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

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

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

【讨论】:

很有帮助,因为我无法让 xmllint 将换行符添加到单行 xml 文件中。谢谢! tidy 也适合我。与hxnormalize 不同,这样做实际上关闭了&lt;body&gt; 标签。 顺便说一句,这里有一些我发现有用的选项:tidy --indent yes --indent-spaces 4 --indent-attributes yes --wrap-attributes yes --input-xml yes --output-xml yes &lt; InFile.xml &gt; OutFile.xml. 很棒的提示@VictorYarema。我将它与 pygmentize 结合并将其添加到我的 .bashrc 中:alias prettyxml='tidy --indent yes --indent-spaces 4 --indent-attributes yes --wrap-attributes yes --input-xml yes --output-xml yes | pygmentize -l xml' 然后可以curl url | prettyxml【参考方案4】:

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

使用tidy

cat filename.xml | tidy -xml -iq

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

【讨论】:

您不需要cat 步骤:tidy -xml -iq filename.xml。此外,您甚至可以使用-m 选项来执行tidy -xml -iq filename.xml修改 原始文件...【参考方案5】:

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

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

【讨论】:

【参考方案6】:

xmllint support formatting in-place:

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

当您的 XML 文档损坏时,您可能缺少 --recover 选项。或者尝试使用严格的 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

【讨论】:

【参考方案7】:

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

brew install xmlformat
cat unformatted.html | xmlformat

【讨论】:

【参考方案8】:

这个简单的(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

【讨论】:

【参考方案9】:

编辑:

免责声明:您通常应该更喜欢安装像 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* 来解决这个问题。

【讨论】:

希望永远不会在某个地方作为系统管理员看到这个 -_- @GillesQuenot 你什么意思?是否存在我没​​有看到的安全风险? 因为用真正的解析器以外的任何东西来解析 XML/HTML 是(或将很快)简单的错误。如果它是个人计算机上的一个小型个人脚本,由你决定,但对于生产来说,没办法。会坏的! 我同意 XML/HTML 可能会被严重破坏,但它确实取决于来源。我为我们自己生成的一些 XML 编写了这个,所以这是一个非常安全的选择。 直到实习生改变 XML 的制作方式 :)【参考方案10】:

我愿意:

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,但您指定了控制台。

【讨论】:

【参考方案11】:

与xidel:

xidel -s input.xml -e 'serialize(.,"indent":true())'
<root>
  <foo a="b">lorem</foo>
  <bar value="ipsum"/>
</root>

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

【讨论】:

以上是关于如何从命令行漂亮地打印 XML?的主要内容,如果未能解决你的问题,请参考以下文章

如何有效地漂亮打印 JSON 对象列表? [复制]

Python colorama | 详解终端漂亮的彩色打印怎么实现的

Python colorama | 详解终端漂亮的彩色打印怎么实现的

使用 Python 将 JSON 数据漂亮地打印到文件中

如何使用 maven mvn test 命令行运行动态 testng.xml?

LibreOffice 命令行 (soffice) 打印选项