将1个文件中的多个xml转换为csv

时间:2020-08-09 06:04:45

标签: perl

我有一个文本文件,其中包含多个如下所示的xml:

<queryResponse><entity><devicesDTO><clearedAlarms>1</clearedAlarms><warningAlarms>0</warningAlarms></devicesDTO></entity></queryResponse>
<queryResponse><entity><devicesDTO><clearedAlarms>2</clearedAlarms><warningAlarms>2</warningAlarms></devicesDTO></entity></queryResponse>

我想将每一行都转换为一个csv:

clearedAlarms, warningAlarms
1, 0
2, 2

这是我现在拥有的,仅使我能够解析xml并输出csv。该文件现在实际上已更改,我应该正在读取包含多个xml的txt文件

#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use XML::Simple;

#Elements, that I want see in my csv
my @Fields = qw{clearedAlarms warningAlarms};

open(my $out, '>', 'test.csv') or die "Output: $!\n";
print $out join(',', @Fields) . "\n";

my $xml = XMLin('test.xml', ForceArray => ['entity']);
foreach my $entity ( @{ $xml->{entity} } ) {
    print Dumper $entity;
}
foreach my $entity ( @{ $xml->{entity} } ) {
    print $out join( ',', @{ $entity->{devicesDTO} }{@Fields} ) . "\n";
}

3 个答案:

答案 0 :(得分:2)

这是Perl口号的由来:“做的方式不止一种!”如果您不想使用xml模块(如前所述,该文件实际上已经更改,并且我应该读取包含多个xml的txt文件),则可以使用https://metacpan.org/pod/File::Grep mdoule(查找与一系列文件中的模式和相关功能)以进行文件操作。以及https://metacpan.org/pod/Text::CSV_XShttps://metacpan.org/pod/Text::CSV_XS)此模块提供了与csv操作相关的更多功能,您可以根据需要使用它们。

fmap阻止列表 使用BLOCK作为映射功能,对LIST中的文件执行映射操作。来自BLOCK的结果将被添加到调用结束时返回的列表中。

csv这是针对简单(用户)界面的高级功能。可用于读取/解析CSV文件或流(默认行为)或生成文件或写入流(定义out属性)。

import 'package:flutter/material.dart';
import 'story.dart';
import 'dart:math';

class StoryBrain {
  static Random random = Random();
  int textNumber;
  bool gameTypeIsClasic = false;

  static List<Story> textListClasic = [
    Story(
      "text content 2",
      "göm",
    ),
    Story(
      "text content 1",
      "öv",
    ),
    Story(
      "text content 3",
      "göm",
    ),
    Story("text content 4", "öv")
  ];

  static List<Story> textListTemel = [
    Story(
      "text content 1",
      "göm",
    ),
    Story(
      "text content 2",
      "öv",
    ),
    Story(
      "text content 3",
      "göm",
    ),
    Story("text content 4", "öv")
  ];

  int heat = 1;

  StoryBrain() {
    if (gameTypeIsClasic == true) {
      random.nextInt(textListClasic.length - 1);
    } else {
      random.nextInt(textListTemel.length - 1);
    }
  }

  void changeNumber() {
    if (gameTypeIsClasic == true) {
      textNumber = random.nextInt(textListClasic.length - 1);
    } else {
      textNumber = random.nextInt(textListTemel.length - 1);
    }
  }

  String getText() {
    if (gameTypeIsClasic == true) {
      return textListClasic[textNumber].textContent;
    } else {
      return textListTemel[textNumber].textContent;
    }
  }

  String getTextType() {
    if (gameTypeIsClasic == true) {
      return textListClasic[textNumber].textType;
    } else {
      return textListTemel[textNumber].textType;
    }
  }

  Color setColor() {
    if (getTextType() == "öv") {
      return Colors.blue;
    } else {
      return Colors.red;
    }
  }

  String updateHeat() {
    if (getTextType() == "öv") {
      if (heat > 1 && heat < 20) {
        heat = heat - 1;
      } else if (heat > 20 && heat < 100) {
        heat -= 10;
      } else if (heat > 200 && heat < 500) {
        heat -= 25;
      } else if (heat > 500) {
        heat = (heat ~/ 3);
      } else {
        heat = heat;
      }
    } else {
      if (heat < 1000) {
        heat = heat * 2;
      } else {
        heat += 100;
      }
    }
    return heat.toString() + "x";
  }

  Color changeHeatBarColor() {
    if (heat >= 50 && heat < 100) {
      return Colors.orange;
    } else if (heat >= 100 && heat < 500) {
      return Colors.redAccent;
    } else if (heat > 500) {
      return Colors.red[800];
    } else {
      return Colors.blue;
    }
  }
}

输出(如果您打开$ csv_file文件)

const { session } = win.webContents;
session.webRequest.onBeforeSendHeaders(filter, (details, callback) => {
    
    delete details.requestHeaders["User-Agent"];

    callback({ requestHeaders: details.requestHeaders });
});

session.webRequest.onHeadersReceived(filter, (details, callback) => {
    details.responseHeaders["access-control-allow-origin"] = "*";

    callback({ responseHeaders: details.responseHeaders });

});

答案 1 :(得分:1)

鉴于XML模式的简单性,使用AnyData更容易做到

例如:

#!/usr/bin/perl
# This script converts a XML file to CSV format.

# Load the AnyData XML to CSV conversion modules
use XML::Parser;
use XML::Twig;
use AnyData;

my $input_xml = "test.xml";
my $output_csv = "test.csv";


$flags->{record_tag} = 'ITEM';
adConvert( 'XML', $input_xml, 'CSV', $output_csv, $flags );

将您的数据结构(XML)转换为:

clearedAlarms, warningAlarms
1, 0
2, 2

答案 2 :(得分:0)

如果您的文件结构始终相同,则实际上不需要XML解析器。但是您也不需要任何其他东西。您可以将该输入文件视为稍微复杂的CSV文件,其中包含奇怪的定界符。

split使用模式将字符串转换为字符串列表。默认情况下,它将占用定界符匹配项,因此此匹配项消失。我们可以使用看起来像XML标签的模式作为模式。请注意,我如何将qr//与不是斜杠/的定界符一起使用,以使其更具可读性,因为它避免了在结束标记中转义可选的斜杠/

split qr{</?[^>]+>}, '<foo>123</foo>';

这将产生一个看起来像这样的数据结构(使用Data::Printer来产生输出):

[
    [0] "",
    [2] 123
]

第一个元素是一个空字符串,表示在分隔符模式的第一个匹配项之前缺少任何其他字符。我们需要过滤掉它们。使用grep可以轻松做到这一点。

grep { $_ ne q{} } split qr{</?[^>]+>}, '<foo>123</foo>';

现在我们的输出很好,很干净。

[
    [0] 123
]

我们现在要做的就是将其应用于完整文件。由于我们的数据仅包含几个数字,因此在这种情况下无需使用Text :: CSV。

use strict;
use warnings;
use feature 'say';

while (<DATA>) {
    chomp;
    say join ',', grep { $_ ne q{} } split qr{</?[^>]+>};
}

__DATA__
<queryResponse><entity><devicesDTO><clearedAlarms>1</clearedAlarms><warningAlarms>0</warningAlarms></devicesDTO></entity></queryResponse>
<queryResponse><entity><devicesDTO><clearedAlarms>2</clearedAlarms><warningAlarms>2</warningAlarms></devicesDTO></entity></queryResponse>

请记住,这里我们可以使用模式匹配,因为我们实际上并不解析XML。如果要进行任何真正的XML解析,请不要使用正则表达式!