使用 Shell 从 KML 中提取海平面压力

使用 Shell 从 KML 中提取海平面压力

我目前正在做一个小项目;在一个名为weatherdata.kml的kml文件中,我想提取每个<Placemark>元素的海平面压力。我正在尝试解析有关海平面压力的信息并将其放入名为report.csv;的文件中。并每次在新行上打印海平面压力。

我认为这会起作用awk,到目前为止我已经尝试过:

 awk -F '[>,]' '/minSeaLevelPres/ {print $2}' report.csv

但是当我在 shell 中运行此命令时,我得到以下信息:

1002</minSeaLevelPres
1002</minSeaLevelPres
1002</minSeaLevelPres
1001</minSeaLevelPres
1001</minSeaLevelPres
1001</minSeaLevelPres
1001</minSeaLevelPres
1001</minSeaLevelPres
1001</minSeaLevelPres
1001</minSeaLevelPres
1001</minSeaLevelPres
1002</minSeaLevelPres
1002</minSeaLevelPres
1003</minSeaLevelPres

当我想得到这个时:

1002
1002
1002
1001
1001
1001
1001
1001
1001
1001
1001
1002
1002
1003

我不知道如何摆脱</minSeaLevelPres。有人可以帮忙吗?

下面是地标元素的一部分的示例weatherdata.kml

 <Placemark>
        <styleUrl>#ex</styleUrl>
        <lat>19.2</lat>
        <lon>-24.1</lon>
        <stormName>NINE</stormName>
    <stormNum>10</stormNum>
    <basin>AL</basin>
        <stormType>LO</stormType>
        <intensity>20</intensity>
           <intensityMPH>23</intensityMPH>
           <intensityKPH>37</intensityKPH>
           <minSeaLevelPres>1002</minSeaLevelPres>
           <atcfdtg>2020082350</atcfdtg>
        <dtg>0000 UTC JAN 07</dtg>
       </Placemark>

答案1

我建议使用一个可以正确处理XML的工具:

xmlstarlet select --template --value-of '//minSeaLevelPres' -n weatherdata.kml

输出:

1002

看:xmlstarlet select --help

答案2

KML 是一种 XML 语言。 XML 不是一种可以可靠解析的语言awk。您可能对您拥有的文件很幸运 - 它们的结构可能比语言定义允许的更可靠 - 但是当您得到一个可以使用不同工具始终工作的文件时,根本没有理由在 AWK 中编写您自己的受限解析器。例如,当删除或添加换行符、注释时,您的内容就会损坏。

我认为您只是想使用错误的工具。正如您awk在系统上安装的那样python,您可能已经安装了 XML 解析器,并且除了 Python 的标准库之外无需任何外部代码,就可以编写一个非常小的程序来写入 CSV。 (记住,UNIX 哲学不是“你有一把锤子,现在一切都是钉子”,而是“你有用于不同目的的工具,为你的目的找到正确的工具”)。

import sys
import xml.etree.ElementTree as ElemTree

fname = sys.argv[1]
tree = ElemTree.parse(fname)
for placemark in tree.getroot().iter("Placemark"):
    print(placemark.find("minSeaLevelPres").text)

就是这样。保存到文件,赋予文件执行权限(chmod o+x {filename}),然后就可以运行了/path/to/filename input.kml

一般说明:

因为weatherdata.kml是一个很大的文件,

我不知道什么对你来说是“大”,但如果你最终编写了一个包含数百万行的 CSV,那么你将无法获得非常有效的数据表示。找出该数据的使用者支持哪些二进制格式,然后直接写入。很可能有一个 Python 库可以实现这一点。

答案3

与其他人一样,我不建议这样做,awk因为您正在使用 XML。但是,如果您出于某种原因想使用它,并且您的文件被格式化为可以工作或更好的格式awk,如果它是纯文本文件,那么我只会准确地说明为什么您有这个命令在你的问题中不起作用:

您的命令具有字段分隔符,如>,所示[>,]

awk -F '[>,]' '/minSeaLevelPres/ {print $2}' report.csv

这意味着第二个字段是文件中这两个字符中的任何一个的第一个实例之后的内容,>并且在包含字符串的行上minSeaLevelPres{print $2}将准确地给出您所得到的内容:

1002</minSeaLevelPres>

在这种特定情况下,如果您只想1002从您提供的示例文本中获取内容,那么您需要的是这个

awk -F '[><]' '/minSeaLevelPres/ {print $3}' weatherdata.kml

这会将字段分隔符设置为>or <,这将使得1002只有1002第三个字段将从上面的命令中打印出来并给出您想要的:

1002

再说一次,我不建议在 XML 上使用awk,或者为了论证的缘故,在 HTML 文件上使用,但我只是提供这个答案来说明为什么你的命令不起作用,以及如果出现以下情况你将如何让它工作:您正在操作纯文本文件。awk以后使用的时候可以参考一下。

答案4

使用(以前称为 Perl_6)

~$ raku -MXML -e 'my $xml=open-xml($*ARGFILES.Str); 
        .put for $xml.lookfor(:TAG<minSeaLevelPres>)>>.[0];' weatherdata.kml

上面是用 Raku(Perl 编程语言家族的成员)编写的答案。您可以XML使用命令行标志在命令行加载 Raku模块-MXML。然后使用lookfor(递归元素搜索)命令解析 XML 。在最后一步中,>>.[0].map(*.[0])映射到标签,仅返回其中包含的值。

请注意,不清楚您的weatherdata.kml文件实际上是什么样子,无论它是否具有简单、浮动和/或挤压地标中的一项或全部。上面的命令只是:TAG<minSeaLevelPres>递归地查找,每行输出一个值。

输入示例,请参阅:

https://developers.google.com/kml/documentation/KML_Samples.kml

示例输出(将TAG上面更改为:TAG<tessellate>测试):

1
0
1
1
1
1
1
1
1
1

https://github.com/raku-community-modules/XML
https://raku.org/

相关内容