从 xml 文件中提取字段
Extract field from xml file
xml 文件:
<head>
<head2>
<dict type="abc" file="/path/to/file1"></dict>
<dict type="xyz" file="/path/to/file2"></dict>
</head2>
</head>
我需要从中提取文件列表。所以输出将是
/path/to/file1
/path/to/file2
到目前为止,我已经做到了以下几点。
grep "<dict*file=" /path/to/xml.file | awk '{print }' | awk -F= '{print $NF}'
根据您的示例快速而肮脏,而不是 xml 可能性
# sed a bit secure
sed -e '/<head>/,/<\/head>/!d' -e '/.*[[:blank:]]file="\([^"]*\)".*/!d' -e 's///' YourFile
# sed in brute force
sed -n 's/.*[[:blank:]]file="\([^"]*\)".*//p' -e 's///' YourFile
# awk quick unsecure using your sample
awk -F 'file="|">' '/<head>/{h=1} /\/head>{h=0} h && /[[:blank:]]file/ { print }' YourFile
现在,我不会在 XML 上推广这种提取,除非你真的知道你的来源在格式和内容方面如何(额外字段、转义引号、字符串内容如标签格式、.. .) 是失败和意外结果的重要原因,没有更合适的工具可用
现在使用您自己的脚本
#grep "<dict*file=" /path/to/xml.file | awk '{print }' | awk -F= '{print $NF}'
awk '! /<dict.*file=/ {next} {[=11=]=;FS="\"";[=11=]=[=11=];print ;FS=OFS}' YourFile
- 不需要 grep 和 awk,使用起始模式过滤器
/<dict.*file/
- 使用不同分隔符 (FS) 的第二个 awk 可以在更改 FS 的同一脚本中完成,但因为它只发生在下一次评估时(默认情况下为下一行),您可以使用 $0= 强制重新评估当前内容在这种情况下 $0
使用 xmllint
解决方案 -xpath
作为 //head/head2/dict/@file
xmllint --xpath "//head/head2/dict/@file" input-xml | awk 'BEGIN{FS="file="}{printf "%s\n%s\n", gensub(/"/,"","g",), gensub(/"/,"","g",)}'
/path/to/file1
/path/to/file2
遗憾的是无法提供纯粹的xmllint
逻辑,因为思想应用,
xmllint --xpath "string(//head/head2/dict/@file)" input-xml
将 return 来自两个节点的 file
属性,但它只是 return 第一个实例。
所以添加了我的逻辑与 GNU Awk
,以提取所需的值,做
xmllint --xpath "//head/head2/dict/@file" input-xml
returns 值为
file="/path/to/file1" file="/path/to/file2"
在上面的输出中,将字符串 de-limiter 设置为 file=
并使用 gensub()
函数删除 double-quotes 解决了要求。
还有PE [perl e无处不在:)]解决方案:
perl -MXML::LibXML -E 'say $_->to_literal for XML::LibXML->load_xml(location=>q{file.xml})->findnodes(q{/head/head2/dict/@file})'
它打印
/path/to/file1
/path/to/file2
对于以上内容,您需要安装 XML::LibXML 模块。
对于 xmlstarlet
它将是:
xmlstarlet sel -t -v "//head/head2/dict/@file" -nl input.xml
这个命令:
awk -F'[=" ">]' '{print }' file
将产生:
/path/to/file1
/path/to/file2
xml 文件:
<head>
<head2>
<dict type="abc" file="/path/to/file1"></dict>
<dict type="xyz" file="/path/to/file2"></dict>
</head2>
</head>
我需要从中提取文件列表。所以输出将是
/path/to/file1
/path/to/file2
到目前为止,我已经做到了以下几点。
grep "<dict*file=" /path/to/xml.file | awk '{print }' | awk -F= '{print $NF}'
根据您的示例快速而肮脏,而不是 xml 可能性
# sed a bit secure
sed -e '/<head>/,/<\/head>/!d' -e '/.*[[:blank:]]file="\([^"]*\)".*/!d' -e 's///' YourFile
# sed in brute force
sed -n 's/.*[[:blank:]]file="\([^"]*\)".*//p' -e 's///' YourFile
# awk quick unsecure using your sample
awk -F 'file="|">' '/<head>/{h=1} /\/head>{h=0} h && /[[:blank:]]file/ { print }' YourFile
现在,我不会在 XML 上推广这种提取,除非你真的知道你的来源在格式和内容方面如何(额外字段、转义引号、字符串内容如标签格式、.. .) 是失败和意外结果的重要原因,没有更合适的工具可用
现在使用您自己的脚本
#grep "<dict*file=" /path/to/xml.file | awk '{print }' | awk -F= '{print $NF}'
awk '! /<dict.*file=/ {next} {[=11=]=;FS="\"";[=11=]=[=11=];print ;FS=OFS}' YourFile
- 不需要 grep 和 awk,使用起始模式过滤器
/<dict.*file/
- 使用不同分隔符 (FS) 的第二个 awk 可以在更改 FS 的同一脚本中完成,但因为它只发生在下一次评估时(默认情况下为下一行),您可以使用 $0= 强制重新评估当前内容在这种情况下 $0
使用 xmllint
解决方案 -xpath
作为 //head/head2/dict/@file
xmllint --xpath "//head/head2/dict/@file" input-xml | awk 'BEGIN{FS="file="}{printf "%s\n%s\n", gensub(/"/,"","g",), gensub(/"/,"","g",)}'
/path/to/file1
/path/to/file2
遗憾的是无法提供纯粹的xmllint
逻辑,因为思想应用,
xmllint --xpath "string(//head/head2/dict/@file)" input-xml
将 return 来自两个节点的 file
属性,但它只是 return 第一个实例。
所以添加了我的逻辑与 GNU Awk
,以提取所需的值,做
xmllint --xpath "//head/head2/dict/@file" input-xml
returns 值为
file="/path/to/file1" file="/path/to/file2"
在上面的输出中,将字符串 de-limiter 设置为 file=
并使用 gensub()
函数删除 double-quotes 解决了要求。
还有PE [perl e无处不在:)]解决方案:
perl -MXML::LibXML -E 'say $_->to_literal for XML::LibXML->load_xml(location=>q{file.xml})->findnodes(q{/head/head2/dict/@file})'
它打印
/path/to/file1
/path/to/file2
对于以上内容,您需要安装 XML::LibXML 模块。
对于 xmlstarlet
它将是:
xmlstarlet sel -t -v "//head/head2/dict/@file" -nl input.xml
这个命令:
awk -F'[=" ">]' '{print }' file
将产生:
/path/to/file1
/path/to/file2