从简单的 XML 文件中提取数据
Posted
技术标签:
【中文标题】从简单的 XML 文件中提取数据【英文标题】:Extraction of data from a simple XML file 【发布时间】:2011-01-14 09:29:33 【问题描述】:我有一个包含内容的 XML 文件:
<?xml version="1.0" encoding="utf-8"?>
<job xmlns="http://www.sample.com/">programming</job>
我需要一种方法来提取 <job..>
</job>
标记中的内容,在这种情况下为 programmin。这应该在 linux 命令提示符下使用 grep/sed/awk 完成。
【问题讨论】:
如果你的 XML 文件包含这个:s/&amp;/\&/g
,&quot;
等也一样,当然它不会推广到用户定义的实体等。
https://***.com/a/17333829/3291390
【参考方案1】:
您真的必须只使用这些工具吗?它们不是为 XML 处理而设计的,虽然在大多数情况下可以获得可以正常工作的东西,但在编码、换行等边缘情况下会失败。
我推荐xml_grep:
xml_grep 'job' jobs.xml --text_only
它给出了输出:
programming
在 ubuntu/debian 上,xml_grep 位于 xml-twig-tools 包中。
【讨论】:
严格的安装说明非常适合 xml_grep sudo apt-get install xml-twig-tools "grep" 只是无痛文本搜索的同义词。【参考方案2】: grep '<job' file_name | cut -f2 -d">"|cut -f1 -d"<"
【讨论】:
只有标签在不同的行时才会失败 格式良好的 XML 可以通过十几种其他方式使其失败。【参考方案3】:使用 xmlstarlet:
echo '<job xmlns="http://www.sample.com/">programming</job>' | \
xmlstarlet sel -N var="http://www.sample.com/" -t -m "//var:job" -v '.'
【讨论】:
有大量不同的工具使用标准 XPath 表示法从 XML 中提取信息——xmlstarlet
只是其中之一。其他包括xmllint
、xpath
等。见***.com/questions/15461737/…【参考方案4】:
请不要在 XML 上使用基于行和正则表达式的解析。这是个坏主意。您可以使用不同格式的语义相同的 XML,而正则表达式和基于行的解析根本无法处理它。
一元标签和可变换行之类的东西——这些 sn-ps '说'同样的东西:
<root>
<sometag val1="fish" val2="carrot" val3="narf"></sometag>
</root>
<root>
<sometag
val1="fish"
val2="carrot"
val3="narf"></sometag>
</root>
<root
><sometag
val1="fish"
val2="carrot"
val3="narf"
></sometag></root>
<root><sometag val1="fish" val2="carrot" val3="narf"/></root>
希望这能说明为什么制作基于正则表达式/行的解析器很困难?幸运的是,您不需要这样做。许多脚本语言至少有一个,有时更多的解析器选项。
正如之前的海报所暗示的 - xml_grep
可用。这实际上是一个基于XML::Twig
perl 库的工具。然而,它的作用是使用“xpath 表达式”来查找某些内容,并区分文档结构、属性和“内容”。
例如:
xml_grep 'job' jobs.xml --text_only
但是,为了获得更好的答案,这里有几个根据您的源数据“自己动手”的示例:
第一种方式:
使用twig handlers
捕获特定类型的元素并对其进行操作。这样做的好处是它可以“随时”解析 XML,并让您在需要时随时修改它。当您使用purge
或flush
处理大文件时,这对于丢弃“处理过的”XML 特别有用:
#!/usr/bin/perl
use strict;
use warnings;
use XML::Twig;
XML::Twig->new(
twig_handlers =>
'job' => sub print $_ ->text
)->parse( <> );
它将使用<>
获取输入(通过管道输入或通过命令行./myscript somefile.xml
指定)并处理它 - 每个job
元素,它将提取并打印任何相关的文本。 (您可能希望 print $_ -> text,"\n"
插入换行符)。
因为它匹配 'job' 元素,所以它也会匹配嵌套的 job 元素:
<job>programming
<job>anotherjob</job>
</job>
将匹配两次,但也会将某些输出打印两次。但是,如果您愿意,可以改为匹配 /job
。有用 - 这让你例如打印和删除一个元素或复制并粘贴一个修改 XML 结构的元素。
或者 - 先解析,然后根据结构“打印”:
my $twig = XML::Twig->new( )->parse( <> );
print $twig -> root -> text;
由于job
是您的根元素,我们需要做的就是打印它的文本。
但我们可以更挑剔一点,寻找job
或/job
并专门打印出来:
my $twig = XML::Twig->new( )->parse( <> );
print $twig -> findnodes('/job',0)->text;
您也可以使用 XML::Twig
s pretty_print
选项重新格式化您的 XML:
XML::Twig->new( 'pretty_print' => 'indented_a' )->parse( <> ) -> print;
有多种输出格式选项,但对于更简单的 XML(如您的),大多数看起来都非常相似。
【讨论】:
【参考方案5】:只需使用 awk,无需其他外部工具。如果您想要的标签出现在 multitine 中,则以下工作。
$ cat file
test
<job xmlns="http://www.sample.com/">programming</job>
<job xmlns="http://www.sample.com/">
programming</job>
$ awk -vRS="</job>" 'gsub(/.*<job.*>/,"");print' file
programming
programming
【讨论】:
</ job>
有效,但您的脚本无法识别它。 <!-- </job> -->
是需要忽略的注释(<!CDATA[[ </job> ]]>
是文字数据),但您的脚本不知道 。还有一些情况,比如有一个定义新宏的 DTD,这样&foo;
会扩展为本地指定的东西,还有一些简单的情况,比如需要将&amp;
转换为&
。尝试滚动您自己的 XML 解析(或更糟糕的是,生成)会导致无休止的极端情况和需要单独运行和修复的小细节。【参考方案6】:
使用 sed 命令:
例子:
$ cat file.xml
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
$ cat file.xml | sed -ne '/<heading>/s#\s*<[^>]*>\s*##gp'
Reminder
说明:
cat file.xml | sed -ne '/<pattern_to_find>/s#\s*<[^>]*>\s*##gp'
n
- 禁止打印所有行e
- 脚本
/<pattern_to_find>/
- 查找包含指定模式的行,例如<heading>
接下来是替换部分 s///p
,它删除了除所需值之外的所有内容,其中 /
被替换为 #
以提高可读性:
s#\s*<[^>]*>\s*##gp
\s*
- 如果存在则包括空格(最后相同)<[^>]*>
表示 <xml_tag>
作为非贪婪正则表达式替代原因 <.*?>
不适用于 sed
g - 替换所有内容,例如关闭 xml </xml_tag>
标签
【讨论】:
【参考方案7】:假设同一行,从标准输入输入:
sed -ne '/<\/job>/ s/<[^>]*>\(.*\)<\/job>/\1/; p '
注意:-n
停止它自动输出所有内容; -e
表示它是一个单行(aot 脚本)/<\/job>
就像一个 grep; s
去掉 opentag + 属性和 endtag; ;
是一个新的声明; p
打印; 使 grep 应用于两个语句,作为一个。
【讨论】:
【参考方案8】:怎么样:
cat a.xml | grep '<job' | cut -d '>' -f 2 | cut -d '<' -f 1
【讨论】:
UUOC。grep '<job' a.xml | ...
@ghost 但是但是,我认为它更清洁/更好/没有那么多浪费/我有特权浪费过程! partmaps.org/era/unix/award.html#cat(实际上,我认为它是更容易编辑文件名,因为更接近开始)
如果你使用< a.xml | grep ...
,你会更接近开始。【参考方案9】:
演出有点晚了。
xmlcutty 从 XML 中删除节点:
$ cat file.xml
<?xml version="1.0" encoding="utf-8"?>
<job xmlns="http://www.sample.com/">programming</job>
<job xmlns="http://www.sample.com/">designing</job>
<job xmlns="http://www.sample.com/">managing</job>
<job xmlns="http://www.sample.com/">teaching</job>
path
参数指定要剪切的元素的路径。在这种情况下,由于我们对标签根本不感兴趣,我们将标签重命名为\n
,所以我们得到了一个不错的列表:
$ xmlcutty -path /job -rename '\n' file.xml
programming
designing
managing
teaching
请注意,XML 开头无效(无根元素)。 xmlcutty 也可以处理稍微损坏的 XML。
【讨论】:
【参考方案10】:你的xml文件.xml
<item>
<title>15:54:57 - George:</title>
<description>Diane DeConn? You saw Diane DeConn!</description>
</item>
<item>
<title>15:55:17 - Jerry:</title>
<description>Something huh?</description>
</item>
grep 'title' yourxmlfile.xml
<title>15:54:57 - George:</title>
<title>15:55:17 - Jerry:</title>
grep 'title' yourxmlfile.xml | awk -F">" '打印 $2'
15:54:57 - George:</title
15:55:17 - Jerry:</title
grep 'title' yourxmlfile.xml | awk -F">" '打印 $2' | awk -F"
15:54:57 - George:
15:55:17 - Jerry:
【讨论】:
以上是关于从简单的 XML 文件中提取数据的主要内容,如果未能解决你的问题,请参考以下文章
Jquery datatable 在从简单的 Web 服务调用 Web 方法时未在表中显示任何数据