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

PowerShell检查XML节点是否已添加,避免重复插入Filter

问题:PowerShell脚本重复添加XML节点的排查与修复

我通过以下PowerShell脚本向backup.xml文件中添加ExpiresFilter节点及对应的filter-mapping节点:

$file = Resolve-Path 'backup.xml'

$output = [xml](Get-Content $file)

$expiresFilterSingleNodeValue = $output.SelectSingleNode("//filter/filter-name[. = 'ExpiresFilter']")

if($expiresFilterSingleNodeValue -ne $null ) {
    return
}

$mainNode = $output.DocumentElement

$newNode = [xml]@"
<filter>
    <filter-name>ExpiresFilter</filter-name>
    <filter-class>org.apache.catalina.filters.ExpiresFilter</filter-class>
    <init-param>
       <param-name>ExpiresByType image</param-name>
       <param-value>access plus 1 day</param-value>
    </init-param>
    <init-param>
       <param-name>ExpiresByType text/css</param-name>
       <param-value>access plus 1 day</param-value>
    </init-param>
    <init-param>
       <param-name>ExpiresByType application/javascript</param-name>
       <param-value>access plus 1 day</param-value>
    </init-param>
    <init-param>
       <param-name>ExpiresByType font</param-name>
       <param-value>access plus 1 day</param-value>
    </init-param>
</filter>
"@

$newNode = $output.ImportNode($newNode.DocumentElement, $true)
$mainNode.appendChild($newNode) | out-null

$newNode2 = [xml]@"
<filter-mapping>
    <filter-name>ExpiresFilter</filter-name>
    <url-pattern>/baseurl/single/node</url-pattern>
    <dispatcher>REQUEST</dispatcher>
</filter-mapping>
"@

$newNode2 = $output.ImportNode($newNode2.DocumentElement, $true)
$mainNode.appendChild($newNode2) | out-null

$output.Save($file)

当前XML文件结构如下:

<web-app> 
    <filter xmlns="">
    <filter-name>ExpiresFilter</filter-name>
    <filter-class>org.apache.catalina.filters.ExpiresFilter</filter-class>
    <init-param>
      <param-name>ExpiresByType image</param-name>
      <param-value>access plus 1 day</param-value>
    </init-param>
    <init-param>
      <param-name>ExpiresByType text/css</param-name>
      <param-value>access plus 1 day</param-value>
    </init-param>
    <init-param>
      <param-name>ExpiresByType application/javascript</param-name>
      <param-value>access plus 1 day</param-value>
    </init-param>
    <init-param>
      <param-name>ExpiresByType font</param-name>
      <param-value>access plus 1 day</param-value>
    </init-param>
  </filter>
  <filter-mapping xmlns="">
    <filter-name>ExpiresFilter</filter-name>
    <url-pattern>/baseurl/single/node</url-pattern>
    <dispatcher>REQUEST</dispatcher>
  </filter-mapping>
</web-app>

脚本多次触发时会重复添加节点,我尝试用以下代码检查节点是否存在,但逻辑无效:

$expiresFilterSingleNodeValue = $output.SelectSingleNode("//filter/filter-name[. = 'ExpiresFilter']")

if($expiresFilterSingleNodeValue -ne $null ) {
    return
}

问题原因

当前XML中的<filter>和<filter-mapping>节点带有xmlns=""空命名空间,而原XPath查询未处理命名空间,导致SelectSingleNode无法匹配到已存在的节点,因此每次执行脚本都会重复添加。


修复方案

方案1:处理命名空间,修正XPath查询

通过创建XmlNamespaceManager处理空命名空间,调整查询逻辑:

$file = Resolve-Path 'backup.xml'
$output = [xml](Get-Content $file)

# 注册空命名空间
$nsManager = New-Object System.Xml.XmlNamespaceManager($output.NameTable)
$nsManager.AddNamespace("empty", "")

# 检查ExpiresFilter节点和对应mapping是否存在
$expiresFilterExists = $output.SelectSingleNode("//empty:filter/empty:filter-name[. = 'ExpiresFilter']", $nsManager) -ne $null
$filterMappingExists = $output.SelectSingleNode("//empty:filter-mapping/empty:filter-name[. = 'ExpiresFilter']", $nsManager) -ne $null

if ($expiresFilterExists -and $filterMappingExists) {
    return
}

$mainNode = $output.DocumentElement

# 添加filter节点(仅当不存在时)
if (-not $expiresFilterExists) {
    $newNode = [xml]@"
<filter>
    <filter-name>ExpiresFilter</filter-name>
    <filter-class>org.apache.catalina.filters.ExpiresFilter</filter-class>
    <init-param>
       <param-name>ExpiresByType image</param-name>
       <param-value>access plus 1 day</param-value>
    </init-param>
    <init-param>
       <param-name>ExpiresByType text/css</param-name>
       <param-value>access plus 1 day</param-value>
    </init-param>
    <init-param>
       <param-name>ExpiresByType application/javascript</param-name>
       <param-value>access plus 1 day</param-value>
    </init-param>
    <init-param>
       <param-name>ExpiresByType font</param-name>
       <param-value>access plus 1 day</param-value>
    </init-param>
</filter>
"@
    $newNode = $output.ImportNode($newNode.DocumentElement, $true)
    $mainNode.appendChild($newNode) | out-null
}

# 添加filter-mapping节点(仅当不存在时)
if (-not $filterMappingExists) {
    $newNode2 = [xml]@"
<filter-mapping>
    <filter-name>ExpiresFilter</filter-name>
    <url-pattern>/baseurl/single/node</url-pattern>
    <dispatcher>REQUEST</dispatcher>
</filter-mapping>
"@
    $newNode2 = $output.ImportNode($newNode2.DocumentElement, $true)
    $mainNode.appendChild($newNode2) | out-null
}

$output.Save($file)

方案2:遍历节点检查(无需处理命名空间)

直接遍历<web-app>下的节点,检查filter-name的值:

$file = Resolve-Path 'backup.xml'
$output = [xml](Get-Content $file)

$mainNode = $output.DocumentElement
# 检查filter节点是否存在
$expiresFilterExists = $mainNode.SelectNodes("filter") | Where-Object { $_.filter-name -eq "ExpiresFilter" }
# 检查filter-mapping节点是否存在
$filterMappingExists = $mainNode.SelectNodes("filter-mapping") | Where-Object { $_.filter-name -eq "ExpiresFilter" }

if ($expiresFilterExists -and $filterMappingExists) {
    return
}

# 后续添加节点逻辑与原脚本一致,此处省略重复代码
$output.Save($file)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 15:20:29