<wpt lat="1.345529841" lon="103.7577152"><time>2010-01-01T00:00:00Z</time</wpt>
<wpt lat="1.345529841" lon="103.7577152"><time>2010-01-01T00:00:00Z</time></wpt>
<wpt lat="1.3982529841" lon="103.90877152"><time>2010-01-01T00:00:00Z</time></wpt>
上記の行を次に変換する必要があるファイルがあります。
1.345529841,103.7577152,2010-01-01 00:00:00
1.345529841,103.7577152,2010-01-01 00:00:00
1.3982529841,103.90877152,2010-01-01 00:00:00
答え1
GPXはXML形式です。awk
そのため、安定して使用したりsed
解析することはできません。
代わりに、次のようなものを使用してください。XMLスター(XML文書の形式が正しくエラーがないと仮定):
$ xmlstarlet sel -t -m '//wpt' \
-v '@lat' -o ',' \
-v '@lon' -o ',' \
-v 'time' -nl data.gpx
1.345529841,103.7577152,2010-01-01T00:00:00Z
1.345529841,103.7577152,2010-01-01T00:00:00Z
1.3982529841,103.90877152,2010-01-01T00:00:00Z
または:
xmlstarlet sel -t -m '//wpt' -v 'concat(@lat, ",", @lon, ",", time)' -nl data.wpx
以下を使用することもできますxq
(部分的yq
にhttps://kislyuk.github.io/yq/):
$ xq -r '.. | .wpt? // empty | .[] | map(values) | @csv' data.gpx
"1.345529841","103.7577152","2010-01-01T00:00:00Z"
"1.345529841","103.7577152","2010-01-01T00:00:00Z"
"1.3982529841","103.90877152","2010-01-01T00:00:00Z"
その後、すべてのノードを見つけ、wpt
すべての属性と子ノードの値を抽出し、それからCSV出力を生成します。
列を並べ替える必要がある場合、または各列に使用する値を選択する必要がある場合でも、これを行うことができます。
$ xq -r '.. | .wpt? // empty | .[] | [."@lat", ."@lon", .time] | @csv' data.gpx
"1.345529841","103.7577152","2010-01-01T00:00:00Z"
"1.345529841","103.7577152","2010-01-01T00:00:00Z"
"1.3982529841","103.90877152","2010-01-01T00:00:00Z"
答え2
してください -awk
などの正規表現ベースのソリューションを使用しないでくださいsed
。
XML
状況によって異なりますが、正規表現はそうではありません。そのため、うまく動作しないので、せいぜいいくつかのハッキングだけです。。
ただし、XMLにはこの問題に対する解決策があります。これxpath
により、状況に応じて「検索」できます。
あなたの例を見てください:
#!/usr/bin/perl
use warnings;
use strict;
use XML::Twig;
my $xml = XML::Twig -> new -> parsefile('your_file.xml');
foreach my $wpt ( $xml -> get_xpath('//wpt') ) {
print join ",", $wpt -> att('lat'),
$wpt -> att('lon'),
$wpt -> first_child_text('time'), "\n";
}
これは望ましい結果を提供しますが、完全に有効で意味的に同じさまざまな形式のXMLも処理します。
インデントと同様に:
<xml>
<wpt lat="1.345529841" lon="103.7577152">
<time>2010-01-01T00:00:00Z</time>
</wpt>
<wpt lat="1.345529841" lon="103.7577152">
<time>2010-01-01T00:00:00Z</time>
</wpt>
<wpt lat="1.3982529841" lon="103.90877152">
<time>2010-01-01T00:00:00Z</time>
</wpt>
</xml>
1行にすべて:
<xml><wpt lat="1.345529841" lon="103.7577152"><time>2010-01-01T00:00:00Z</time></wpt><wpt lat="1.345529841" lon="103.7577152"><time>2010-01-01T00:00:00Z</time></wpt><wpt lat="1.3982529841" lon="103.90877152"><time>2010-01-01T00:00:00Z</time></wpt></xml>
別のインデントスタイル:
<xml>
<wpt
lat="1.345529841"
lon="103.7577152">
<time>2010-01-01T00:00:00Z</time>
</wpt>
<wpt
lat="1.345529841"
lon="103.7577152">
<time>2010-01-01T00:00:00Z</time>
</wpt>
<wpt
lat="1.3982529841"
lon="103.90877152">
<time>2010-01-01T00:00:00Z</time>
</wpt>
</xml>
でも:
<xml
><wpt
lat="1.345529841"
lon="103.7577152"
><time
>2010-01-01T00:00:00Z</time></wpt><wpt
lat="1.345529841"
lon="103.7577152"
><time
>2010-01-01T00:00:00Z</time></wpt><wpt
lat="1.3982529841"
lon="103.90877152"
><time
>2010-01-01T00:00:00Z</time></wpt></xml>
これらは意味上すべて同じで、しなければならない同じ方法で解析します。これを行う正規表現は、XMLパーサーを使用するよりもはるかに複雑であることが誰にとっても明らかになることを願っています。
しかし、簡単に説明すると、次のようになります。
perl -MXML::Twig -0777 -e 'XML::Twig->new(twig_handlers=>{wpt=>sub{print join ",", $_->att("lat", $_->att("lon"),$_->first_child_text("time"), "\n" }})->parse(<>)'
答え3
以下を使用して、不要な文字を削除できますsed
。
sed 's/[^0-9.T:-]\+/,/g;s/T/ /;s/^,\|,$//g' file
s/[^0-9.T:-]\+/,/g
不要な文字をカンマに置き換える
s/T/ /
T
文字は空白に置き換えられます。
s/^,\|,$//g
最初と最後のカンマを削除
答え4
f.xml
入力(有効なxml)を想定すると、次のようになります。
$ perl -MXML::DT -E 'dt("f.xml",
time=>sub{$a=father;
$c =~ s/[TZ]/ /g;
say "$a->{lat},$a->{lon},$c"}
)'
-MXML::DT
XML :: DTモジュールのロード(xmlダウンコンバータ)dt( file, time => sub{....})
time
: ファイルを解析し、そのサブファイルが実行されるのを見るたびに$a=father
:父から属性を取得する$c
:現在の要素コンテンツです。
cpan XML::DT
警告:私はXML::DT(以下を使用してインストールされます)の作成者の一人です。