学习解析XML通常被认为是一项复杂的冒险,但它不一定是。XML是高度严格的结构化的,所以它是相对可预测的。也有很多工具可以帮助使这项工作易于管理。
我最喜欢的XML工具之一是XMLStarlet,这是一个用于你的终端的XML工具箱。通过XMLStarlet,你可以验证、解析、编辑、格式化和转换XML数据。XMLStarlet是一个相对最小的命令,但浏览XML是充满潜力的,所以本文演示了如何使用它来查询XML数据。
安装
在CentOS、Fedora和许多其他现代Linux发行版上,XMLStarlet是默认安装的,所以只要打开终端,输入xmlstarlet
,就可以访问它。如果XMLStarlet还没有安装,你的操作系统会主动为你安装它。
另外,你也可以从你的软件包管理器中安装xmlstarlet
命令。
$ sudo dnf install xmlstarlet
复制代码
在macOS上,使用MacPorts或Homebrew。在Windows上,使用Chocolatey。
如果一切都失败了,你可以从Sourceforge的源代码中手动安装它。
用XMLStarlet解析XML
有许多工具被设计用来帮助解析和转换XML数据,包括让你编写自己的解析器的软件库和复杂的命令,如fop
和xsltproc
。不过,有时你并不需要处理XML数据;你只需要一个方便的方法来提取重要的数据,更新,或只是验证它。对于自发的XML交互,我使用xmlstarlet
,这是一个典型的 “瑞士军刀 “式的应用程序,可以完成最常见的XML任务。你可以通过运行命令和--help
选项来看看它能提供什么。
$ xmlstarlet --help
Usage: xmlstarlet [] []
where is one of:
ed (or edit) - Edit/Update XML document(s)
sel (or select) - Select data or query XML document(s) (XPATH, etc)
tr (or transform) - Transform XML document(s) using XSLT
val (or validate) - Validate XML document(s) (well-formed/DTD/XSD/RelaxNG)
fo (or format) - Format XML document(s)
el (or elements) - Display element structure of XML document
c14n (or canonic) - XML canonicalization
ls (or list) - List directory as XML
[...]
复制代码
你可以在这些子命令的末尾加上--help
,以获得进一步的帮助。
$ xmlstarlet sel --help
-Q or --quiet - do not write anything to standard output.
-C or --comp - display generated XSLT
-R or --root - print root element
-T or --text - output is text (default is XML)
-I or --indent - indent output
[...]
复制代码
用sel选择数据
你可以用xmlstarlet select
(简称sel
)命令查看XML中的数据。下面是一个简单的XML文件。
Fedora
7
Moonshine
Live
Fedora
Everything
Fedora Core
6
Zod
复制代码
当在一个XML文件中寻找数据时,你的首要任务是关注你想探索的节点。如果你知道该节点的路径,用--value-of
选项指定完整的路径。你在文档对象模型(DOM)树中越早开始探索,你看到的信息就越多。
$ xmlstarlet select --template \
--value-of /xml/os/linux/distribution \
--nl myfile.xml
Fedora
7
Moonshine
Live
Fedora
Everything
Fedora Core
6
Zod
复制代码
--nl
代表 “新行”,它插入了大量的空白,以确保你的终端提示符在你的结果出来后得到一个新行。我已经删除了样本输出中的一些多余的空间。
通过进一步下降到DOM树中来缩小你的焦点。
$ xmlstarlet select --template \
--value-of /xml/os/linux/distribution/name \
--nl myfile.xml
Fedora
Fedora Core
复制代码
条件性选择
用于导航和解析XML的最强大的工具之一叫做XPath。它规范了XML搜索中使用的语法,并从XML库中调用功能。XMLStarlet理解XPath表达式,所以你可以用XPath函数使你的选择成为条件。XPath具有丰富的功能,W3C对它进行了详细的记录,但我发现Mozilla的XPath文档更简洁。
你可以用方括号作为一个测试函数,将一个元素的内容与某个值进行比较。这里是对 元素的值的测试,它返回仅与特定匹配相关的版本号。
想象一下,样本XML文件包含了所有以1开头的Fedora版本。 要查看所有与旧名称 “Fedora Core “相关的版本号(该项目从第7版开始将 “Core “从名称中删除)。
$ xmlstarlet sel --template \
--value-of '/xml/os/linux/distribution[name = "Fedora Core"]/release' \
--nl myfile.xml
6
5
4
3
2
1
复制代码
您也可以查看这些发行版的所有代号,只要把--value-of
路径改为/xml/os/linux/distribution[name = "Fedora Core"]/codename
。
匹配路径和获取值
把XML标签看作节点的一个好处是,一旦你找到了节点,你就可以把它看作你当前的数据 “目录”。它不是一个真正的目录,至少不是文件系统意义上的目录,但它是一个你可以查询的数据集合。为了帮助你把目的地和 “里面 “的数据分开,XMLStarlet用--match
选项来区分你要匹配的内容,用--value-of
选项区分你要的数据值。
假设你知道 节点包含几个元素。这使它成为你的目的地。一旦你到了那里,你就可以用--value-of
来指定你想要哪个元素的值。要看所有的元素,用一个点(.
)来代表你当前的位置。
$ xmlstarlet sel --template \
--match '/xml/os/linux/distribution/spin' \
--value-of '.' --nl myfile.xml \
Live
Fedora
Everything
复制代码
与浏览DOM一样,你可以使用XPath表达式来限制返回数据的范围。在这个例子中,我使用last()
函数,只检索spin
节点中的最后一个元素。
$ xmlstarlet select --template \
--match '/xml/os/linux/distribution/spin' \
--value-of '*[last()]' --nl myfile.xml
Everything
复制代码
在这个例子中,我使用position()
函数来选择spin
节点中的一个特定元素。
$ xmlstarlet select --template \
--match '/xml/os/linux/distribution/spin' \
--value-of '*[position() = 2]' --nl myfile.xml
Fedora
复制代码
--match
和--value-of
选项可以重叠,所以由你决定如何一起使用它们。这两个表达式,在示例的XML中,做的是同样的事情。
$ xmlstarlet select --template \
--match '/xml/os/linux/distribution/spin' \
--value-of '.' \
--nl myfile.xml
Live
Fedora
Everything
$ xmlstarlet select --template \
--match '/xml/os/linux/distribution' \
--value-of 'spin' \
--nl myfile.xml
Live
Fedora
Everything
复制代码
适应XML
XML有时看起来过于冗长和笨重,但为与之互动而建立的工具一直让我感到惊讶。如果你想利用XML,那么XMLStarlet可能是一个很好的入门点。下次你要打开一个XML文件来查看结构化的数据时,可以尝试使用XMLStarlet,看看你是否可以查询这些数据。你对XML越熟悉,它就越能作为一种强大而灵活的数据格式为你服务。