【问题标题】:How to extract all instances of a specific XML tag attribute using Windows batch如何使用 Windows 批处理提取特定 XML 标记属性的所有实例
【发布时间】:2012-06-21 15:18:00
【问题描述】:

我有一个 XML 文件,我需要提取

testname

来自所有的实例

<con:testSuite name="testname" 

在 XML 文件中。

我不太确定如何解决这个问题,或者这是否可以批量处理。

这是我目前的想法:

1) 使用 FINDSTR 并存储具有

的每一行
<con:testSuite name=

在变量或临时文件中,像这样:

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

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

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

我是批处理新手,不胜感激。

【问题讨论】:

  • 您的问题没有使用正则表达式,所以我更改了问题标题以更好地匹配您的要求。

标签: batch-file


【解决方案1】:

使用批处理解析 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 选项仅用于保证没有任何行以 ; 开头,这样我们就不必担心烦人的默认 FOR "EOL" 选项。

延迟扩展的开启和关闭切换是为了保护输入文件中可能存在的任何! 字符。如果您知道! 永远不会出现在输入中,那么您只需将setlocal enableDelayedExpansion 放在顶部并删除所有其他setlocalendlocal 命令。

最后一个 FOR /F 使用特殊的转义序列来将双引号指定为 DELIM 字符。

在评论中回答其他问题

您不能简单地将附加约束放在现有的 FINDSTR 命令中,因为它将返回具有匹配项的整行。记得你自己说过,“在同一行中可能有多个匹配字符串的实例”。第一个名称可能以正确的前缀开头,而同一行中的第二个名称可能不是。您只想保留正确启动的那个。

一种解决方案是简单地将echo(%%B &gt;&gt;%output% 行更改如下:

echo(%%B|findstr "^lp_" >>%output%

FINDSTR 使用正则表达式元字符^ 来指定字符串必须以lp_ 开头。此时引号已被删除,因此我们不必担心它们。

但是,您将来可能会遇到必须在搜索字符串中包含 " 的情况。此外,在初始 FINDSTR 中包含 lp_ 屏幕可能会稍微快一些,这样就不会不必要地调用 :parseLine

FINDSTR 要求搜索字符串双引号用反斜杠转义。但是 Windows CMD 处理器也有自己的转义规则。像&gt; 这样的特殊字符需要被引用或转义。原始代码使用引号,但您想在字符串中包含引号,这会在您的命令中创建不平衡的引号。 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 (

【讨论】:

  • 谢谢。我试过了,它似乎工作。我将如何只获得以某种模式开头的名称?例如,我只想要以 lp_ 开头的测试名称(例如 lp_test1、lp_test2 等)。我尝试在 findstr 命令中包含 "lp_ 部分,但我不确定如何转义双引号。这不起作用` findstr /n /c:"
  • @AndresDelaBarra - 查看我更新的答案。如果答案符合您的需求,请不要忘记接受答案(单击复选标记)。它让其他人知道问题已被回答,它会奖励您接受答案的 2 分,并奖励 15 分给提供答案的人。
猜你喜欢
  • 2018-07-27
  • 1970-01-01
  • 2014-02-15
  • 2017-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多