如何移除XML元素中的xsi:nil属性以正常处理PowerShell数据?
问题:处理SOAP返回XML中带xsi:nil属性的元素异常
从SOAP服务器获取的XML结果里,部分<data>元素带有xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"属性,导致数据处理异常。使用Select-Xml能正常处理多数元素,但对带该属性的<data>元素无效。
XML示例
<ns2:getReportResultResponse xmlns:ns2="http://service.admin.ws.example.com/"> <return> <header> <values> <data>DATE</data> <data>AGENT</data> <data>AGENT FIRST NAME</data> <data>AGENT LAST NAME</data> <data>CALLS count</data> <data>HANDLE TIME</data> <data>AFTER CALL WORK TIME</data> <data>CONFERENCE TIME</data> <data>SHORT CALLS count</data> <data>LONG CALLS count</data> </values> </header> <records> <values> <data>2022/07/27</data> <data>example@example.com</data> <data>Test</data> <data>User</data> <data>49</data> <data>02:00:00</data> <data>00:45:00</data> <data xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" /> <data>49</data> <data>0</data> </values> </records> </return> </ns2:getReportResultResponse>
原PowerShell代码
Select-Xml -Content ([xml]$final_response | Select-Object -ExpandProperty Objects | Select-Object -ExpandProperty Object | Select-Object -ExpandProperty '#text') "//return/*/values" -Namespace @{ ns = 'http://service.admin.ws.example.com/'} | ForEach-Object { # See if an entry already exists for the key at hand. if ($obj.Contains($_.Node.header.values.data)) { # Convert the entry value into an array on demand and # append the value at hand. [array] $obj[$_.Node.header.values.data] += $_.Node.records.values.data } else { # Create the entry, using the value as-is. $obj[$_.Node.header.values.data] = $_.Node.records.values.data } }
注:$final_response即上述XML示例输出。
解决方案
核心问题
带xsi:nil="true"的<data>是空自闭合标签,直接访问.values.data时,PowerShell会忽略这类节点,导致数组长度不匹配、值缺失或错位。
修正后的代码
# 直接解析XML对象 $xml = [xml]$final_response # 提取header的所有字段名 $headers = $xml.SelectNodes('//header/values/data') | ForEach-Object { $_.InnerText } # 提取records的所有值,处理空节点 $recordValues = $xml.SelectNodes('//records/values/data') | ForEach-Object { # 判断是否为xsi:nil空节点 if ($_.HasAttribute('xsi:nil') -and $_.GetAttribute('xsi:nil') -eq 'true') { "" # 空节点替换为空字符串,可根据需求改为0或其他默认值 } else { $_.InnerText } } # 构建结果哈希表(保持顺序) $obj = [ordered]@{} for ($i=0; $i -lt $headers.Count; $i++) { $key = $headers[$i] $value = $recordValues[$i] if ($obj.Contains($key)) { [array]$obj[$key] += $value } else { $obj[$key] = $value } } # 输出结果 $obj
关键改进点
- 直接解析XML对象,避免原代码中冗余的
Select-Object操作和无效的命名空间配置 - 显式遍历所有
<data>节点,强制处理空节点,保证字段值和header一一对应,不会错位 - 使用
[ordered]哈希表保持字段顺序和XML中header的顺序一致
内容的提问来源于stack exchange,提问作者Rod Argumedo
相关产品推荐
相关产品推荐

