使用批处理解析 XML 非常痛苦。Batch 并不是一个好的文本处理器。但是,通过一些努力,您通常可以从给定的 XML 文件中提取所需的数据。但是输入文件可以很容易地重新排列成等效的有效 XML 格式,这会破坏您的解析器。
有了这个免责声明......
这是本机批处理解决方案
@echo off
setlocal disableDelayedExpansion
set input="test.xml"
set output="names.txt"
if exist %output% del %output%
for /f "delims=" %%A in ('findstr /n /c:"<con:testSuite name=" %input%') do (
set "ln=%%A"
setlocal enableDelayedExpansion
call :parseLine
endlocal
)
type %output%
exit /b
:parseLine
set "ln2=!ln:*<con:testSuite name=!"
if "!ln2!"=="!ln!" exit /b
for /f tokens^=2^ delims^=^" %%B in ("!ln2!") do (
setlocal disableDelayedExpansion
>>%output% echo(%%B
endlocal
)
set "ln=!ln2!"
goto :parseLine
FINDSTR/N
选项只是为了保证没有行以 a 开头,;
这样我们就不必担心讨厌的默认 FOR "EOL" 选项。
打开和关闭延迟扩展的切换是为了保护!
输入文件中可能存在的任何字符。如果您知道!
从未出现在输入中,那么您可以简单地setlocal enableDelayedExpansion
在顶部删除所有其他setlocal
和endlocal
命令。
最后一个 FOR /F 使用特殊的转义序列来启用将双引号指定为 DELIM 字符。
回答评论中的其他问题
您不能简单地将附加约束放在现有的 FINDSTR 命令中,因为它将返回具有匹配项的整行。请记住您自己说过,“同一行中可能有多个匹配字符串的实例”。第一个名称可能以正确的前缀开头,而同一行中的第二个名称可能不是。您只想保留正确启动的那个。
一种解决方案是简单地更改该echo(%%B >>%output%
行,如下所示:
echo(%%B|findstr "^lp_" >>%output%
FINDSTR 使用正则表达式元字符^
来指定字符串必须以 . 开头lp_
。此时引号已被删除,因此我们不必担心它们。
但是,您将来可能会遇到必须包含"
在搜索字符串中的情况。另外,将屏幕包含在初始 FINDSTR 中可能会稍微快lp_
一些,这样:parseLine
就不会不必要地调用它。
FINDSTR 要求使用反斜杠对搜索字符串双引号进行转义。但是 Windows CMD 处理器也有自己的转义规则。>
需要引用或转义之类的特殊字符。原始代码使用引号,但您想在字符串中包含引号,这会在您的命令中创建不平衡的引号。Windows 批处理通常喜欢成对引用。对于 CMD,至少有一个引号必须转义为^"
. 如果 CMD 和 FINDSTR 都需要对引号进行转义,则它看起来像\^"
.
但是,字符串中不再从 CMD 角度进行功能引用的任何特殊字符也必须使用转义^
。
这是一种转义所有特殊字符的解决方案。它看起来很糟糕而且非常混乱。
for /f "delims=" %%A in ('findstr /n /c:^"^<con:testSuite^ name^=\^"lp_^" %input%') do (
这是另一种看起来更好的解决方案,但是跟踪 CMD 转义的内容和 FINDSTR 转义的内容仍然令人困惑。
for /f "delims=" %%A in ('findstr /n /c:"<con:testSuite name=\"lp_^" %input%') do (
让事情变得更简单的一种方法是将搜索转换为正则表达式。可以使用 搜索单个双引号[\"\"]
。这是一个匹配引号或引号的字符类表达式 - 我知道这很傻。但它保持引号配对,以便 CMD 很高兴。现在您不必担心为 CMD 转义任何字符,您可以专注于正则表达式搜索字符串。
for /f "delims=" %%A in ('findstr /nr /c:"<con:testSuite name=[\"\"]lp_" %input%') do (