我需要使用脚本将 xml 转换为 csv。我找到了 xmlstarlet 的解决方案,但它不可用,所以我返回到点 0。这是我的 xml。
<root>
<record>
<id_localisation>8PJ</id_localisation>
<data>
<id_client>50C</id_client>
<mail>[email protected]</mail>
<adress>10 </adress>
<num_tel>001</num_tel>
<key>C</key>
<contact>
<name>toto</name>
<birth>01/30/009</birth>
<city>London</city>
</contact>
</data>
<data>
<id_client>25C</id_client>
<mail>[email protected]</mail>
<adress>20</adress>
<num_tel>02200</num_tel>
<key>D1</key>
<contact>
<name>tata</name>
<birth>02/08/2004</birth>
<city>Spa</city>
</contact>
</data>
</record>
<record>
<id_localisation>ESP31</id_localisation>
<data>
<id_client>70D</id_client>
<mail>[email protected]</mail>
<adress>7Bcd</adress>
<num_tel>5555</num_tel>
<key>D2</key>
<contact>
<name>titi</name>
<birth>05/07/2014</birth>
<city>StMarine</city>
</contact>
</data>
<data>
<id_client>10D</id_client>
<mail>[email protected]</mail>
<adress>888</adress>
<num_tel>881.0</num_tel>
<key>D3</key>
<contact>
<name>awk</name>
<birth>05/08/1999</birth>
<city>Bahrein</city>
</contact>
</data>
</record>
</root>
和我需要的csv,请注意标题是输出的
id_localisation;id_client;key
8PJ;50C;C
8PJ;25C;D1
ESP1;70D;D2
ESP1;10D;D3
我无法安装任何库,但我可以使用 awk、perl、bash,所以我对解决方案持开放态度。
答案1
好的。这里有一个非常基本的问题。 XML 是一种具有详细规范的复杂语言。如果没有库,这会很困难 - XML 从根本上来说是一个需要正确解析的东西。
例如使用XML::Twig
使用 Perl,你会得到:
use strict;
use warnings;
use XML::Twig;
my $twig = XML::Twig->new()->parsefile ( 'your_xml_file.xml' );
print "id_localisation;id_client;key\n";
foreach my $record ( $twig->root->children('record') ) {
foreach my $data ( $record->children('data') ) {
print join( ";",
$record->first_child_text('id_localisation'),
$data->first_child_text('id_client'),
$data->first_child_text('key'),
),
"\n";
}
}
您可能会发现它XML::Twig
已经可用 - 这是相当常见的“默认安装”。所以先检查一下。
有一种肮脏的黑客方式来做这件事,但我真的不建议这样做。我的意思是真的真的,因为它会产生脆弱且可怕的代码。
我无法用更强烈的措辞重申这一点。在执行此操作之前,请先查看:https://stackoverflow.com/a/1732454/2566198
和: https://stackoverflow.com/a/28913945/2566198
请注意,在某些情况下,您可以“按用户”安装 perl 模块,这在这里可能特别相关。
并认识到您的代码故意违反了 XML 规范 - 将其视为文本文件。这是各种糟糕的事情,尤其是因为您可以对 XML 执行一些完全有效的操作,从而打破这一点。
但是,如果您绝对必须:
use strict;
use warnings;
open ( my $input_xml, "<", 'your_xml_file.xml' ) or die $!;
my $loca = "";
print "id_localisation;id_client;key\n";
for (<$input>) {
my ($value) = (m/>(\w+)</);
if (m/id_localisation/) { $loca = $value; }
if (m/id_client/) { print "$loca;$value;"; }
if (m/key/) { print "$value\n"; }
}
close($input);
将打印:
id_localisation;id_client;key
8PJ;50C;C
8PJ;25C;D1
ESP31;70D;D2
ESP31;10D;D3
如果您打算将其用于任何类型的生产功能,那么首先要戳那些不让您安装东西的人,让他们安装您需要的库。这听起来像是一项艰苦的工作,但请相信我 - 没有什么比试图解决有一天神秘地损坏的问题更糟糕的了,因为上游数据格式发生了变化(以规范有效的方式),但下游脚本没有实现标准。
答案2
我会尝试以下 xsl 文件
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output type="text" indent="yes" omit-xml-declaration="yes" />
<xsl:template match="//record">
<xsl:for-each select="data" >
<xsl:value-of select="../id_localisation" />;<xsl:value-of select="id_client" />;<xsl:value-of select="key "/><xsl:text>;
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
与使用
xsltproc sample.xsl sample.xml
答案3
使用 ltXML2 工具包(爱丁堡大学)中的 lxprintf,例如:
$ lxprintf -e data "%s;%s;%s\n" ../id_localisation id_client key test.xml
8PJ;50C;C
8PJ;25C;D1
ESP31;70D;D2
ESP31;10D;D3
使用 XSLT2 很好,但对于这种提取来说有点过分了。
XML 常见问题解答:http://xml.silmaril.ie/
答案4
使用xmlstarlet
:
$ echo 'id_localisation;id_client;key'; xmlstarlet sel -t -m '//record/data' -v 'concat(../id_localisation,";",id_client,";",key)' -nl file.xml
id_localisation;id_client;key
8PJ;50C;C
8PJ;25C;D1
ESP31;70D;D2
ESP31;10D;D3
标头由 输出echo
,并使用 XPath 查询提取数据,该查询将每个record/data
节点id_localisation
的父record
节点值与当前节点的id_client
和key
值连接起来。
这是可行的,只要提取的数据不包含嵌入的分号或换行符,CSV 解析器就能够读取输出。
使用xq
(部分yq
来自https://kislyuk.github.io/yq/):
$ xq -r '[ "id_localisation", "id_client", "key" ], (.root.record[] | .id_localisation as $id | .data[] | [ $id, .id_client, .key ]) | @csv' file.xml
"id_localisation","id_client","key"
"8PJ","50C","C"
"8PJ","25C","D1"
"ESP31","70D","D2"
"ESP31","10D","D3"
这使用jq
表达式来创建 CSV 表。它首先创建一个包含标头的数组,然后从 XML 结构中提取所需的数据,每个data
节点一个数组。然后格式化程序@csv
将这些数组转换为 CSV 记录。
要将分隔符从普通逗号更改为分号,请使用CSV 解析器csvformat
中的例如csvkit
:
$ xq -r '...as before...' file.xml | csvformat -D ';'
id_localisation;id_client;key
8PJ;50C;C
8PJ;25C;D1
ESP31;70D;D2
ESP31;10D;D3