在写入文件之前美化 JSON 的 cURL 下载

beautify cURL download of JSON before writing to file

我正在使用 cURL 7.39.0 调用 REST 网络服务并将响应写入 .json 文件:

curl -L-X POST -b cookies.txt -H "Content-Type: application/json" http://localhost:7001/web/service/url -d {"param1":"value1"} -o "C:\output\serviceName.json" 

响应被写入输出文件,但没有格式化:

{"status": "success","user": "name", "regId": "14420","subscriber": [{"memberFor":"3 years","lastLogin":"2 days ago"}]}

我的问题是:

  1. 有没有办法在将 JSON 响应写入输出文件之前对其进行格式化(如下所示)?

    {
        "status": "success",
        "user": "name",
        "regId": "14420",
        "subscriber": [
            {
                "memberFor":"3 years",
                "lastLogin":"2 days ago"     
            }
        ]
    }
    
  2. 如果无法通过 cURL 进行格式化,我希望编写一个简单的批处理文件来自动打开 JSON 输出文件并应用格式化。类似于:

    @echo off
    cls
    "C:\Program Files\Notepad++\notepad++" "C:\output\serviceName.json" 
    pause
    

batch/console 中是否有任何 flags/options 可用以实现此目的?

编辑: 我找到了一个使用 htmlfile COM 对象的解决方案,它应该提供最快的性能(至少对于单个 运行)和不需要互联网连接。请参阅此答案中的最后一个解决方案。


因为你用 [batch-file] 标签标记了这个问题,并且因为我发现这个挑战很有趣,所以我写了一个混合批处理 + JScript 脚本来美化你的 JSON。由于 JScript 5.7 doesn't natively support the JSON object,此脚本使用外部 json2.js,如果尚未下载,则通过 XHR 下载它。从那里开始,调用 JavaScript 熟悉的 JSON.stringify() 方法及其美化选项是一件简单的事情。

语法:

json_generator | batfile.bat
    -or-
batfile.bat < jsonfile.json

用法示例:

beautify.bat < "C:\output\serviceName.json" > "C:\output\beautified.json"

这导致以下内容被保存为 beautified.json:

{  
        "status": "success",
        "user": "name",
        "regId": "14420",
        "subscriber": [
                {
                        "memberFor": "3 years",
                        "lastLogin": "2 days ago"
                }
        ]
}

代码:

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

@echo off & setlocal

cscript /nologo /e:JScript "%~f0"
goto :EOF

@end // end Batch / begin JScript hybrid chimera

var xObj = WSH.CreateObject('Microsoft.XMLHTTP'),
    fso = WSH.CreateObject('Scripting.FileSystemObject'),
    temp = WSH.CreateObject('WScript.Shell').Environment('Process')('temp'),
    j2lib = 'https://raw.githubusercontent.com/douglascrockford/JSON-js/master/json2.js',
    json = WSH.StdIn.ReadAll();

if (fso.FileExists(temp + '\json2.js')) {
    j2lib = fso.OpenTextFile(temp + '\json2.js', 1);
    eval(j2lib.ReadAll());
    j2lib.Close();
}
else {
    with (xObj) {
        open("GET", j2lib, true);
        setRequestHeader('User-Agent', 'XMLHTTP/1.0');
        send('');
    }

    while (xObj.readyState != 4) WSH.Sleep(50);
    eval(xObj.responseText);
    j2lib = fso.CreateTextFile(temp + '\json2.js', true);
    j2lib.Write(xObj.responseText);
    j2lib.Close();
}

WSH.Echo(JSON.stringify(JSON.parse(json), null, '\t'));

这是另一个不需要下载的使用相同语法的解决方案 json2.js。它通过不可见地启动 Internet Explorer,调用 IE 的内置 JSON 方法,然后再次静默关闭 IE 来避免这种情况。这很可能会比上面的方法慢,并且它可能会被阻止,具体取决于机器安全策略;但它确实具有无需 Internet 连接即可工作的优势。

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

@echo off & setlocal

cscript /nologo /e:JScript "%~f0"
goto :EOF

@end // end Batch / begin JScript hybrid chimera

var IE = WSH.CreateObject('InternetExplorer.Application'),
    json = WSH.StdIn.ReadAll();

IE.Visible = 0;
IE.Navigate('about:blank');
while (IE.Busy || IE.ReadyState != 4) WSH.Sleep(25);

var JSON = IE.document.parentWindow.JSON,
    pretty = JSON.stringify(JSON.parse(json), null, "\t");

WSH.Echo(pretty);

IE.Quit();
try { while (IE && IE.Busy) WSH.Sleep(25); }
catch(e) {}

这是另一种解决方案,这次使用批处理/HTA 混合。有一个 <meta> 标签强制 HTA 解释器兼容 IE9,因此包括 支持 JSON 方法。这比 IE 方法更快,但并非完全不可见。 HTA window 在屏幕上闪烁一瞬间,然后自行关闭。

<!-- : batch portion

@echo off & setlocal

rem // The for /f loop forces mshta to communicate with stdout
rem // as a console script host.  Without for /f, attempting
rem // to write to stdout results in an invalid handle error.
for /f "delims=" %%I in ('mshta.exe "%~f0"') do echo(%%I
goto :EOF

end batch / begin HTA : -->

<meta http-equiv="x-ua-compatible" content="IE=9" />
<script>
var fso = new ActiveXObject('Scripting.FileSystemObject'),
    stdin = fso.GetStandardStream(0),
    stdout = fso.GetStandardStream(1),
    json = stdin.ReadAll(),
    pretty = JSON.stringify(JSON.parse(json), null, '\t');

close(stdout.Write(pretty));
</script>

我认为最好的解决方案是使用 scantily-documented htmlfile COM 对象。使用与 <meta> 标记相同的技巧来强制它与 IE9 兼容,如上面的 HTA 解决方案所示,htmlfile COM 对象提供对 JSON 方法的本机支持,而无需下载库,并且没有分叉额外的 windowed 帮助应用程序。它只是加载一个 dll。

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

@echo off & setlocal

cscript /nologo /e:JScript "%~f0"
goto :EOF

@end // end batch / begin JScript hybrid chimera

var htmlfile = WSH.CreateObject('htmlfile'),
    json = WSH.StdIn.ReadAll();

htmlfile.write('<meta http-equiv="x-ua-compatible" content="IE=9" />');

var JSON = htmlfile.parentWindow.JSON,
    pretty = JSON.stringify(JSON.parse(json), null, '\t');

htmlfile.close(WSH.Echo(pretty));

只是对老问题的更新。 https://stedolan.github.io/jq/ 是个不错的工具。默认情况下,jq 漂亮打印 JSON 输出。所以你可以做

curl ... | jq .

“。”是身份过滤器。参见 https://stedolan.github.io/jq/manual/#Invokingjq

我相信这一切都可以用 Xidel 来完成,默认情况下漂亮的打印:

xidel -s --method=POST ^
--load-cookies="cookies.txt" ^
-H "Content-Type: application/json" ^
-d {"param1":"value1"} ^
http://localhost:7001/web/service/url ^
-e "$json"

预期输出:

{
  "status": "success",
  "user": "name",
  "regId": "14420"
  "subscriber": [
    {
      "memberFor":"3 years",
      "lastLogin":"2 days ago"     
    }
  ]
}