PowerShell用[xml]类型可高效解析XML,需用-Raw参数或Load()方法避免解析失败;推荐XPath定位节点而非硬编码路径;映射对象时须判空并处理空白与多值节点;Save()会丢失格式且不自动转义特殊字符。

PowerShell 里用 [xml] 类型加速解析 XML
PowerShell 原生支持 XML 解析,不需要额外模块——直接用 [xml] 强制类型转换就能把字符串或文件加载为可导航的 .NET XmlDocument 对象。这比调用外部工具快得多,也比手动字符串拆解可靠。
常见错误是直接用 Get-Content 读取后不转类型,结果得到纯文本,无法用点号访问节点:$xml.Root.Child 会报错“Cannot index into a null array”。
- 正确做法:用
[xml](Get-Content file.xml -Raw)或[xml]::new().Load("file.xml") -
-Raw参数必须加,否则Get-Content按行返回字符串数组,[xml]无法解析 - 如果 XML 带 BOM 或编码异常(如 UTF-8 with BOM),优先用
[xml]::new().Load()配合StreamReader显式指定编码
用 XPath 定位节点比硬写层级更健壮
XML 结构稍一变动(比如多一层 ),用 $xml.DocumentElement.FirstChild.NextSibling.InnerText 这类链式访问就会崩。XPath 是标准、声明式的定位方式,PowerShell 的 SelectNodes() 和 SelectSingleNode() 都支持。
注意 PowerShell 默认使用 .NET Framework 的 XPath 1.0 实现,不支持 last()、position() 等函数,但常用谓词 [1]、[@attr='val'] 全都可用。
- 查所有
下的name子节点:$xml.SelectNodes("//item/name") - 查带特定属性的节点:
$xml.SelectSingleNode("//config[@env='prod']") - 避免写死索引:
$xml.SelectSingleNode("//user[username='admin']")比$xml.users.user[0]更安全
映射 XML 到自定义对象时别直接用 PSCustomObject 填属性
把 XML 节点转成 PowerShell 对象很常见,但直接用 [PSCustomObject]@{...} 手动赋值,在字段多、嵌套深、有可选节点时极易漏判空值,导致后续操作报错。
更稳妥的方式是先提取节点(用 XPath 或 ChildNodes),再逐个检查 .InnerText 或 .Value 是否为空,并用三元表达式或 if 控制默认值。
$items = $xml.SelectNodes("//product")
$products = foreach ($item in $items) {
[PSCustomObject]@{
Id = if ($item.id) { $item.id.InnerText } else { $null }
Name = $item.name.InnerText.Trim()
Price = if ($item.price -and $item.price.InnerText -match '^\d+\.?\d*$') {
[decimal]$item.price.InnerText
} else { 0 }
Tags = @($item.tags.ChildNodes | Where-Object NodeType -eq 'Element' | ForEach-Object Name)
}
}
-
.InnerText可能含空白,记得Trim() - 子节点不存在时,
$item.missing返回$null,但$null.InnerText会抛异常,必须先判空 - 多值节点(如多个
)要用ChildNodes+ 类型过滤,不能只靠$item.tags.tag
写回 XML 时 Save() 不保留原始缩进,且不自动编码特殊字符
修改完 [xml] 对象后调用 $xml.Save("out.xml"),输出文件会丢失原有格式(全挤在一行)、中文可能变乱码、&、 等字符不会被转义——这不是 bug,是 XmlDocument 的默认行为。
如果需要人眼可读或兼容旧系统,得手动配置 XmlWriterSettings;如果只是供程序读取,保持默认即可。
- 保留缩进和 UTF-8 编码:
$settings = [System.Xml.XmlWriterSettings]::new() $settings.Indent = $true $settings.Encoding = [System.Text.UTF8Encoding]::new($false) $writer = [System.Xml.XmlWriter]::Create("out.xml", $settings) $xml.Save($writer) $writer.Close() - 写入前确保内容已转义:PowerShell 不会自动处理,
&必须写成&,否则保存后 XML 无效 - 修改节点内容用
.InnerText = "new value",不要改.InnerXml除非你明确需要插入标记
XML 命名空间(xmlns)是最容易被忽略的复杂点。一旦文档声明了默认命名空间,所有 XPath 查询必须绑定前缀,否则查不到任何节点——这点在调试时经常卡住半天。










