我有一个很大的 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
这是放置消息正文最后的这样逗号分隔的数据会将第三个字段到最后作为正文。
消息时间是自 1970-01-01 00:00:00 UTC 以来的毫秒数。处理它的一种方法是使用 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
应包含带有如上所述额外标签的数据)
更多例子这里