Abh*_*i S 3 xml sed awk text-processing ctags
给定一个特定的 XML 元素(即特定的标记名称)和一段 XML 数据,我想从该元素的每次出现中提取子元素。更具体地说,我有以下(不太有效的)XML 数据片段:
<!-- data.xml -->
<instance ab=1 >
<a1>aa</a1>
<a2>aa</a2>
</instance>
<instance ab=2 >
<b1>bb</b1>
<b2>bb</b2>
</instance>
<instance ab=3 >
<c1>cc</c1>
<c2>cc</c2>
</instance>
Run Code Online (Sandbox Code Playgroud)
我想要一个脚本或命令,它将这些数据作为输入并产生以下输出:
<a1>aa</a1><a2>aa</a2>
<b1>bb</b1><b2>bb</b2>
<c1>cc</c1><c2>cc</c2>
Run Code Online (Sandbox Code Playgroud)
我希望解决方案使用标准文本处理工具,例如sed
或awk
。
我尝试使用以下sed
命令,但没有奏效:
sed -n '/<Sample/,/<\/Sample/p' data.xml
Run Code Online (Sandbox Code Playgroud)
如果您真的想要对 XML 文件进行sed
- 或 -awk
类似的命令行处理,那么您可能应该考虑使用 XML 处理命令行工具。以下是我见过的一些更常用的工具:
您还应该知道有几种特定于 XML 的编程/查询语言:
请注意(为了成为有效的 XML)您的 XML 数据需要一个根节点并且您的属性值应该被引用,即您的数据文件应该看起来更像这样:
<!-- data.xml -->
<instances>
<instance ab='1'>
<a1>aa</a1>
<a2>aa</a2>
</instance>
<instance ab='2'>
<b1>bb</b1>
<b2>bb</b2>
</instance>
<instance ab='3'>
<c1>cc</c1>
<c2>cc</c2>
</instance>
</instances>
Run Code Online (Sandbox Code Playgroud)
如果您的数据被格式化为有效的 XML,那么您可以使用XPath和xmlstarlet来通过一个非常简洁的命令来获得您想要的内容:
xmlstarlet sel -t -m '//instance' -c "./*" -n data.xml
Run Code Online (Sandbox Code Playgroud)
这会产生以下输出:
<a1>aa</a1><a2>aa</a2>
<b1>bb</b1><b2>bb</b2>
<c1>cc</c1><c2>cc</c2>
Run Code Online (Sandbox Code Playgroud)
或者你可以使用 Python(我个人最喜欢的选择)。这是一个完成相同任务的 Python 脚本:
<!-- data.xml -->
<instances>
<instance ab='1'>
<a1>aa</a1>
<a2>aa</a2>
</instance>
<instance ab='2'>
<b1>bb</b1>
<b2>bb</b2>
</instance>
<instance ab='3'>
<c1>cc</c1>
<c2>cc</c2>
</instance>
</instances>
Run Code Online (Sandbox Code Playgroud)
以下是运行脚本的方法:
xmlstarlet sel -t -m '//instance' -c "./*" -n data.xml
Run Code Online (Sandbox Code Playgroud)
这使用了Python 标准库中的xml 包,它也是一个严格的 XML 解析器。
如果您不关心正确格式化的 XML,而只想解析一个与您所提供的文件大致相似的文本文件,那么您绝对可以仅使用 shell 脚本和标准命令行工具来完成您想要的. 这是一个awk
脚本(根据要求):
<a1>aa</a1><a2>aa</a2>
<b1>bb</b1><b2>bb</b2>
<c1>cc</c1><c2>cc</c2>
Run Code Online (Sandbox Code Playgroud)
要从文件执行脚本,您可以使用如下命令:
#!/usr/bin/env python2
# -*- encoding: ascii -*-
"""extract_instance_children.bash"""
import sys
import xml.etree.ElementTree
# Load the data
tree = xml.etree.ElementTree.parse(sys.argv[1])
root = tree.getroot()
# Extract and output the child elements
for instance in root.iter("instance"):
print(''.join([xml.etree.ElementTree.tostring(child).strip() for child in instance]))
Run Code Online (Sandbox Code Playgroud)
这是一个生成所需输出的 Bash 脚本:
python extract_instance_children.py data.xml
Run Code Online (Sandbox Code Playgroud)
你会像这样执行它:
#!/usr/bin/env awk
# extract_instance_children.awk
BEGIN {
addchild=0;
children="";
}
{
# Opening tag for "instance" element - set the "addchild" flag
if($0 ~ "^ *<instance[^<>]+>") {
addchild=1;
}
# Closing tag for "instance" element - reset "children" string and "addchild" flag, print children
else if($0 ~ "^ *</instance>" && addchild == 1) {
addchild=0;
printf("%s\n", children);
children="";
}
# Concatenating child elements - strip whitespace
else if (addchild == 1) {
gsub(/^[ \t]+/,"",$0);
gsub(/[ \t]+$/,"",$0);
children=children $0;
}
}
Run Code Online (Sandbox Code Playgroud)
或者,再次回到 Python,您可以使用Beautiful Soup包。Beautiful Soup 在解析无效 XML 的能力方面比标准 Python XML 模块(以及我遇到的所有其他 XML 解析器)灵活得多。这是一个使用 Beautiful Soup 实现预期结果的 Python 脚本:
awk -f extract_instance_children.awk data.xml
Run Code Online (Sandbox Code Playgroud)