XML을 CSV로 변환

XML을 CSV로 변환

스크립트를 사용하여 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::TwigPerl을 사용하면 다음을 얻을 수 있습니다.

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 FAQ: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/dataid_localisationrecordid_clientkey

추출된 데이터에 세미콜론이나 개행 문자가 포함되어 있지 않으면 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"

표현식을 사용하여 jqCSV 테이블을 생성합니다. 먼저 헤더가 포함된 배열을 만든 다음 data노드당 하나의 배열로 XML 구조에서 필요한 데이터를 추출합니다. 그런 다음 포맷터는 @csv이러한 배열을 CSV 레코드로 변환합니다.

구분 기호를 일반 쉼표에서 세미콜론으로 변경하려면 csvformat예를 들어 CSV 구문 분석기에서 사용하십시오 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

관련 정보