BATCH脚本 - 读取XML并为同一标记/元素返回多个值,并将其作为变量传递

时间:2021-04-23 10:03:21

Here is code which gives reads ONLY the last TargetEndpoint tag in the xml file and gives the output as - Facebook

下面是代码,它只读取xml文件中的最后一个TargetEndpoint标记,并将输出显示为 - Facebook

@echo off
setlocal enableextensions EnableDelayedExpansion
set input="TP.xml"

for /f "tokens=3 delims=<> " %%i in ('type %input% ^|find "TargetEndpoint"') do set "targetsName=%%i"
echo %targetsName%"

We want the ability to read all the TargetEndpoint tags and output as to pass it to a batch script as an array of variables-- Apple, Google, Microsoft, Adobe, Facebook

我们希望能够读取所有TargetEndpoint标签和输出,并将其作为变量数组传递给批处理脚本 - Apple,Google,Microsoft,Adobe,Facebook

XML file for reference:

XML文件供参考:

  <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <Name revision="1" name="myname">
    <ConfigurationVersion majorVersion="4" minorVersion="0"/>
    <Description>myxml</Description>
    <Policies>
        <!--test1 -->
    </Policies> 
    <Resources>
         <!--test1 -->
    </Resources>
    <TargetServers/>
    <TargetEndpoints>
        <TargetEndpoint>Apple</TargetEndpoint>
        <TargetEndpoint>Google</TargetEndpoint>
        <TargetEndpoint>Microsoft</TargetEndpoint>
        <TargetEndpoint>Adobe</TargetEndpoint>
        <TargetEndpoint>Facebook</TargetEndpoint>
    </TargetEndpoints>
    <validate>false</validate>
</Name> 

2 个解决方案

#1


0  

I recommend parsing your XML as XML, rather than tokenizing and scraping it as text. If you parse it as XML, then the success of your script won't be so dependent upon whether the XML is beautified, uglified, minified, whatever. Since the batch language has no easy way to interpret the XML DOM, you can borrow from Windows Script Host by using a batch + JScript hybrid script. Save this with a .bat extension and give it a try.

我建议将XML解析为XML,而不是将其标记化并将其作为文本进行拼接。如果您将其解析为XML,那么您的脚本的成功将不会取决于XML是否被美化,丑化,缩小等等。由于批处理语言没有简单的方法来解释XML DOM,因此可以使用批处理+ JScript混合脚本从Windows脚本宿主中借用。使用.bat扩展名保存并尝试一下。

@if (@CodeSection == @Batch) @then

@echo off
setlocal

set "XMLfile=test.xml"
set "nodes=TargetEndpoint"

rem // build array of text node values for TargetEndpoint nodes
set "Ubound=-1"

for /f "delims=" %%I in (
    'cscript /nologo /e:JScript "%~f0" "%XMLfile%" "%nodes%"'
) do (
    set "%%I"
    set /a Ubound += 1
)

rem // display array
set %nodes%

rem // demonstrate retrieval of a value
setlocal enabledelayedexpansion
echo Last element: %nodes%[%Ubound%] = !%nodes%[%Ubound%]!
endlocal

goto :EOF
@end // end batch / begin JScript chimera

String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, ''); }

var DOM = WSH.CreateObject('Microsoft.XMLDOM'),
    args = { file: WSH.Arguments(0), node: WSH.Arguments(1) },
    XPath = "//" + args.node + "/text()";

DOM.load(args.file);
DOM.async = false;
DOM.setProperty('SelectionLanguage', 'XPath');

if (DOM.parseError.errorCode) {
    var e = DOM.parseError;
    WSH.StdErr.WriteLine('Error in ' + args.file + ' line ' + e.line + ' char '
        + e.linepos + ':\n' + e.reason + '\n' + e.srcText);
    WSH.Quit(1);
}

for (var d = DOM.selectNodes(XPath), i = 0; i < d.length; i++) {
    WSH.Echo(args.node + '[' + i + ']=' + d[i].nodeValue.trim());
}

You could actually do something similar with PowerShell with a one-liner. If the structure of your XML is static and you don't need to search via XPath, you could do something like this:

实际上你可以用PowerShell做一些类似的东西。如果XML的结构是静态的,并且您不需要通过XPath进行搜索,那么您可以执行以下操作:

powershell "[xml]$x = (gc test.xml); $x.Name.TargetEndpoints.TargetEndpoint"

Or if an XPath is needed to select the TargetEndpoint nodes:

或者,如果需要XPath来选择TargetEndpoint节点:

powershell "select-xml '//TargetEndpoint/text()' test.xml | %{ $_.node.data }"

Be advised that PowerShell's XML parser is more strict than the Microsoft.XMLDOM COM object. Your example XML above would error with the PowerShell XML parser because the <?xml?> declaration is preceded by whitespace. Jscript, on the other hand, doesn't seem to care.

请注意,PowerShell的XML解析器比Microsoft.XMLDOM COM对象更严格。上面的示例XML会因Pow​​erShell XML解析器而出错,因为 声明前面有空格。另一方面,Jscript似乎并不关心。

#2


0  

Your issue is just a simple bracket problem. You need to group the set and the echo commands inside the loop, this will print each as it loops through. It currently only prints facebook as thats the last one it finds in the list and is what is stored in the variable once the loop has finished.

您的问题只是一个简单的括号问题。您需要在循环内对set和echo命令进行分组,这将在循环时打印每个命令。它目前只打印facebook,因为它是列表中找到的最后一个,并且一旦循环结束就存储在变量中。

For example:

    @echo off
setlocal enableextensions EnableDelayedExpansion
set input="TP.xml"

for /F "tokens=3 delims=<>" %%I in ('type %input% ^|find "TargetEndpoint"') do (
    set targetendpoint=%%I
    echo !targetendpoint!
)

#1


0  

I recommend parsing your XML as XML, rather than tokenizing and scraping it as text. If you parse it as XML, then the success of your script won't be so dependent upon whether the XML is beautified, uglified, minified, whatever. Since the batch language has no easy way to interpret the XML DOM, you can borrow from Windows Script Host by using a batch + JScript hybrid script. Save this with a .bat extension and give it a try.

我建议将XML解析为XML,而不是将其标记化并将其作为文本进行拼接。如果您将其解析为XML,那么您的脚本的成功将不会取决于XML是否被美化,丑化,缩小等等。由于批处理语言没有简单的方法来解释XML DOM,因此可以使用批处理+ JScript混合脚本从Windows脚本宿主中借用。使用.bat扩展名保存并尝试一下。

@if (@CodeSection == @Batch) @then

@echo off
setlocal

set "XMLfile=test.xml"
set "nodes=TargetEndpoint"

rem // build array of text node values for TargetEndpoint nodes
set "Ubound=-1"

for /f "delims=" %%I in (
    'cscript /nologo /e:JScript "%~f0" "%XMLfile%" "%nodes%"'
) do (
    set "%%I"
    set /a Ubound += 1
)

rem // display array
set %nodes%

rem // demonstrate retrieval of a value
setlocal enabledelayedexpansion
echo Last element: %nodes%[%Ubound%] = !%nodes%[%Ubound%]!
endlocal

goto :EOF
@end // end batch / begin JScript chimera

String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, ''); }

var DOM = WSH.CreateObject('Microsoft.XMLDOM'),
    args = { file: WSH.Arguments(0), node: WSH.Arguments(1) },
    XPath = "//" + args.node + "/text()";

DOM.load(args.file);
DOM.async = false;
DOM.setProperty('SelectionLanguage', 'XPath');

if (DOM.parseError.errorCode) {
    var e = DOM.parseError;
    WSH.StdErr.WriteLine('Error in ' + args.file + ' line ' + e.line + ' char '
        + e.linepos + ':\n' + e.reason + '\n' + e.srcText);
    WSH.Quit(1);
}

for (var d = DOM.selectNodes(XPath), i = 0; i < d.length; i++) {
    WSH.Echo(args.node + '[' + i + ']=' + d[i].nodeValue.trim());
}

You could actually do something similar with PowerShell with a one-liner. If the structure of your XML is static and you don't need to search via XPath, you could do something like this:

实际上你可以用PowerShell做一些类似的东西。如果XML的结构是静态的,并且您不需要通过XPath进行搜索,那么您可以执行以下操作:

powershell "[xml]$x = (gc test.xml); $x.Name.TargetEndpoints.TargetEndpoint"

Or if an XPath is needed to select the TargetEndpoint nodes:

或者,如果需要XPath来选择TargetEndpoint节点:

powershell "select-xml '//TargetEndpoint/text()' test.xml | %{ $_.node.data }"

Be advised that PowerShell's XML parser is more strict than the Microsoft.XMLDOM COM object. Your example XML above would error with the PowerShell XML parser because the <?xml?> declaration is preceded by whitespace. Jscript, on the other hand, doesn't seem to care.

请注意,PowerShell的XML解析器比Microsoft.XMLDOM COM对象更严格。上面的示例XML会因Pow​​erShell XML解析器而出错,因为 声明前面有空格。另一方面,Jscript似乎并不关心。

#2


0  

Your issue is just a simple bracket problem. You need to group the set and the echo commands inside the loop, this will print each as it loops through. It currently only prints facebook as thats the last one it finds in the list and is what is stored in the variable once the loop has finished.

您的问题只是一个简单的括号问题。您需要在循环内对set和echo命令进行分组,这将在循环时打印每个命令。它目前只打印facebook,因为它是列表中找到的最后一个,并且一旦循环结束就存储在变量中。

For example:

    @echo off
setlocal enableextensions EnableDelayedExpansion
set input="TP.xml"

for /F "tokens=3 delims=<>" %%I in ('type %input% ^|find "TargetEndpoint"') do (
    set targetendpoint=%%I
    echo !targetendpoint!
)