如何使用xmlint --xpath在每次匹配后追加换行符

Ada*_*ion 8 xml shell xpath xmllint

我有以下HTML代码:

<textarea name="command" class="setting-input   fixed-width" rows="9">1</textarea><textarea name="command" class="setting-input   fixed-width" rows="5">2</textarea>
Run Code Online (Sandbox Code Playgroud)

我想解析它以接收这样的输出:

1
2
Run Code Online (Sandbox Code Playgroud)

目前我正在使用:

xmllint --xpath '//textarea[@name="command"]/text()' --html
Run Code Online (Sandbox Code Playgroud)

但每次比赛后都不会附加换行符.

The*_*des 10

你好,从 2020 年开始!

从 libxml 的 v2.9.9 开始,此行为本身已得到修复xmllint

但是,如果您使用比这更旧的任何东西,并且不想从源代码构建 libxml 只是为了获得固定的xmllint,您将需要此处的其他解决方法之一。例如,在撰写本文时,最新的 CentOS 8 仍在使用 libxml (2.9.7) 版本,其行为方式与 OP 描述的方式相同。

当我从这个 SO answer 中收集到时,理论上可以将命令输入到--shell较旧(<2.9.9)版本的选项中xmllint,这将在单独的行上生成每个节点。但是,您最终不得不对其进行后期处理sedgrep删除 shell 模式(面向人的)输出的视觉碎片。这并不理想。


XMLStarlet(如果可用)提供了另一种解决方案,但xmlstarlet foxmlstarlet sel用于提取节点之前,您确实需要使用将 HTML 片段格式化为有效的 XML :

echo '
<textarea name="command" class="setting-input fixed-width"
 rows="9">1</textarea>
<textarea name="command" class="setting-input fixed-width"
 rows="5">2</textarea>' \
  | xmlstarlet fo -H -R \
  | xmlstarlet sel -T -t -v '//textarea[@name="command"]' -n
Run Code Online (Sandbox Code Playgroud)

如果Attempt to load network entity来自第二次xmlstarlet调用的消息惹恼了您,只需2>/dev/null在最后添加以抑制它(冒着抑制打印到标准错误的其他消息的风险)。

解释了 XMLStarlet 选项(另请参阅用户指南):

  • fo -H -R- FO RMAT输出,期望HTML输入,并回收尽可能多的坏输入尽可能
    • 这将添加一个<html>根节点,使 OP 示例中的片段成为有效的 XML
  • sel -T -t -v //xpath -n—基于 XPath选择节点//xpath
    • 输出纯文本 ( -T) 而不是 XML
    • 使用给定的模板 ( -t) 返回-v节点的值 ( ) 而不是节点本身(允许您放弃text()在 XPath 表达式中使用)
    • 最后,添加一个换行符 ( -n)

编辑:删除了半实现的xmllint --shell解决方案,因为它很糟糕。添加了一个实际处理 OP 数据的 XMLStarlet 示例。


Cyk*_*ker 5

试试这个 patch,它提供了 2 个选项:

  • --xpath: 与 old 相同--xpath,节点由\n.

  • --xpath0: 与 old 相同--xpath,节点由\0.

测试输入 ( a.html):

<textarea name="command" class="setting-input   fixed-width" rows="9">1</textarea><textarea name="command" class="setting-input   fixed-width" rows="5">2</textarea>
Run Code Online (Sandbox Code Playgroud)

测试命令1:

# xmllint --xpath '//textarea[@name="command"]/text()' --html a.html
Run Code Online (Sandbox Code Playgroud)

测试输出 1:

 1
 2
Run Code Online (Sandbox Code Playgroud)

测试命令2:

# xmllint --xpath0 '//textarea[@name="command"]/text()' --html a.html | xargs -0 -n1
Run Code Online (Sandbox Code Playgroud)

测试输出 2:

 1
 2
Run Code Online (Sandbox Code Playgroud)

  • 合并此功能会很棒 (2认同)