我正在尝试获取一个命令,根据xml文件中的标记数量提取多个字符串。我有这样的文件结构:
<task id="0">
some stuff
</task>
<task id="1">
some other stuff
</task>
<task>
标签的数量创建多个字符串?我的意思是,当我以id =“0”开始时,它会以正确的</task>
标记还是文件中的最后一个标记结束?答案 0 :(得分:2)
我建议不要使用面向行的工具来处理xml内容,例如grep
/ sed
/ awk
等.Xml 不是面向行的格式;因此,当文本表示时,跨行的xml元素的特定分布是偶然的。 (您可以将您的示例写在一行中,但仍然是同样正确的xml格式。)
我建议在shell脚本中解析格式良好的 xml内容是xmlstarlet
工具。它是一种瑞士军刀,用于以可编写脚本的方式处理xml。
首先,确保您的xml内容为well formed。以下是包含示例数据的格式良好的xml:
<?xml version="1.0" encoding="UTF-8"?>
<tasks>
<task id="0">some stuff</task>
<task id="1">some other stuff</task>
<task id="2">yet another stuff</task>
</tasks>
(可以使用xmlstarlet val
检查&#34;格式良好&#34; xml文件。)
要从xml中提取内容,请使用xmlstarlet sel
。此工具需要XPath表达式,用于过滤必须选择的内容。 (在大多数情况下,xmlstarlet sel
和Xpath适用于xml grep
和正则表达式适用于面向行的内容。)
使用保存在文件tasks.xml
中的上述xml示例的示例:
提取所有任务的内容
$ xmlstarlet sel -T -t -m '/tasks/task' -v '.' -n tasks.xml
some stuff
some other stuff
yet another stuff
获取所有任务ID
$ xmlstarlet sel -T -t -m '/tasks/task' -v '@id' -n tasks.xml
0
1
2
提取任务0的内容
$ xmlstarlet sel -T -t -m '/tasks/task[@id="0"]' -v '.' -n tasks.xml
some stuff
提取id大于或等于1
的所有任务的内容$ xmlstarlet sel -T -t -m '/tasks/task[@id>="1"]' -v '.' -n tasks.xml
some other stuff
yet another stuff
天真转换为cvs格式
$ xmlstarlet sel -T -t -m '/tasks/task' -v '@id' -o ',' -v '.' -n tasks.xml
0,some stuff
1,some other stuff
2,yet another stuff
答案 1 :(得分:1)
在GNU sed上:
sed -n '/<task id=/{n;:a;p;n;/<\/task>/!ba;s/.*/---/p;}' filename
将输出:
some stuff
---
some other stuff
---
这将搜索文件中的每个<task id=
并迭代直到下一个</task>
。 s/.*/---/p;
部分将结束标记转换为分隔符,您可以将其删除并连接所有字符串。
答案 2 :(得分:1)
我为这样的事情做了HTML/XML pattern matcher。
例如,您可以执行第一项任务:
$ xidel /tmp/xxx.xml -e '<task id="0">{.}</task>'
some stuff
或者对于所有任务:
$ xidel /tmp/xxx.xml -e '<task>{.}</task>+'
some stuff
some other stuff
虽然在你的情况下只有一个元素,但使用XPath更简单:
获得第一项任务:
$ xidel /tmp/xxx.xml -e //task[@id=0]
some stuff
获取所有任务内容:
$ xidel /tmp/xxx.xml -e //task
some stuff
some other stuff
答案 3 :(得分:0)
这可以通过很多方式完成。在我看来,最简单的方法是awk。把它放在一个名为task.awk的文件中:
BEGIN{x=0;}
/^<\/task>/{x=0;}
{if(x==1)print $0;}
/^<task [^>]*>/{x=1;}
然后,如果你的xml在task.xml中,你可以:
awk -f task.awk < task.xml
工作原理:
答案 4 :(得分:0)
将此文件作为/tmp/data.xml
中的来源:
<task id="0">
some1 stuff for id 0
some2 stuff for id 0
</task>
<task id="1">
some1 stuff for id 1
some2 stuff for id 1
</task>
此代码:
awk '
/<task id=/{tag_data=$0}
/<\/task>/{tag_data=tag_data $0 " "; print tag_data}
{tag_data=tag_data $0 " "}' < /tmp/data
产生所需的结果:
<task id="0"><task id="0"> some1 stuff for id 0 some2 stuff for id 0 </task>
<task id="1"><task id="1"> some1 stuff for id 1 some2 stuff for id 1 </task>
它执行以下操作:
它搜索第一个开始标记,并开始在变量tag_data
中累积数据,直到它包含closinig标记。在结束标记处,您可以在tag_data
变量中的开始和结束标记之间获得所有需要的数据。您可以轻松修改代码以不存储标记,甚至可以将id解析并存储在单独的变量中。