2012-06-21 69 views
0

我有一个XML文件,我需要在XML文件中从如何使用Windows批处理

<con:testSuite name="testname" 

所有实例提取

testname 

提取特定的XML标记属性的所有实例。

我不太清楚如何处理这个问题,或者这是否可以批量处理。

这是我迄今认为:

1)使用FINDSTR和存储每个具有

<con:testSuite name= 
在一个变量或临时文件

行,像这样:

FINDSTR /C:"<con:testSuite name=" file.xml > tests.txt 

2)以某种方式使用该文件或变量来提取字符串

请注意,有mi ght是同一行中匹配字符串的多个实例。

我是批处理新手,任何帮助表示赞赏。

+1

您的问题不使用正则表达式,所以我更改了问题标题以更好地匹配您的请求。 – dbenham

回答

3

解析XML对批处理非常痛苦。批处理不是一个好的文本处理器。但是,通过一定的努力,您通常可以从给定的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选项只存在,以保证没有行始于;让我们不必担心烦人的默认FOR“EOL”选项。

打开和关闭延迟扩展的切换是为了保护可能在输入文件中的任何!字符。如果您知道!从不出现在输入中,那么您可以简单地在顶部setlocal enableDelayedExpansion并删除所有其他setlocalendlocal命令。

最后一个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视角不再引用功能的字符串中的任何特殊字符也必须使用^进行转义。

下面是一个解决方案,可以转义所有特殊字符。它看起来很糟糕,很混乱。

这里是另一个解决方案,看起来好多了,但它仍然是混乱跟踪什么逃过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 (
+0

谢谢。我试过了,它似乎工作。我怎样才能得到只有那些以某种模式开始的名字?例如,我只需要以lp_开头的测试名(例如lp_test1,lp_test2等)。我尝试在findtr命令中包含“lp_部分,但我不确定如何转义双引号。” “ 谢谢 –

+1

@AndresDelaBarra - 查看我更新的答案。如果答案符合您的需求,请不要忘记接受答案(点击复选标记)。它让其他人知道这个问题已经回答了,它会给你2分以接受答案,并且给予提供答案的人15分。 – dbenham