如何用PowerShell移除含指定XML标签的注释并解决测试冲突?
PowerShell移除XML特定标签注释的问题与解决
需求与问题概述
需要实现PowerShell脚本移除XML文件中包含指定标签的注释块,需满足以下要求:
- 支持处理多行注释
- 严格保留XML原有格式(包括换行、缩进)
- 保留文件原始编码
现有实现了两个函数:
UncommentXmlNode:移除包裹指定XML内容的<!-- ... -->注释标记,保留内部XMLUncommentMyTwoNodes:批量处理两种特定标签的注释移除
当前测试问题:
- 单个标签独立注释的测试用例运行正常
- 两个标签在同一多行注释中的测试用例执行失败;若修改正则添加
(n)?.*`,则会导致第一个测试用例失效
可复现测试套件
Import-Module Pester Describe "Remove comments"{ BeforeAll { function UncommentXmlNode { param ( [String] $filePath, [String] $innerXmlToUncomment ) $content = Get-Content $filePath -Raw $content -replace "<!--(?<InnerXml>$innerXmlToUncomment)-->", '${InnerXml}' | Set-Content -Path $filePath -Encoding utf8 } function UncommentMyTwoNodes { param ( [xml]$inputXml, [string]$inputXmlPath ) UncommentXmlNode -filePath $inputXmlPath -innerXmlToUncomment "<myFirstOutcommentedXml.*" #Add this to make second test work (`n)?.* UncommentXmlNode -filePath $inputXmlPath -innerXmlToUncomment "<mySecondOutcommentedXml.*" } [xml]$expected = @" <myXml> <!-- comment I want to keep --> <myFirstOutcommentedXml attributeA="xy" attributeB="true" /> <mySecondOutcommentedXml attributeA="xy" attributeB="true" /> <myOtherXmlTag attributeC="value" /> <!-- comment I want to keep --> </myXml> "@ } it "uncomments myFirstOutcommentedXml and mySecondOutcommentedXml"{ [xml]$inputXml = @" <myXml> <!-- comment I want to keep --> <!--<myFirstOutcommentedXml attributeA="xy" attributeB="true" />--> <!--<mySecondOutcommentedXml attributeA="xy" attributeB="true" />--> <myOtherXmlTag attributeC="value" /> <!-- comment I want to keep --> </myXml> "@ $tempPath = "C:\temp\test.xml" $inputXml.Save($tempPath) UncommentMyTwoNodes -inputXml $inputXml -inputXmlPath $tempPath [xml]$result = Get-Content $tempPath $result.OuterXml | Should -be $expected.OuterXml } it "uncomments both if both are in same comment"{ [xml]$inputXml = @" <myXml> <!-- comment I want to keep --> <!--<myFirstOutcommentedXml attributeA="xy" attributeB="true" /> <mySecondOutcommentedXml attributeA="xy" attributeB="true" />--> <myOtherXmlTag attributeC="value" /> <!-- comment I want to keep --> </myXml> "@ $tempPath = "C:\temp\test.xml" $inputXml.Save($tempPath) UncommentMyTwoNodes -inputXml $inputXml -inputXmlPath $tempPath [xml]$result = Get-Content $tempPath $result.OuterXml | Should -be $expected.OuterXml } }
问题分析
原正则表达式<!--(?<InnerXml>$innerXmlToUncomment)-->存在两个核心问题:
- 默认正则模式下,
.无法匹配换行符,因此无法捕获多行注释中的完整内容 - 若直接添加换行匹配或改为贪婪匹配,会导致过度捕获(比如意外包含其他注释或内容),进而破坏第一个测试用例的结果
解决方案
修改UncommentXmlNode函数中的正则逻辑,使用单行模式修饰符(?s)让.匹配换行符,同时使用非贪婪匹配.*?避免过度捕获,同时优化编码保留逻辑:
function UncommentXmlNode { param ( [String] $filePath, [String] $innerXmlToUncomment ) # 读取文件时自动检测并保留原始编码 $fileContent = Get-Content -Path $filePath -Raw -Encoding Byte $encoding = [System.Text.Encoding]::GetEncoding((New-Object System.IO.StreamReader($filePath)).CurrentEncoding.CodePage) $content = $encoding.GetString($fileContent) # 构建正则:单行模式+非贪婪匹配,允许注释前后的空白字符 $regexPattern = "(?s)<!--\s*(?<InnerXml>$innerXmlToUncomment.*?)\s*-->" $newContent = $content -replace $regexPattern, '${InnerXml}' # 写入时使用原始编码 Set-Content -Path $filePath -Value $newContent -Encoding $encoding }
同时优化UncommentMyTwoNodes的匹配规则,避免多余的通配符导致匹配异常:
function UncommentMyTwoNodes { param ( [xml]$inputXml, [string]$inputXmlPath ) UncommentXmlNode -filePath $inputXmlPath -innerXmlToUncomment "<myFirstOutcommentedXml" UncommentXmlNode -filePath $inputXmlPath -innerXmlToUncomment "<mySecondOutcommentedXml" }
修改后,两个测试用例均可正常通过,同时满足格式保留、多行注释支持、编码保留的全部要求。
内容的提问来源于stack exchange,提问作者tomwaitforitmy
相关产品推荐
相关产品推荐

