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

时间:2013-08-30 12:28:50

标签: 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>

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

1
2

目前我正在使用:

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

但每场比赛后都不会附加换行符。

5 个答案:

答案 0 :(得分:2)

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

使用以下命令将</textarea>替换为\n</textarea>来更改HTML代码:

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

答案 1 :(得分:2)

尝试this patch,它提供2个选项:

  • --xpath:与旧的--xpath相同,节点之间由\n隔开。

  • --xpath0:与旧的--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>

测试命令1:

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

测试输出1:

 1
 2

测试命令2:

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

测试输出2:

 1
 2

答案 2 :(得分:1)

当我从this SO answer收集时,也可以:

    varOpexAmount  = $(xml).find('d\\:OpexAmount ')

    varPreCapexorCapexAmount  = $(xml).find('d\\:PreCapexorCapexAmount ')

    varSuppCapexAmount = $(xml).find('d\\:SuppCapexAmount')

    varBudget = varOpexAmount + varPreCapexorCapexAmount + varSuppCapexAmount;
    $("#Budget").append(varBudget); 

然后使用

删除输出中的“分隔符”(破折号行)
xmllint --shell input.xml <<<'cat //textarea[@name="command"]/text()'

我觉得这样可以让你更接近你想要看到的东西,最初是作为一个人,并且去除你想要的东西的正则表达式更加明显和精确

但是,在管道中间使用相同的方法可能是不可能的,因为在这种情况下stdin是包含all that whatnot above | sed '/^ -/d' shell的cat命令的“here string”。 / p>

同一主题中的另一个建议是使用xmllint,如果有的话:

xmlstarlet

...并且这仍然可以在管道中正常运行,例如,从xmlstarlet sel -t -v '//textarea[@name="command"]/text()' input.xml 或其他东西。

答案 3 :(得分:0)

这是一个包装脚本,专门用于换行符分隔输出(对于xmllint的旧版本):

#!/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

检查最新修订:https://github.com/sputnick-dev/xmllint

Debian Buster于2020年6月29日发布了2.9.4版本,该版本已发布4年。
Debian测试/实验版为2.9.10,这是固定版本。

另一种在Debian上一个稳定版本中安装2.9.10的方法:https://serverfault.com/a/1022826/120473(不冒使apt系统崩溃的风险)

答案 4 :(得分:0)

换行符可以合法地出现在 xml 数据中。更可靠的方法是用一个字符来分隔 xpath 结果,保证不会出现在 XML 数据中。 Null character 中的 Universal Coded Character Set,U+0000,就是这样一个字符。

<块引用>

注意代码点U+0000,分配给空控件 字符,是唯一以 Unicode 和 ISO/IEC 10646 编码的字符 这在任何 XML 1.0 和 1.1 文档中总是无效的。
https://en.wikipedia.org/wiki/Valid_characters_in_XML

@Cyker 的 xmllintmerge request 包括添加一个 -xpath0 选项,该选项将通过 NUL 分隔 xpath 结果。此功能的 A new feature request 也已打开。

希望 xmllint 能尽快获得此功能。

现在可以诱使另一个 xpath 命令行工具 xmlstarlet 实现此目标。 xmlstarlet 目前不直接支持 NUL 的输出,但是我们可以让它输出 U+FFFF,它和 NUL 一样,保证不会出现在 XML 数据中。 (我假设 Universal Coded Character Set 是 UTF-8 编码。)然后我们只需要将 U+FFFF 转换为 U+0000,我们就会得到 NUL 分隔的 xpath 结果。

在以下示例中,我将使用以下部分 html 文件。与问题中的数据相同,只是我添加了换行符以进行测试。

cat > data.html <<'EOF'
<textarea name="command" class="setting-input fixed-width" rows="9">1 
 newline</textarea>
<textarea name="command" class="setting-input fixed-width" rows="5">2 
 newline</textarea>
EOF

以下是如何使用 xmlstarletperl 单行来用 NUL 分隔 xpath 结果:

xmlstarlet fo -H -R data.html \
| xmlstarlet sel -t -m '//textarea[@name="command"]' -v '.' -o $'\uffff' \
| perl -C -0xFFFF -l0 -pe ''

注意:我通过 xmlstarlet fo -H -R 运行 HTML,如@TheDudeAbides 的回答所示。

既然 xpath 结果由 NUL 分隔,我们可以在 xargs -0 的帮助下处理结果。示例:

xmlstarlet fo -H -R data.html \
| xmlstarlet sel -t -m '//textarea[@name="command"]' -v '.' -o $'\uffff' \
| perl -C -0xFFFF -l0 -pe '' \
| xargs -0 -n 1 printf '%q\n'

结果:

'1 '$'\n'' newline'
'2 '$'\n'' newline'

或将其加载到 bash 数组中:

mapfile -t -d '' a < <(
 xmlstarlet fo -H -R data.html \
 | xmlstarlet sel -t -m '//textarea[@name="command"]' -v '.' -o $'\uffff' \
 | perl -C -0xFFFF -l0 -pe ''
)

declare -p a

结果:

declare -a a=([0]=$'1 \n newline' [1]=$'2 \n newline')