You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

处理XML/plist非法字符时的节点删除与格式保留问题求助

解决Embarcadero iOS plist模板的PowerShell编辑问题

背景

Embarcadero IDE通过plist模板构建iOS应用,这类XML模板包含<%VersionInfoPListKeys%>这类仅在Embarcadero部署阶段解析的占位符。由于IDE不支持Xcode的$(PRODUCT_BUNDLE_IDENTIFIER)变量,必须通过PowerShell脚本手动编辑模板,添加关联Bundle ID的自定义条目。

问题现象

这些占位符属于XML非法内容,导致PowerShell无法直接将文件转换为XML对象。尝试先将<%替换为<_、%>替换为_/>,处理完成后再替换回原符号,但执行脚本后出现两个问题:

  • 新增的array节点无格式化,以单行形式存在;
  • 无法删除已存在的对应array节点,仅能删除key节点,导致内容重复。

若使用Get-Content加载文件,节点增删逻辑正常,但PreserveWhitespace属性失效,输出内容为单行。

现有脚本代码

加载plist文件

$plist_raw = ([System.IO.File]::ReadAllText($plistPath)) -replace "&lt;%", "&lt;_" -replace "%&gt;", "_/&gt;"
$plist = [xml]::new()
$plist.PreserveWhitespace = $true
$plist.LoadXml($plist_raw)

添加/替换array节点

$arrayKey = "some_key"
$keyNode = (Select-Xml -Xml $plist -XPath "//dict/key" | Where-Object { $_.Node.InnerText -eq $arrayKey } | Select-Object -First 1).Node
if ($keyNode) {
    $plist.plist.dict.RemoveChild($keyNode.NextSibling)
    $plist.plist.dict.RemoveChild($keyNode)
}

$arrayNode = $plist.CreateElement('array')
$arrayKeyNode = $plist.CreateElement('key')
$arrayKeyNode.InnerText = $arrayKey
$plist.plist.dict.AppendChild($arrayKeyNode)
$plist.plist.dict.AppendChild($arrayNode)

$value1 = "$bundleId.foo"
$value2 = "$bundleId.bar"

foreach ($item in @($value1, $value2)) {
    $newItem = $plist.CreateElement('string')
    $newItem.InnerText = $item
    $arrayNode.AppendChild($newItem)
    Write-Host "Identifier '$item' has been added to the array '$arrayKey'."
} 

保存plist文件

($plist.OuterXml -replace "&lt;_", "&lt;%" -replace "_/&gt;", "%&gt;" -replace "_ /&gt;", "%&gt;") | Set-Content $plistPath

预期与实际输出

  • 预期:some_key对应的array节点格式正确,旧节点被完全覆盖;
  • 实际:旧array节点未被删除,新节点无格式化,内容重复。

解决方案

1. 修复旧节点删除逻辑

原逻辑中keyNode.NextSibling可能指向空白节点(换行、空格)而非目标array节点,需跳过空白节点定位到真正的array节点:

$arrayKey = "some_key"
$keyNode = (Select-Xml -Xml $plist -XPath "//dict/key[text()='$arrayKey']").Node
if ($keyNode) {
    $currentNode = $keyNode.NextSibling
    # 跳过空白节点,找到后续的array节点
    while ($currentNode -and $currentNode.NodeType -eq [System.Xml.XmlNodeType]::Whitespace) {
        $currentNode = $currentNode.NextSibling
    }
    # 确认找到的是array节点再删除
    if ($currentNode -and $currentNode.Name -eq 'array') {
        $plist.plist.dict.RemoveChild($currentNode)
    }
    $plist.plist.dict.RemoveChild($keyNode)
}

2. 解决XML格式化问题

OuterXml输出无格式XML,改用XmlWriter生成带缩进的格式化内容,匹配plist默认格式:

# 配置XML写入设置
$xmlSettings = New-Object System.Xml.XmlWriterSettings
$xmlSettings.Indent = $true
$xmlSettings.IndentChars = "`t" # 用制表符对齐
$xmlSettings.OmitXmlDeclaration = $false
$xmlSettings.NewLineChars = "`n" # 统一换行符

# 写入内存流生成格式化XML
$memoryStream = New-Object System.IO.MemoryStream
$writer = [System.Xml.XmlWriter]::Create($memoryStream, $xmlSettings)
$plist.WriteTo($writer)
$writer.Flush()
$memoryStream.Position = 0

# 读取格式化内容并替换占位符
$reader = New-Object System.IO.StreamReader($memoryStream)
$formattedXml = $reader.ReadToEnd()
$reader.Close()
$writer.Close()
$memoryStream.Close()

# 保存最终内容
$finalContent = $formattedXml -replace "&lt;_", "&lt;%" -replace "_/&gt;", "%&gt;"
Set-Content -Path $plistPath -Value $finalContent -Encoding UTF8

3. 优化文件加载逻辑

显式指定UTF8编码加载plist文件,避免编码问题:

$plist_raw = ([System.IO.File]::ReadAllText($plistPath, [System.Text.Encoding]::UTF8)) -replace "&lt;%", "&lt;_" -replace "%&gt;", "_/&gt;"
$plist = [xml]::new()
$plist.PreserveWhitespace = $true
$plist.LoadXml($plist_raw)

内容的提问来源于stack exchange,提问作者Marvin Zakrzewski

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 12:54:53