首页 > 解决方案 > 如何使用csv列标题powershell获取xml字段值

问题描述

当我使用 for 循环然后在代码中添加值 $b ({ $_.'field_name' -eq $b}那么它给出的是空白值而不是结果。

$CSVpath = "G:\1.csv"
$columncount=((Get-Content $CSVpath)[0] -split ",").count
write-host $columncount
$xml= "G:\1.xml"
[xml] $xmlDoc = Get-Content $xml
for($i=0; $i -le $columncount;$i++){
$a = ((Get-Content $CSVpath)[0] -split(','))[$i]
$b= "'$a'"
Function xml{
param($value)
$xml= "G:\1.xml"
[xml] $xmlDoc = Get-Content $xml
$a1= $xmlDoc.enum_types.enum_type.Where({ $_.'field_name' -eq  $b}, 'First').items.item.where({ $_.id -eq 1}).value
$d = $a1.'#cdata-section'
write-host  $d
}
xml $b
}

请帮我解决问题。请找到xml:

    <enum_types>
    
        <enum_type field_name="Test1">
            <items>
                <item>
                    <id>1</id>
                    <value>A</value>
                </item>
            </items>
            </enum_type>
<enum_type field_name="Test2">
            <items>
                <item>
                    <id>1</id>
                    <value>A</value>
                </item>
            </items>
            </enum_type>
        </enum_types>

请找到 csv 文件:在此处输入图像描述

标签: xmlpowershellcommand-line-interface

解决方案


这是您的代码的简化版本:

$CSVpath = "G:\1.csv"
$xmlPath = "G:\1.xml"

# This is a more robust (and faster) way to load XML files.
($xmlDoc = [xml]::new()).Load((Convert-Path $xmlPath))

# Get all column names
$columnNames = (Get-Content -First 1 $CSVpath) -split ',' -replace '"'
Write-Host "Column count: $($columnNames.Count); names: $columnNames"

foreach ($columnName in $columnNames) {
  @($xmlDoc.enum_types.enum_type.Where({ $_.field_name -eq $columnName }, 'First').
   items).ForEach({ $_.item }).Where({ $_.id -eq 1 }).value
}

它为我输出以下内容:

Column count: 2; names: Test1 Test2
A
A

笔记:

  • 由于 XML 文档中没有 CDATA 部分,因此不需要.'#cdata-section'

  • 使用.ForEach()枚举子元素命名的基本原理<item>,特别是 - 虽然您的示例 XML 文档不是绝对必要的,因为只有一个这样的子元素 - 在这个答案中进行了解释。

    • 由于不幸的错误[1]已在 PowerShell (Core) 7+ 中修复,因此仅在Windows PowerShell@(...)中需要使用数组子表达式运算符来安全地应用.ForEach()(和)。.Where()

    • 链接的答案还显示了一个 - 更快 - 基于 XPath 的解决方案 via Select-Xml,您可以通过其实例方法将其类似地应用于[xml]内存中已经存在的实例($xmlDoc在本例中) 。.SelectSingleNode()


以上仅对 CSV 文件的列名进行操作,具有硬编码 id值 - 就像您自己的尝试一样。

要根据 CSV 中的数据并根据填写的列从 XML 中提取数据

$CSVpath = "G:\1.csv"
$xmlPath = "G:\1.xml"

# This is a more robust (and faster) way to load XML files.
($xmlDoc = [xml]::new()).Load((Convert-Path $xmlPath))

# Import the CSV.
$csvRows = Import-Csv $CSVpath
# Get the column names.
$columnNames = $csvRows[0].psobject.Properties.Name

foreach ($csvRow in $csvRows) {
  foreach ($columnName in $columnNames) {
    $id = $csvRow.$columnName
    if (-not $id) { continue }
    @($xmlDoc.enum_types.enum_type.Where({ $_.field_name -eq $columnName }, 'First').
      items).ForEach({ $_.item }).Where({ $_.id -eq $id }).value
  }
}

注意:对于这样的嵌套循环,绝对值得考虑切换到 XPath 解决方案.SelectSingleNode()以提高性能。

[1].ForEach()并且.Where()应该适用于任何对象,甚至是标量(非集合)对象,但在 Windows PowerShell 中不适用于某些类型,例如 XML 元素。


推荐阅读