首页 > 解决方案 > 使用 PowerShell 读取、更新和写入 XML 文档

问题描述

我想读取、更新然后将 Web.config 文件写回磁盘,该文件是一个 XML。我现在的做法是:

[xml]$config = Get-Content -Path $ConfigPath
# Update...
$config.Save($ConfigPath)

问题是它稍微弄乱了初始配置格式。我有一些节点,例如:

<add key="DEBUG_API_ABC" value='
{
  "A": {
    "B": "asd",
    "C": "qwe"    
  }
}
'/>

它使它像:

<add key="DEBUG_API_ABC" value=" {   &quot;..."/>

我想完全按原样保存它,保持格式、文本间距,只在更新时注入一些值。可能吗?

标签: xmlpowershellformattingconfig

解决方案


加载 XML 文档的正确方法(不仅在 PowerShell 中)是使用 XML 解析器来加载它并避免Get-Content,因为Get-Content如果有机会,它会很高兴地破坏文件编码。

您似乎有一个属性中包含 JSON 数据的 XML 文件,这很奇怪,但让我们使用您所拥有的:

$config = New-Object xml

$config.Load $ConfigPath

$debugApi = $config.selectSingleNode("//add[@key='DEBUG_API_ABC']")

$configData = $debugApi.getAttribute("value") | ConvertFrom-JSON
$configData.A.B = "new value"

$configJson = $configData | ConvertTo-JSON
$debugApi.setAttribute("value", $configJson)

$config.Save($ConfigPath)

ConvertTo-JSON默认情况下将漂亮地打印其输出,因此虽然它可能不会在 JSON 中保持“原始”空白布局,但仍会在 XML 中产生可识别的结构。


关于问题“我可以在属性值中保留"而不是吗?”&quot;

不,你不能。原因如下:

当涉及序列化“特殊”字符(其中 XML 没有很多,但"'两个)时,XML DOM API 是固执己见的。例如,value='something " something'是有效的 XML,会导致@value该节点的属性something " something解析后获取 RAM 中的字符串值。

然而,当该字符串再次被序列化时,value="something &quot; something"100% 完全相同——但为了重现原始布局,解析器需要记住在原始文件中,该特定属性具有单引号分隔符。

这是很多额外的工作,它会减慢解析速度,占用更多内存,并且这样做不会使最终结果更正确。所以解析器通常不会,它们使用同样正确但容易生成的默认值。

例如,DOM API 对序列化的看法可能是“所有属性都使用双引号作为分隔符,因此属性值中的所有双引号都将被转义”,这完全没问题,因为它将保持数据完整性,这才是最重要的。

它还将所有单引号属性“规范化”为双引号属性,使属性中的 JSON 更难阅读。但问题的一部分是,也许将 JSON 存储在 XML 中并不是最好的选择,至少只要您依赖人工编辑器。


推荐阅读