PowerShell合并多层XML节点数据导出CSV时结构错乱如何解决
问题根因
原代码逻辑存在本质错误:每次调用ConvertTo-Csv都会将传入的节点对象作为独立数据行生成CSV片段,再逐段追加到文件中,完全没有做跨层级的属性合并,最终不同节点的属性会被纵向拆分为多行;另外直接传入嵌套Xml元素转CSV时,PowerShell只会识别到对象类型为System.Xml.XmlElement,不会自动提取内部嵌套的属性值,才会出现类型名占位、属性名和属性值拆成两行的异常。
正确实现方案
核心思路是先遍历所有目标节点,把各层级节点的属性全部提取合并到同一个自定义PowerShell对象中,让所有属性横向展开为列,最后一次性转换导出CSV,禁止逐段追加内容。
完整可直接运行的代码如下:
[xml]$inputFile = Get-Content "$savepath\config.xml" -Encoding UTF8 # 遍历所有应用池节点,合并全层级属性 $allAppPools = foreach ($pool in $inputFile.appcmd.APPPOOL) { $addNode = $pool.add $recyclingNode = $addNode.recycling $periodicRestartNode = $recyclingNode.periodicRestart # 合并所有层级属性到单行对象 [PSCustomObject]@{ # 顶层APPPOOL节点属性 "APPPOOL.NAME" = $pool.GetAttribute("APPPOOL.NAME") PipelineMode = $pool.GetAttribute("PipelineMode") RuntimeVersion = $pool.GetAttribute("RuntimeVersion") state = $pool.GetAttribute("state") # add节点属性 add_name = $addNode.GetAttribute("name") enable32BitAppOnWin64 = $addNode.GetAttribute("enable32BitAppOnWin64") managedPipelineMode = $addNode.GetAttribute("managedPipelineMode") # recycling节点属性 logEventOnRecycle = $recyclingNode.GetAttribute("logEventOnRecycle") # periodicRestart节点属性 privateMemory = $periodicRestartNode.GetAttribute("privateMemory") requests = $periodicRestartNode.GetAttribute("requests") restart_time = $periodicRestartNode.GetAttribute("time") # cpu节点属性 cpu_limit = $addNode.cpu.GetAttribute("limit") smpAffinitized = $addNode.cpu.GetAttribute("smpAffinitized") numaNodeAssignment = $addNode.cpu.GetAttribute("numaNodeAssignment") # failure节点属性 orphanWorkerProcess = $addNode.failure.GetAttribute("orphanWorkerProcess") rapidFailProtectionInterval = $addNode.failure.GetAttribute("rapidFailProtectionInterval") rapidFailProtectionMaxCrashes = $addNode.failure.GetAttribute("rapidFailProtectionMaxCrashes") autoShutdownExe = $addNode.failure.GetAttribute("autoShutdownExe") # processModel节点属性 maxProcesses = $addNode.processModel.GetAttribute("maxProcesses") pingInterval = $addNode.processModel.GetAttribute("pingInterval") } } # 一次性导出为标准CSV文件 $allAppPools | ConvertTo-Csv -NoTypeInformation -Delimiter ";" | Set-Content "$savepath\config.csv" -Encoding UTF8
导出效果说明
针对提供的示例XML,最终导出的CSV完全符合数据导入要求:每个应用池对应单独一行,所有层级节点属性全部横向展开为独立列,不存在拆行、类型名占位问题,输出内容如下:
"APPPOOL.NAME";"PipelineMode";"RuntimeVersion";"state";"add_name";"enable32BitAppOnWin64";"managedPipelineMode";"logEventOnRecycle";"privateMemory";"requests";"restart_time";"cpu_limit";"smpAffinitized";"numaNodeAssignment";"orphanWorkerProcess";"rapidFailProtectionInterval";"rapidFailProtectionMaxCrashes";"autoShutdownExe";"maxProcesses";"pingInterval" "DefaultAppPool";"Classic";"v4.0";"Started";"DefaultAppPool";"true";"Classic";"Time, Requests, Schedule, Memory, IsapiUnhealthy, OnDemand, ConfigChange";"5000";"1";"1.05:01:00";"50000";"true";"MostAvailableMemory";"true";"00:01:00";"6";"1";"2";"00:00:31"
补充说明:
- 如果配置文件中存在多个APPPOOL节点,脚本会自动遍历全部节点逐行生成记录,无需额外调整
- 如果需要新增其他节点的属性,直接在
[PSCustomObject]结构块中新增对应列名、从目标节点读取属性值即可
内容的提问来源于stack exchange,提问作者full01
相关产品推荐
相关产品推荐

