Parse simple JSON string in Batch

后端 未结 5 1889
执笔经年
执笔经年 2020-12-16 00:36

How do you parse a simple JSON string in Batch?

For example, if I have the following JSON string:

{ \"...\":\"...\", \"year\": 2016, \"time\": \"05:01\

5条回答
  •  佛祖请我去吃肉
    2020-12-16 01:05

    Here's a hybrid Batch + PowerShell solution. The PowerShell objectifies (deserializes) the JSON text and outputs it in key=value format to be captured and set as batch variables by the batch for /f loop. Save this with a .bat extension and give it a shot.

    <# : batch portion (contained within a PowerShell multi-line comment)
    @echo off & setlocal
    
    set "JSON={ "year": 2016, "time": "05:01" }"
    
    rem # re-eval self with PowerShell and capture results
    for /f "delims=" %%I in ('powershell "iex (${%~f0} | out-string)"') do set "%%~I"
    
    rem # output captured results
    set JSON[
    
    rem # end main runtime
    goto :EOF
    
    : end batch / begin PowerShell hybrid code #>
    
    add-type -AssemblyName System.Web.Extensions
    $JSON = new-object Web.Script.Serialization.JavaScriptSerializer
    $obj = $JSON.DeserializeObject($env:JSON)
    
    # output object in key=value format to be captured by Batch "for /f" loop
    foreach ($key in $obj.keys) { "JSON[{0}]={1}" -f $key, $obj[$key] }
    

    Then if you want only the year and time values, just use %JSON[year]% or %JSON[time]%.

    If you're reading your JSON from a .json file, you could have the PowerShell portion read the file, replacing ($env:JSON) with ((gc jsonfile.json)). Then you wouldn't be dependent at all on whether your JSON is multi-line and beautified or minified. It'll be deserialized all the same either way.


    If execution speed is a concern, you might prefer a Batch + JScript hybrid solution. It deserializes the JSON into an object the same as the PowerShell solution, but invoking JScript from a Batch context is faster than invoking a PowerShell command or script from Batch.

    @if (@CodeSection == @Batch) @then
    @echo off & setlocal
    
    set "JSON={ "year": 2016, "time": "05:01" }"
    
    rem // re-eval self with JScript interpreter and capture results
    for /f "delims=" %%I in ('cscript /nologo /e:JScript "%~f0"') do set "%%~I"
    
    rem // output captured results
    set JSON[
    
    rem // end main runtime
    goto :EOF
    
    @end // end Batch / begin JScript hybrid code
    
    var htmlfile = WSH.CreateObject('htmlfile'),
        txt = WSH.CreateObject('Wscript.Shell').Environment('process').Item('JSON');
    
    htmlfile.write('');
    var obj = htmlfile.parentWindow.JSON.parse(txt);
    htmlfile.close();
    
    for (var i in obj) WSH.Echo('JSON[' + i + ']=' + obj[i]);
    

    And as is the case with the first PowerShell hybrid solution, you can parse multi-line JSON by reading the .json file from within the JScript portion if you wish (by creating a Scripting.FileSystemObject object and calling its .OpenTextFile() and .ReadAll() methods).


    Here's another pure batch solution, but one which sets key=value pairs as an associative array to avoid stomping on %time% as Aacini's solution does. I really think it's better to parse JSON as an object in a helper language rather than as flat text in pure batch, but I also realize that the best answer is not always the most popular.

    @echo off
    setlocal
    
    set "JSON={ "other": 1234, "year": 2016, "value": "str", "time": "05:01" }"
    
    set "JSON=%JSON:~1,-1%"
    set "JSON=%JSON:":=",%"
    
    set mod=0
    for %%I in (%JSON%) do (
        set /a mod = !mod
        setlocal enabledelayedexpansion
        if !mod! equ 0 (
            for %%# in ("!var!") do endlocal & set "JSON[%%~#]=%%~I"
        ) else (
            endlocal & set "var=%%~I"
        )
    )
    
    set JSON[
    

提交回复
热议问题