在 Linux 中使用 XPATH 示例解析 XML 和剥离标签

举报
Tiamo_T 发表于 2022/09/19 23:40:25 2022/09/19
【摘要】 本文逐步解释了构建有用的多部分命令的过程。 要在终端中构建复杂的命令,我们需要了解管道。管道基本上是获取一个命令的输出并将其发送到另一个命令作为输入。这是通过 | (管道)符号。

本文逐步解释了构建有用的多部分命令的过程。

要在终端中构建复杂的命令,我们需要了解管道。管道基本上是获取一个命令的输出并将其发送到另一个命令作为输入。这是通过 | (管道)符号。

上个月,一个小项目需要我反复阅读类似的 XML 文件,以便为另一个程序提供测试数据。我将不得不如此频繁地这样做,以至于不得不下载、保存、解析和重复会很烦人。基本要求是:

  1. 从 URL 获取 XML
  2. 解析 XML 并仅选择所有元素的两个属性
  3. 剥离标签,只保留内容
  4. 发送到标准输出

1.证明命令行可以解析XML

去年我曾使用 Ruby 库 REXML::Xpath 编写脚本,我记得命令行上有一个 Perl 版本。您可以使用 CPAN 安装它:

$ cpan XML::XPath

让我们使用一个示例员工文件来实现这个想法。在浏览器中打开这个employees.xml文件,在浏览器中打开它并保存为employees.xml。

现在我们有了 xpath 命令和一个可以使用的文件。

用一个简单的路径测试它:


$ xpath employees.xml '/DIRECTORY/EMPLOYEE/FIRST_NAME'
­­ NODE ­­
<FIRST_NAME>Steven</FIRST_NAME>­­ NODE ­­
<FIRST_NAME>Susan</FIRST_NAME>­­ NODE ­­
<FIRST_NAME>Marigold</FIRST_NAME>­­ NODE ­­
...
<FIRST_NAME>Sunny</FIRST_NAME>­­ NODE ­­
<FIRST_NAME>Flo</FIRST_NAME>

出色的!它打印所选路径上每个 /EMPLOYEE 的 FIRST_NAME 属性。但是我们如何选择多个 XPath 元素呢?查看 XPath 语法,我们看到了一种方法。将 XPath 表达式与 | 字符,我们创建一个 OR 表达式。

$ xpath employees.xml '/DIRECTORY/EMPLOYEE/ FIRST_NAME | /DIRECTORY/EMPLOYEE/LAST_NAME'
--­­ NODE ­­--
<FIRST_NAME>Steven</FIRST_NAME>­­-- NODE ­­--
<LAST_NAME>Sanguini</LAST_NAME>­--­ NODE ­--­
<FIRST_NAME>Susan</FIRST_NAME>­­-- NODE ­­--
<LAST_NAME>Aquilegia</LAST_NAME>--­­ NODE --­­
...
<FIRST_NAME>Flo</FIRST_NAME>­­-- NODE ­­--
<LAST_NAME>Lobalessia</LAST_NAME>

注意,这里 | 被解释为 OR 运算符而不是输出重定向。

此外,在此语句中,我们选择 X 和 Y。为什么 OR 选择两者?它分别评估 XML 文档中的每个节点,如果节点是 A 或 B,它通过评估,并传递到输出。

2.下载XML并发送到STDOUT

下一步实际上将在命令行中更早出现,我们将单独构建它。我更喜欢首先构建最难的或“你做不到”的命令条目作为概念证明。如果第一步不能工作,那么做周围的命令行工作是没有意义的。

cURL 是用于 HTTP 交互的强大命令。这些curl 示例将使您朝着正确的方向开始。

如果需要,我们会指定一个位置,然后进行重定向。为此,请使用此选项:-L 'https://www.thegeekstuff.com/scripts/employees.xml'

我们关闭 cURL 的信息输出。并指定 GET 协议。为此,请使用此选项:-s G

因此,让我们在之前下载的文件的 URL 上测试我们的命令:

$ curl -­s -­G -­L ' https://www.thegeekstuff.com/scripts/employees.xml'
<?xml version="1.0" encoding="UTF­8"?>
<DIRECTORY>
<EMPLOYEE>
<FIRST_NAME>Steven</FIRST_NAME>
<LAST_NAME>Sanguini</LAST_NAME>
<STORE_NUMBER>4</STORE_NUMBER>
<SHIFT>FIRST</SHIFT>
<AUM>$2.44</AUM>
<ID>031599</ID>
</EMPLOYEE>

它默认为标准输出。这很好,因为我们现在要将它重定向到 XPath 删除文件参数:

$ curl ­-s -­G -­L ' https://www.thegeekstuff.com/scripts/employees.xml' | xpath \
'/DIRECTORY/EMPLOYEE/LAST_NAME | /DIRECTORY/EMPLOYEE/ID'
­--­ NODE ­­--
<LAST_NAME>Sanguini</LAST_NAME>­­-- NODE ­­--
<ID>031599</ID>­­ NODE ­­
<LAST_NAME>Aquilegia</LAST_NAME>­­-- NODE -- ­­
<ID>030699</ID>­­-- NODE ­­--
...
<LAST_NAME>Lobalessia</LAST_NAME>--­­ NODE --­­
<ID>022299</ID>

这会产生预期的输出。伟大的!不知道为什么,但 XPath 将“节点”发送到标准错误 (STDERR)。但我们稍后会看到一个可能的原因。

3.剥离XML标签

现在我们需要能够剥离这些标签并只获取内容。Sed 是进行即时正则表达式替换的最佳工具。学习 REGEX 超出了本文的范围。

有关更多信息,请参阅我们关于Python 正则表达式的系列文章。

当使用多个参数和标志制作复杂的命令时,我发现最好使用一个简单的示例,直到我得到它恰到好处,然后将实际参数粘贴到上下文中。我们通过管道将一个简单的字符串传递给 sed 以进行测试替换。Sed 默认在 STDIN 上工作。

$ echo "This<strong> is </strong>a test." | sed ­-re 's/i//g'
Ths<strong> s </strong>a test.

好的。这样可行。现在重写搜索以替换标签。

$ echo "This<strong> is </strong>a test." | sed ­-re 's/<\w+>//g'
This is </strong>a test.

好的。让我们通过添加前缀 '\' 转义的 '/' 来删除关闭标签,并通过后缀 '?' 使其成为可选。

$ echo "This<strong> is </strong>a test." | sed ­re 's/<\/?\w+>//g'
This is a test.

完美的。正是我们所期望的。

4. 把它们放在一起

现在我们已经创建了命令的各个部分,我们按照逻辑顺序将它们粘贴在一起,由 | 连接。.

curl ­-s -­G -­L ' https://www.hgst.com.cn/scripts/employees.xml' | \
xpath '/DIRECTORY/EMPLOYEE/LAST_NAME | /DIRECTORY/EMPLOYEE/ID ' | \
sed ­-re 's/<\/?\w+>//g'

输出:

Found 72 nodes:
--­­ NODE -- ­­
­--­ NODE ­­--
...
Sanguini031599Aquilegia030699...

哦哦!也许这就是为什么存在“节点”标记的原因。如果我们将其通过管道传输到文件,则 NODE 文本不会跟随。它们被发送到标准错误(STDERR),但我们可以使用`2>&1`(解释)重定向到STDOUT,并使用sed替换`sed re's/ NODE //g'`以与标签。

curl -­s -­G -­L 'https://www.hgst.com.cn/scripts/employees.xml' | \
xpath '/DIRECTORY/EMPLOYEE/LAST_NAME | /DIRECTORY/EMPLOYEE/ID '
2>&1| sed -­re 's/­--­NODE--­­//g' | sed -­re 's/<\/?\w+>//g'

输出:

Found 72 nodes:
Sanguini
031599
Aquilegia
030699
...
Lobalessia
022299

完美的。现在,当我处理我的项目时,我可以快速从 Web 上的 XML 文件获取示例数据到 STDOUT,而无需保存文件或运行一些复杂的软件。我们甚至可以通过管道将其传递给 `tail –n+3` 以切断前两条响应行。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。