Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/batch-file/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用纯批处理从单行XML文件中获取多个属性值?_Xml_Batch File - Fatal编程技术网

如何使用纯批处理从单行XML文件中获取多个属性值?

如何使用纯批处理从单行XML文件中获取多个属性值?,xml,batch-file,Xml,Batch File,我需要从一行格式化的XML文件的多个属性中获取值 我已经检查了许多示例,但是由于单行文件的缘故,没有一个真正适合我 首先,我尝试使用findstr命令,但这并没有真正的帮助,因为它总是返回整行(在我的例子中是所有内容),而且显然不可能使用REGEX获取值,而只能找到正确的行。 e、 g.喜欢 findstr /c:"testCase=" test_case_run_log_report.xml 然后我尝试在FOR命令中使用delims和token。如果它确实是根据输入文件指定的,那么这种方法

我需要从一行格式化的XML文件的多个属性中获取值

我已经检查了许多示例,但是由于单行文件的缘故,没有一个真正适合我

首先,我尝试使用findstr命令,但这并没有真正的帮助,因为它总是返回整行(在我的例子中是所有内容),而且显然不可能使用REGEX获取值,而只能找到正确的行。 e、 g.喜欢

findstr /c:"testCase=" test_case_run_log_report.xml 
然后我尝试在FOR命令中使用delims和token。如果它确实是根据输入文件指定的,那么这种方法可能有效,但我需要一种通用方法,因为xml文件每次启动时可能包含更多的“testCaseRunLogTestStep”步骤。这实际上是一个有效的解决方案,至少在XML不会只存储在一行的情况下是这样。 e、 g.(此处的令牌编号不准确,但如前所述,也不能使用此解决方案)

因此,我的想法是将文件内容拆分为“/>”,然后可能运行FOR命令并进行一些处理。但这对我来说太过分了

这就是XML文件的外观

<?xml version="1.0" encoding="UTF-8"?>
<con:testCases testCase="testCase1" timeTaken="201" status="FINISHED" timeStamp="2019-07-25 09:00:47" xmlns:con="http://xx/config"><con:testCaseRunLogTestStep name="testStep1" timeTaken="222" status="OK" timestamp="2019-07-25 09:00:45" httpStatus="200" contentLength="9" readTime="6" totalTime="216" dnsTime="0" connectTime="117" timeToFirstByte="93" httpMethod="GET" />  <con:testCaseRunLogTestStep name="testStep2" timeTaken="528" status="OK" timestamp="2019-07-25 09:00:46" httpStatus="200" contentLength="0" readTime="0" totalTime="529" dnsTime="0" connectTime="1" timeToFirstByte="528" httpMethod="GET"/></con:testCases>
例如:

testStep1=OK
testStep2=OK
我曾经使用过PowerShell,但后来在不同服务器上安装了不同版本的PowerShell时遇到了问题。 所以出于兼容性的原因,我切换到了纯批处理,它在不同的任务中一直工作得很好,直到现在


我自己也是开发人员,但这项任务让我感觉像爱丽丝梦游仙境。

这里有一个批处理文件,只使用Windows命令处理器的内部命令
cmd.exe

@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "XmlFile=test_case_run_log_report.xml"

if not exist "%XmlFile%" (
    echo ERROR: File "%XmlFile%" not found.
    goto :EOF
)

rem Assign last non-empty line of specified XML file not starting
rem with a semicolon to environment variable XmlLine if not longer
rem than 8181 characters. Maximum length of "XmlLine=..." is 8191
rem characters and so maximum value length is 8181 characters.

set "XmlLine="
for /F "usebackq delims=" %%I in ("%XmlFile%") do (
    set "XmlLine=%%I"
    set "NewLine=!XmlLine:"=!"
    if /I "!NewLine!" == "<?xml version=1.0 encoding=UTF-8?>" set "XmlLine="
)
if not defined XmlLine (
    echo ERROR: File "%XmlFile%" is empty or contains too much data.
    goto :EOF
)

for %%I in ("%XmlFile%") do set "ResultFile=%%~dpnI.txt"
del "%ResultFile%" 2>nul

rem Remove everything from beginning of line to end of the string between *
rem and = and assign this remaining part of the line to variable NewLine.
rem If nothing was removed, there is no more tag con:testCaseRunLogTestStep
rem with a space and attribute name in remaining line. Otherwise get values
rem of attribute name and status and output both into result file.

:GetNameStatus
set "NewLine=!XmlLine:*<con:testCaseRunLogTestStep name=!"
if not "!NewLine!" == "!XmlLine!" (
    set "XmlLine=!NewLine!"
    for /F "tokens=1,5 delims== " %%I in ("!XmlLine!") do echo %%~I=%%~J>>"%ResultFile%"
    goto GetNameStatus
)

rem Delete result file if existing but file size is less or equal 2 bytes.
if exist "%ResultFile%" for %%I in ("%ResultFile%") do if %%~zI LEQ 2 del "%ResultFile%"

if not exist "%ResultFile%" (
    echo ERROR: No element con:testCaseRunLogTestStep with attributes name and status
    echo        found in file "%XmlFile%".
)
endlocal
此解决方案适用于单行和多行XML文件,无行长度限制(可用的空闲RAM除外)。在元素
con:testCaseRunLogTestStep
中,属性
name
status
的位置也更灵活,只要该元素包含第一个
name
和下一个
status

cscript.exe
执行的区分大小写的JScript搜索正则表达式表示:

  • [\s\s]*?
    。。。任何空格或任何非空格字符0次或以上非贪婪。所以这个表达式将从文件开头或上一个匹配的结尾到
    的所有内容匹配一次或多次。因此,这个表达式将start标记之后的所有内容匹配到标记中的属性
    name
  • name=\x22
    。。。必须在下一个字符串
    name=“
    中找到正匹配。双引号字符是使用其十六进制表示形式指定的,作为参数字符串,在Windows命令行上通常不能包含
  • 。。。第一标记组。此第一个标记组中的表达式找到的字符串在替换字符串中被
    $1
    反向引用
  • [^\x22]+
    。。。除
    以外的任何字符都可以使用一次或多次。此表达式与属性名称的值匹配
  • [^>]+?
    …就像前面的任何字符不是
    一次或多次非贪婪。因此,此表达式匹配标记中从属性
    名称
    的值之后的
    到属性
    状态的所有内容
  • 状态=\x22
    。。。接下来必须找到字符串
    status=“
    ”以进行正匹配
  • …第二个标记组。此第二个标记组中的表达式找到的字符串在替换字符串中被
    $2
    反向引用
  • [^\x22]+
    …与任何字符之前的相同,除了
    一次或多次。此表达式与属性
    状态
    的值匹配
  • [^>]+>
    。。。任何字符不是
    一次或多次出现
    ,然后出现
    。此表达式匹配从属性值
    状态
    之后的
    到内联元素末尾的所有内容
    con:testCaseRunLogTestStep
  • (?:
    )?
    …非标记组匹配(可选)
  • \s*\s*
    …任何空格字符0次或更多次,字符串
    再次任何空格字符0次或更多次。此可选应用表达式将
    con:testcase runlogteststep
    的最后一个标记后的所有内容匹配到文件结尾,只要文件以结束标记
    结尾
其他解决方案也可以使用JScript使用JREPL.BATJREPL.BAT。这只是一个在我的测试中使用的解决方案,提供了示例文件内容及其变体


要了解所使用的命令及其工作方式,请打开命令提示符窗口,在其中执行以下命令,并非常仔细地阅读为每个命令显示的所有帮助页面

  • 呼叫/?
  • del/?
  • echo/?
  • endlocal/?
  • 获取/?
  • goto/?
  • 如果/?
  • rem/?
  • 设置/?
  • setlocal/?
  • jrepl.bat/?
testStep1=OK
testStep2=OK
@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "XmlFile=test_case_run_log_report.xml"

if not exist "%XmlFile%" (
    echo ERROR: File "%XmlFile%" not found.
    goto :EOF
)

rem Assign last non-empty line of specified XML file not starting
rem with a semicolon to environment variable XmlLine if not longer
rem than 8181 characters. Maximum length of "XmlLine=..." is 8191
rem characters and so maximum value length is 8181 characters.

set "XmlLine="
for /F "usebackq delims=" %%I in ("%XmlFile%") do (
    set "XmlLine=%%I"
    set "NewLine=!XmlLine:"=!"
    if /I "!NewLine!" == "<?xml version=1.0 encoding=UTF-8?>" set "XmlLine="
)
if not defined XmlLine (
    echo ERROR: File "%XmlFile%" is empty or contains too much data.
    goto :EOF
)

for %%I in ("%XmlFile%") do set "ResultFile=%%~dpnI.txt"
del "%ResultFile%" 2>nul

rem Remove everything from beginning of line to end of the string between *
rem and = and assign this remaining part of the line to variable NewLine.
rem If nothing was removed, there is no more tag con:testCaseRunLogTestStep
rem with a space and attribute name in remaining line. Otherwise get values
rem of attribute name and status and output both into result file.

:GetNameStatus
set "NewLine=!XmlLine:*<con:testCaseRunLogTestStep name=!"
if not "!NewLine!" == "!XmlLine!" (
    set "XmlLine=!NewLine!"
    for /F "tokens=1,5 delims== " %%I in ("!XmlLine!") do echo %%~I=%%~J>>"%ResultFile%"
    goto GetNameStatus
)

rem Delete result file if existing but file size is less or equal 2 bytes.
if exist "%ResultFile%" for %%I in ("%ResultFile%") do if %%~zI LEQ 2 del "%ResultFile%"

if not exist "%ResultFile%" (
    echo ERROR: No element con:testCaseRunLogTestStep with attributes name and status
    echo        found in file "%XmlFile%".
)
endlocal
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "XmlFile=test_case_run_log_report.xml"

if not exist "%XmlFile%" (
    echo ERROR: File "%XmlFile%" not found.
    goto :EOF
)
if not exist "%~dp0jrepl.bat" (
    echo ERROR: Batch file "%~dp0jrepl.bat" not found.
    goto :EOF
)

for %%I in ("%XmlFile%") do (
    set "ResultFile=%%~dpnI.txt"
    set "XmlFileSize=%%~zI"
)
del "%ResultFile%" 2>nul

call "%~dp0jrepl.bat" "[\s\S]*?<con:testCaseRunLogTestStep[\s\S]+?name=\x22([^\x22]+)[^>]+?status=\x22([^\x22]+)[^>]+>(?:\s*</con:testCases>\s*)?" "$1=$2\r\n" /M /XSEQ /F "%XmlFile%" /O "%ResultFile%"

if exist "%ResultFile%" for %%I in ("%ResultFile%") do if %%~zI == %XmlFileSize% del "%ResultFile%"

if not exist "%ResultFile%" (
    echo ERROR: No element con:testCaseRunLogTestStep with attributes name and status
    echo        found in file "%XmlFile%".
)
endlocal