xml - 如何使用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>
解决方案
这是您的代码的简化版本:
$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 元素。
推荐阅读
- sql-update - 在 WHERE 子句中使用类似 WINDOW 的函数对表进行 SQL 更新
- css - 为什么我的 Angular 应用程序加载时没有立即应用预期的 Material 按钮样式,只是稍后应用?
- c# - 使用反射在字符串列表中查找字符串
- ruby-on-rails - 在 Ruby on rails 5 上运行测试时出现未初始化的常量错误
- angular - 在角度 8 ng add ng-zorro-antd 中使用 cli 添加 ng-zorro-antd 时出现错误
- python - 为什么'if not'检查python中的空字符串
- javascript - 使用nodejs wrapper(compile-run)来运行cpp代码是否可行?
- python - 如何正确导入python中不同文件中定义的常量
- javascript - TradingView 图表不显示
- xslt - 获取节点的位置将其用作 XSLT 中的属性值