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

如何使用xmlint--xpath在每次匹配后追加换行符,xml,shell,xpath,xmllint,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> 目前我正在使用: xmllint --xpath '//textarea[@name="comm

我有以下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>
目前我正在使用:

xmllint --xpath '//textarea[@name="command"]/text()' --html

但它不会在每次比赛后添加换行符。

我做了以下丑陋的把戏,请随时提供更好的解决方案

通过使用以下命令将
替换为
\n
更改了HTML代码:

sed 's/\<\/textarea/\'$'\n\<\\/textarea/g' f

sed的/\您好,从2020年开始

从libxml的v2.9.9开始,这种行为就不再存在了

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

正如我从中收集到的,从理论上讲,可以将命令馈送到older的
--shell
选项中(/dev/null
在最末端抑制它(冒着抑制打印到标准错误的其他消息的风险)

解释了XMLStarlet选项(另请参见):

  • fo-H-R
    -fo格式化输出,期望HTML输入,并恢复尽可能多的错误输入
    • 这将添加一个
      根节点,使OP示例中的片段成为有效的XML
  • sel-T-T-v//xpath-n
    -select节点基于xpath
    //xpath
    • 输出纯文本(
      -T
      )而不是XML
    • 使用给定的模板(
      -t
      ),该模板返回节点的值(
      -v
      ),而不是节点本身(允许您放弃在XPath表达式中使用
      text()
    • 最后,添加一个换行符(
      -n
Edit(s):删除了一半实现的
xmllint--shell
解决方案,因为它很糟糕。添加了一个实际使用OP数据的XMLStarlet示例。

试试,它提供了两个选项:

  • --xpath
    :与旧的
    --xpath
    相同,节点之间用
    \n
    分隔

  • --xpath0
    :与旧的
    --xpath
    相同,节点之间用
    \0
    分隔

测试输入(
a.html
):

测试输出1:

 1
 2
测试命令2:

# xmllint --xpath0 '//textarea[@name="command"]/text()' --html a.html | xargs -0 -n1
测试输出2:

 1
 2

这是一个包装器脚本,完全用于新行分隔的输出(对于
xmllint
的旧版本):

!/bin/bash
#将脚本包装到
#-在Xpath查询上有换行符分隔的输出
#-在非常旧的版本上实现--xpath
/usr/bin/xmllint--xpath&>/dev/null
实现_xpath=$?
换行符\u分隔\u xmllint\u版本=20909
当前版本=$(xmllint--version |&awk'NR==1{print$NF;exit})
args=(“$@”)
如果[$@=*--xpath*];则
#迭代位置参数
对于((i=0;i=20909)| |$file==-| |$file==/dev/stdin | |$xpath==/| |$xpath==string\(*]]
然后
exec/usr/bin/xmllint“$@”
其他的

exec/usr/bin/xmllint“${args[@]}”-shell您现在是如何获得输出的?您在哪里测试的?@Babai假设上述HTML代码在文件f中可用,
xmllint--xpath'//textarea[@name=“command”]/text()“--HTMLF
事实上,我在在线工具中测试过它,文本将出现一行新的内容..因此试图理解您要将其打印到哪里..@Babai在这种情况下,我猜您使用的工具的行为与
xmllint
不同。您好,从未来开始!此行为在libxml2版本2.9.9和
--xpath
中得到了修复(最后)在转储XPath节点时,是否符合您的期望。如果您使用的是旧的libxml2,请参阅下面使用XMLStarlet的替代解决方案。您可以使用其他字符作为sed的分隔符,例如,
%
,因此不需要跳出斜杠。如果不美观,请不要发布它。“sed”不是一个XML解析器,拥有此功能将非常好乌尔merged@AdamSiemion不确定他们是否有访问gnome git repo的rw权限。如果他们在github上托管他们的源代码,我很乐意发送一个拉取请求。另外,需要他们团队中的人做一些健全性检查。@Cyker你的代码还在那里,仍然打开,但是你的
--xpath
修复了为v2.9.9添加新行的问题。谢谢!@Theudea非常感谢您的提醒。这一更改以字符串形式硬编码
\n
,这使得使用
\0
进行分离几乎不可能。因此,此修补程序无法再合并,我不会重新设置基础。我将把它留在那里,以防有人不需要最新的功能,而是
\0
@Cyker Bummer。非常感谢您的努力,不是吗ess.该链接指向了此页面上已接受的答案。哈。捕捉得好。我的剪贴板中一定有其他内容。现在已修复。
:)
如果您正在解析其他人的HTML,还值得注意的是“格式良好”(X)如今,
xmllint
xmlstartet
可以无误解析的各种HTML似乎是……一种罕见的东西。你可以按照建议尝试
xmllint--HTML
,这对输入格式来说稍微宽容一些。有时即使这样也不起作用,我会先把输入的HTML传递一次。或者放弃d使用正则表达式,此时我有两个问题。
# xmllint --xpath '//textarea[@name="command"]/text()' --html a.html
 1
 2
# xmllint --xpath0 '//textarea[@name="command"]/text()' --html a.html | xargs -0 -n1
 1
 2
#!/bin/bash

# wrapper script to
# - have newline delimited output on Xpath querys
# - implements --xpath on very old releases

/usr/bin/xmllint --xpath &>/dev/null
implements_xpath=$?

newlines_delimited_xmllint_version=20909
current_version=$(xmllint --version |& awk 'NR==1{print $NF;exit}')

args=( "$@" )
if [[ $@ == *--xpath* ]]; then
    # iterate over positional parameters
    for ((i=0; i<${#args}; i++)); do
        if [[ ${args[i]} == --xpath ]]; then
            xpath="${args[i+1]}"
            unset args[i+1]
            unset args[i]
            break
        fi
    done
    if [[ ($implements_xpath==0 && $current_version>=20909) || $file == - || $file == /dev/stdin || $xpath == / || $xpath == string\(* ]]
    then
        exec /usr/bin/xmllint "$@"
    else
        exec /usr/bin/xmllint "${args[@]}" --shell <<< "cat $xpath" | sed '1d;$d;s/^ ------- *$//;/^$/d'
    fi
else
    exec /usr/bin/xmllint "$@"
fi