大きなSMSメッセージXMLファイルがあります。簡単にアクセスできるcsv形式にしたいです。 「address」、「messageBody」、「messageTime」の部分を具体的に抽出しようとしましたが、成功しませんでした。
<messageType>1</messageType><messageTime>1624297248761</messageTime><read>null</read><status>null</status><service_center>null</service_center><person>null</person><seen>1</seen></chat><chat><threadID>50</threadID><address>447917504050</address><messageBody>Yeah mate let's do lunch and catch up.</messageBody><messageType>1</messageType><messageTime>1629944007697</messageTime><read>null</read><status>null</status><service_center>null</service_center><person>null</person><seen>1</seen></chat><chat><threadID>50</threadID><address>447917563330</address><messageBody>You going now mate</messageBody>
私は次のような小さな成功を収めました。
cat SMS.xml | awk -F'address' '{print $2}'
しかし、これは行の最初の「アドレス」だけを取得し、残りは無視します。
このデータを読み取り可能なcsv形式に変換する方法についてのアイデアはありますか?
「messageTime」セクションの数字を説明するのを手伝ってくれてありがとう。
編集:実際のxmlファイルにはバランスの取れたオープンタグとクローズタグがあり、フォーマットが正しく指定されています。ここではいくつかの内容を抜粋しました。
答え1
XMLの形式が正しく、すべてのノードがいくつかの単一ノードの下にchat
表示されると仮定すると、root
xq
yq
https://kislyuk.github.io/yq/):
xq -r '["address","messageBody","messageTime"], (.root.chat[] | [.address,.messageBody,.messageTime]) | @csv' file.xml
不足している開始タグと終了タグを追加して質問の破損したXMLを修正すると、次のCSV出力が生成されます。
"address","messageBody","messageTime"
,,"1624297248761"
"447917504050","Yeah mate let's do lunch and catch up.","1629944007697"
"447917563330","You going now mate",
答え2
その他xmlstarletコンマで区切られたデータ出力に対する回答:
xmlstarlet sel -t -m //chat -v messageTime -o , -v address -o , -v messageBody -n file.xml
1624297248761,,
1629944007697,447917504050,Yeah mate let's do lunch and catch up.
,447917563330,You going now mate
バッチメッセージの本文です。最後このコンマで区切られたデータは、最後まで3番目のフィールドを本文として持ちます。
メッセージ時間は、1970-01-01 00:00:00 UTC以降のミリ秒数です。これを処理する1つの方法はGNU awkを使用することです。
xmlstarlet sel -t -m //chat -v messageTime -o , -v address -o , -v messageBody -n file.xml \
| TZ=UTC gawk 'BEGIN {FS = OFS = ","} {$1 = strftime("%F %T", $1 / 1000)} 1'
出力
2021-06-21 17:40:48,,
2021-08-26 02:13:27,447917504050,Yeah mate let's do lunch and catch up.
1970-01-01 00:00:00,447917563330,You going now mate
この形式を使用すると、時系列で簡単に並べ替えることができます。
答え3
コメントで述べたように、XMLは正しくないため、次のようにすべてのテキストを新しいタグで囲みます。
<?xml version="1.0"?>
<myxml>
<chat>
....your data which already includes </chat><chat>
</chat>
</myxml>
その後、次のように使用できますxmlstarlet
(たとえば、住所を取得するため)。
xmlstarlet select --template --value-of /myxml/chat/address --nl input_file.xml
(input_file.xml
上記のように追加のラベルを含むデータを含める必要があります)
その他の例ここ