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('<meta http-equiv="x-ua-compatible" content="IE=9" />');
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[