【发布时间】:2024-01-14 21:53:01
【问题描述】:
给定this html5 page,使用xmllint 使用文件描述符与先前的子shell 交互地处理它。
申请于xml2xpath OS project。
如何重现:在“问题”部分运行脚本 sn-p
基本命令是:
(echo 'xpath //*'; echo "bye") | xmllint --shell html5.html
提供要处理的源输出:
/ > xpath //*
Object is a Node Set :
Set contains 346 nodes:
1 ELEMENT html
default namespace href=http://www.w3.org/1999/xhtml
ATTRIBUTE lang
TEXT
content=en
ATTRIBUTE dir
TEXT
content=ltr
2 ELEMENT head
3 ELEMENT title
...
202 ELEMENT div
default namespace href=http://www.w3.org/1999/xhtml
203 ELEMENT p
204 ELEMENT code
205 ELEMENT math
default namespace href=http://www.w3.org/1998/Math/MathML
...
345 ELEMENT mo
346 ELEMENT mn
/ > bye
目标是将包含namespace 的行加入上一行,将n ELEMENT name 显示为n name,忽略其余部分(并向xmllint 发送更多命令)。
以下命令给出正确的行预计会出现在以前的子shell
(echo 'xpath //*' )| xmllint --shell $proj/git/xml2xpath/tests/resources/html5.html | \
sed -nEe '{ :a; $!N;s/^([0-9]{1,5}) *ELEMENT *([^ ]*)\n +(default)? ?namespace ([a-z]+)? ?href=([^=]+)/\1 \2 \3\4=\5/;ta; s/^([0-9]{1,5}) *ELEMENT *([^ ]*)/\1 \2/; /^[1-9]/ P;D }'
1 html default=http://www.w3.org/1999/xhtml
2 head
3 title
4 link
5 link
6 link
7 link
8 body
9 h1
10 h2
...
问题
通过文件描述符将行发送回子外壳不会正确连接行,namespace 信息出现在 arrns 数组内的自己的项目上(下一个代码示例)。
因此,从文件描述符中读取并使用sed 处理以填充数组无法按预期工作。此外,在此阶段尽量避免对文件进行超过 1 次的后处理或解析。
目前最好的方法是:
#!/bin/bash
wget --no-clobber "https://www.w3.org/TR/XHTMLplusMathMLplusSVG/sample.xhtml" -O html5.html
fname='xff'
[ ! -p "$fname" ] && mkfifo "$fname"
exec 3<>"$fname"
cat /dev/null > tmp.log
stop='dir xxxxxxx'
function parse_line(){
while read -r -u 3 xline; do
printf "%s\n" "$xline"
if [ "$xline" == "/ > $stop" ]; then
break
fi
done | sed -nEe '{ :a; $!N;s/^([0-9]{1,5}) *ELEMENT *([^ ]*)\n +(default)? ?namespace ([a-z]+)? ?href=([^=]+)/\1 \2 \3\4=\5/;ta; s/^([0-9]{1,5}) *ELEMENT *([^ ]*)/\1 \2/; /^[1-9]|namespace/ P;D }'
}
(
echo 'xpath //*'
echo "$stop"
IFS=$'\n' read -r -d '' -a arrns < <(parse_line && printf '\0')
# print to file temporarily for debugging and avoid sending to xmllint shell
printf "%s\n" "${arrns[@]}" >> tmp.log
echo "OUT OF LOOP 1 ${#arrns[@]}" >> tmp.log
echo "bye"
) | xmllint --shell html5.html >&3
exec 3>&-
rm xff
cat tmp.log
将 fd 3 中的所有行解析为一个变量,然后应用 sed 得到相同的结果。
在tmp.log 上显示arrns 的内容(几乎正确):
1 html
default namespace href=http://www.w3.org/1999/xhtml
2 head
3 title
4 link
5 link
...
239 math
default namespace href=http://www.w3.org/1998/Math/MathML
...
OUT OF LOOP 1 354
示例中的第 1 行和第 239 行应该是这样的
239 math default=http://www.w3.org/1998/Math/MathML
这可能允许通过一些处理将此命令从同一子 shell 转发到 xmllint,以设置它们在文档中出现的命名空间。
setns default=http://www.w3.org/1998/Math/MathML
【问题讨论】:
-
您的问题到底是什么? MCVE 肯定会有所帮助。
-
@RenaudPacalet 谢谢,感谢您的评论。包含
namespace的行未连接到前一行。另一方面,问题解释了问题并提供了重现的代码。对某些人来说可能不是最低要求,但它肯定是完整且可重现的。
标签: bash sed file-descriptor xmllint