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
相关产品推荐
相关产品推荐

