在XML标记之间提取多个值

时间:2017-07-25 16:35:39

标签: bash

我有一个来自Tripadvisor页面的XML文件,它显示了特定区域内的餐馆。

我想从搜索结果中提取所有餐厅提供的'美食'。所有值都存储在<a><span> HTML标记之间。

对于每家餐厅,数据存储在<div>标签之间,来自一家餐厅的美食片段如下所示:

<div class="cuisines">
<span class="item price">££ - £££</span>
<span class="item cuisine" onclick="ta.restaurant_list_tracking.clickNonLinkedCuisine()">Bar</span>
<a class="item cuisine" href="/Restaurants-g1096751-c7-Whittlebury_Northamptonshire_England.html" onclick="ta.setEvtCookie('RESTAURANT_DETAILS', 'RESTAURANTS_DETAILS_CUISINE', '', 0, this.href);">British</a>
<span class="item cuisine" onclick="ta.restaurant_list_tracking.clickNonLinkedCuisine()">Pub</span>
<span class="item cuisine" onclick="ta.restaurant_list_tracking.clickNonLinkedCuisine()">Gastropub</span>
<a class="item cuisine" href="/Restaurants-g1096751-zfz10665-Whittlebury_Northamptonshire_England.html" onclick="ta.setEvtCookie('RESTAURANT_DETAILS', 'RESTAURANTS_DETAILS_CUISINE', '', 0, this.href);">Vegetarian Friendly</a>
<a class="item cuisine" href="/Restaurants-g1096751-zfz10992-Whittlebury_Northamptonshire_England.html" onclick="ta.setEvtCookie('RESTAURANT_DETAILS', 'RESTAURANTS_DETAILS_CUISINE', '', 0, this.href);">Gluten Free Options</a>
</div>

如何在每个餐厅的这些div标签之间提取美食,然后将其输出到新的文本文件中?

我希望从该代码片段获得的预期输出是:

Bar, British, Pub, Gastropub, Vegetarian Friendly, Gluten Free Options

请注意,此XML文件中有多个<div>标记,我想要处理所有这些标记,将所有不同菜系的结果提取到一个文本文件中。每行显示每个<div>块的所有美食。

谢谢!

2 个答案:

答案 0 :(得分:0)

这是一个基本的bash脚本(使用awk)完成这项工作,至少对于你提供的例子:

#!/bin/bash    
cat in.xml | awk '
/item cuisine/ {item=gensub(/<[^>]*>/, "", "g"); 
    ans = (ans=="") ? item : ans ", " item;}
END {print ans}' > out.txt

该脚本会删除括号内的所有文本,并仅保留它们之间的文本,并且仅保留在包含&#34; item cuisine&#34;的行中。

但是,请注意,这是从XML文件中提取值的非常脆弱方式,或者就此而言,任何数据交换格式(如JSON,YAML)等等,并且可能因为十几种不同的原因而停止工作(错误的XML格式,包含&#34;项目菜单的XML行和#34;括号外的术语,不用新行分解的XML标记等)。

总是可以扩展上面的脚本并覆盖越来越多的错误,但是没有必要重新发明轮子,因为这已经以更好的方式完成了。像xmllintxgrep这样的工具提供了更强大的XML解析功能,让您只关注手头的任务而不是错误处理。

如果这不仅仅是一个快速的个人黑客/实验,我恳请您使用已有的工具之一。

答案 1 :(得分:0)

使用XMLStarlet,假设您的内容位于in.xml

# Generate an array of cuisines
cuisines=( )
while IFS= read -r cuisine; do
  cuisines+=( "$cuisine" )
done < <(xmlstarlet sel -t \
           -m '//div[@class="cuisines"]/*[@class="item cuisine"]' \
           -v . -n \
           <in.xml)

# Transform that into a string with a command and space after each item
printf -v cuisines_str '%s, ' "${cuisines[@]}"

# Remove the trailing ", " from that string on output
echo "${cuisines_str%, }"