如何循环遍历XML文件并创建CSV文件?

时间:2016-11-18 13:49:30

标签: xml powershell csv

我有一个良好的PowerShell脚本(感谢Ansgar Wiechers)获得一个XML文件,它将所需的字段导出到CSV文件:

$goal = '\\LC\ARCHIV\INPUT_' + (Get-Date -Format yyyyMMddss) + '.xml'
[xml]$xml = Get-Content '\\mcsonlines-impexp\Onlines\LCMS\IMPORT\*.xml'
$xml.SelectNodes('//COMPOUND') |
  Select-Object @{n='SampleID';e={[int]$_.ParentNode.id}},
                @{n='SampleName';e={"B" + $_.ParentNode.name}},
                @{n='CompoundID';e={[int]$_.id}},
                @{n='CompoundName';e={$_.name}},
                @{n='analconc';e={[double]$_.PEAK.analconc}} |
  Export-Csv '\\LC\IMPORT\quandata.csv' -NoType -Delimiter ';'

Move-Item -Path \\LC\IMPORT\*.xml -destination $goal

XML文件:

<?xml version="1.0"?>
<QUANDATASET>
  <XMLFILE>
  <DATASET>
  <GROUPDATA>
    <GROUP>
      <METHODDATA/>
      <SAMPLELISTDATA>
        <SAMPLE id="1" groupid="1" name="Routine_2016_05_30_002">
          <COMPOUND id="1" sampleid="1" groupid="1" name="Leu">
            <PEAK foundscan="0" analconc="0.023423456">
              <ISPEAK/>
            </PEAK>
          </COMPOUND>
          <COMPOUND id="2" sampleid="1" groupid="1" name="Iso">
             <PEAK foundscan="0" analconc="0.123456789">
               <ISPEAK/>
             </PEAK>
          </COMPOUND>
          <COMPOUND id="3" sampleid="1" groupid="1" name="Thre">
          ...
          ...
          ...
        <SAMPLE id="2" groupid="1" name="Routine_2016_05_30_003">
          <COMPOUND id="1" sampleid="2" groupid="1" name="Leu">
          ...
          ...
          ...

CSV导出如下:

SampleID   SampleName  CompoundID  CompoundName    analconc
...
6   Routine_2016_11_11_006  1   Leu 60,30064828
6   Routine_2016_11_11_006  2   Iso 60,38823887
6   Routine_2016_11_11_006  3   Thre 74,00187964
...

现在我的问题 - 是否可以使用脚本一次处理多个XML文件到CSV文件?我的改变使得剧本一点都没有。

首先尝试:

$file = Get-ChildItem '\\LC\IMPORT\*.xml' -Recurse
foreach ($file in $files) {
  [xml]$xml = (Get-Content $file)
  $xml.SelectNodes('//COMPOUND') |
    Select-Object @{n='SampleID';e={[int]$_.ParentNode.id}},
                  @{n='SampleName';e={"B" + $_.ParentNode.name}},
                  @{n='CompoundID';e={[int]$_.id}},
                  @{n='CompoundName';e={$_.name}},
                  @{n='analconc';e={[double]$_.PEAK.analconc}} |
    Export-Csv '\\LC\IMPORT\quandata.csv' -NoType -Delimiter ';'
}

这根本不起作用。

第二次尝试:

Get-ChildItem '\\LC\IMPORT\' *.xml -Recurse | % {
  $xml = [xml](Get-Content $_.FullName)
  #$goal = '\\LC\ARCHIV\INPUT_' + (Get-Date -Format yyyyMMddss) + '.xml'

  $xml.SelectNodes('//COMPOUND') |
    Select-Object @{n='SampleID';e={[int]$_.ParentNode.id}},
                  @{n='SampleName';e={"B" + $_.ParentNode.name}},
                  @{n='CompoundID';e={[int]$_.id}},
                  @{n='CompoundName';e={$_.name}},
                  @{n='analconc';e={[double]$_.PEAK.analconc}} |
    Export-Csv '\\LC\IMPORT\quandata.csv' -NoType -Delimiter ';'
}

通过此尝试,只有一个XML文件导出到CSV文件。

这是我第一篇文章的链接:

How to output child elements separately, not as one space-delimited string?

2 个答案:

答案 0 :(得分:1)

您总是覆盖csv文件,请使用:

[..]Export-Csv '\\LC\IMPORT\quandata.csv' -NoType -Delimiter ';' -Append

代替。 -Append将导致PowerShell添加新内容。

答案 1 :(得分:0)

您的第一种方法没有做任何事情,因为您收集变量$file中的XML文件列表,但随后迭代变量$files(注意尾随的“s”),这是空。

你的第二种方法会在每次迭代时覆盖输出文件,因为你在} 循环中使用了Export-Csv 而没有参数-Append

循环之后放置Export-Csv语句

Get-ChildItem '\\LC\IMPORT\*.xml' -Recurse | ForEach-Object {
  [xml]$xml = Get-Content $_.FullName

  $xml.SelectNodes('//COMPOUND') |
    Select-Object @{n='SampleID';e={[int]$_.ParentNode.id}},
                  @{n='SampleName';e={"B" + $_.ParentNode.name}},
                  @{n='CompoundID';e={[int]$_.id}},
                  @{n='CompoundName';e={$_.name}},
                  @{n='analconc';e={[double]$_.PEAK.analconc}}
} | Export-Csv '\\LC\IMPORT\quandata.csv' -NoType -Delimiter ';'

或使用参数Export-Csv 循环中调用-Append,以便每次迭代都附加到CSV:

Get-ChildItem '\\LC\IMPORT\*.xml' -Recurse | ForEach-Object {
  [xml]$xml = Get-Content $_.FullName

  $xml.SelectNodes('//COMPOUND') |
    Select-Object @{n='SampleID';e={[int]$_.ParentNode.id}},
                  @{n='SampleName';e={"B" + $_.ParentNode.name}},
                  @{n='CompoundID';e={[int]$_.id}},
                  @{n='CompoundName';e={$_.name}},
                  @{n='analconc';e={[double]$_.PEAK.analconc}} |
    Export-Csv '\\LC\IMPORT\quandata.csv' -Append -NoType -Delimiter ';'
}

第一种方法更可取,因为它避免重复打开和关闭输出文件,因此它具有更好的性能。此外,参数-Append在PowerShell v3之前不可用,因此第二种方法至少需要PowerShell版本,并且无法在PowerShell v2或更早版本上运行。