バッチファイル(.bat)はテキスト処理が得意ですが、構造化データである JSON や XML を直接パースする機能はありません。しかし findstr による簡易検索 と PowerShell の ConvertFrom-Json / [xml] キャスト を組み合わせることで、追加ツールなしでも実用的な JSON/XML 処理が実現できます。本記事では値の取得・ネストアクセス・配列処理・変数格納・条件分岐まで体系的に解説します。
- JSON・XML ファイルから特定のキー/タグの値を取得する方法
- ネストされたオブジェクト・配列の値を取り出す方法
- 取得した値をバッチの変数に格納して後続処理に使う方法
- JSON の値で条件分岐・ループ処理を行う方法
- XML 設定ファイルから複数の値を読み込む方法
- API レスポンス(JSON)のエラーコードを確認する方法
方法の比較
| 方法 | 向き不向き | 特徴 |
|---|---|---|
findstr |
シンプルな行検索・キー存在確認 | 軽い・正確なパースは不可 |
PowerShell ConvertFrom-Json |
JSON の値取得・ネスト・配列 | 確実・Win7 以降 |
PowerShell [xml] キャスト |
XML の DOM 操作・XPath 検索 | 確実・属性もアクセス可 |
方法1: findstr で簡易検索(テキストとして処理)
JSON・XML をテキストとして扱い、特定キーワードを含む行を抽出します。構造は無視するためシンプルな確認や存在チェックに向いています。
キーワードを含む行を抽出
@echo off rem JSON ファイルから "version" を含む行を抽出 findstr /i /c:"version" config.json rem XML ファイルから <title> タグを含む行を抽出 findstr /i /c:"<title>" config.xml
値の存在チェック(条件分岐)
@echo off
rem "status": "error" が含まれているかチェック
findstr /i /c:""status": "error"" response.json >nul 2>&1
if not errorlevel 1 (
echo [ERROR] レスポンスにエラーが含まれています
exit /b 1
) else (
echo [OK] エラーなし
)
findstr で値の行だけ取り出してスライス
@echo off
setlocal enabledelayedexpansion
rem "version": "1.2.3" のような行から値部分を抽出する簡易パース
for /f "tokens=2 delims=:, " %%V in ('findstr /i /c:"version" config.json') do (
rem クォートを除去
set "VER=%%~V"
goto :got_ver
)
:got_ver
echo バージョン: %VER%
endlocal
findstr はテキスト行を抽出するだけで、JSON/XML の構造を理解しません。
同じキーが複数行に現れる・値にコロンやスペースが含まれる・改行なしの JSON(1行JSON)などでは誤った値を取得します。
正確な処理が必要な場合は PowerShell を使ってください。
方法2: PowerShell で JSON を処理する
PowerShell の ConvertFrom-Json は JSON を .NET オブジェクトに変換し、ドット記法でプロパティにアクセスできます。
基本: トップレベルの値を取得
@echo off
setlocal
rem config.json の内容例:
rem { "version": "1.2.3", "env": "production" }
for /f "usebackq delims=" %%A in (`
powershell -NoProfile -Command ^
"(Get-Content config.json -Raw | ConvertFrom-Json).version"
`) do set "VERSION=%%A"
echo バージョン: %VERSION%
endlocal
ネストしたオブジェクトの値を取得
@echo off
setlocal
rem config.json の内容例:
rem { "app": { "settings": { "theme": "dark", "lang": "ja" } } }
for /f "usebackq delims=" %%A in (`
powershell -NoProfile -Command ^
"(Get-Content config.json -Raw | ConvertFrom-Json).app.settings.theme"
`) do set "THEME=%%A"
echo テーマ: %THEME%
endlocal
配列の要素を取得
@echo off
setlocal
rem config.json の内容例:
rem { "servers": ["192.168.1.1", "192.168.1.2", "192.168.1.3"] }
rem 最初の要素(インデックス 0)
for /f "usebackq delims=" %%A in (`
powershell -NoProfile -Command ^
"(Get-Content config.json -Raw | ConvertFrom-Json).servers[0]"
`) do set "SERVER1=%%A"
echo 1台目: %SERVER1%
rem 配列を全件ループして表示
for /f "usebackq delims=" %%A in (`
powershell -NoProfile -Command ^
"(Get-Content config.json -Raw | ConvertFrom-Json).servers | ForEach-Object { $_ }"
`) do (
echo サーバー: %%A
)
endlocal
複数の値を一括取得して変数に格納
@echo off
setlocal enabledelayedexpansion
rem JSON の複数フィールドを一度に取得(区切り文字で1行に出力)
for /f "usebackq tokens=1,2 delims=|" %%A in (`
powershell -NoProfile -Command ^
"$j = Get-Content config.json -Raw | ConvertFrom-Json;" ^
"$($j.version)|$($j.env)"
`) do (
set "VERSION=%%A"
set "ENV=%%B"
)
echo バージョン: %VERSION%
echo 環境: %ENV%
endlocal
JSON の全キーを列挙する
@echo off
rem JSON のトップレベルキーを一覧表示
for /f "usebackq delims=" %%K in (`
powershell -NoProfile -Command ^
"(Get-Content config.json -Raw | ConvertFrom-Json).PSObject.Properties.Name"
`) do (
echo キー: %%K
)
JSON の配列件数を取得
@echo off
setlocal
for /f "usebackq delims=" %%N in (`
powershell -NoProfile -Command ^
"(Get-Content config.json -Raw | ConvertFrom-Json).items.Count"
`) do set "COUNT=%%N"
echo アイテム数: %COUNT%
endlocal
方法3: PowerShell で XML を処理する
[xml] キャストで XML を DOM オブジェクトに変換し、タグ名・属性へのアクセスができます。
基本: 要素の値を取得
@echo off
setlocal
rem config.xml の内容例:
rem <configuration>
rem <appSettings>
rem <add key="Version" value="1.0.0" />
rem </appSettings>
rem </configuration>
for /f "usebackq delims=" %%A in (`
powershell -NoProfile -Command ^
"([xml](Get-Content config.xml)).configuration.appSettings.add.value"
`) do set "VALUE=%%A"
echo 値: %VALUE%
endlocal
属性で絞り込んで値を取得(Where-Object)
@echo off
setlocal
rem config.xml:
rem <add key="DbServer" value="localhost" />
rem <add key="DbName" value="mydb" />
rem key="DbServer" の value を取得
for /f "usebackq delims=" %%A in (`
powershell -NoProfile -Command ^
"$x = [xml](Get-Content config.xml);" ^
"($x.configuration.appSettings.add | Where-Object { $_.key -eq DbServer }).value"
`) do set "DBSERVER=%%A"
echo DBサーバー: %DBSERVER%
endlocal
複数の要素をループ処理
@echo off
rem <add> 要素を全件ループして key=value を表示
for /f "usebackq delims=" %%A in (`
powershell -NoProfile -Command ^
"$x = [xml](Get-Content config.xml);" ^
"$x.configuration.appSettings.add |" ^
"ForEach-Object { $($_.key)=$($_.value) }"
`) do (
echo %%A
)
XPath で要素を取得
@echo off
setlocal
rem SelectSingleNode で XPath 検索
for /f "usebackq delims=" %%A in (`
powershell -NoProfile -Command ^
"$x = [xml](Get-Content config.xml);" ^
"$x.SelectSingleNode(//add[@key=""""Version""""]).value"
`) do set "VER=%%A"
echo バージョン(XPath): %VER%
endlocal
方法4: 取得した値で条件分岐する
@echo off
setlocal enabledelayedexpansion
rem config.json の "env" の値で処理を切り替え
for /f "usebackq delims=" %%A in (`
powershell -NoProfile -Command ^
"(Get-Content config.json -Raw | ConvertFrom-Json).env"
`) do set "ENV=%%A"
echo 環境: %ENV%
if /i "%ENV%"=="production" (
echo [本番環境] 本番設定を適用します
rem 本番向けの処理...
) else if /i "%ENV%"=="staging" (
echo [ステージング環境] ステージング設定を適用します
) else (
echo [開発環境] 開発設定を適用します
)
endlocal
方法5: JSON を出力・更新する
PowerShell の ConvertTo-Json を使って JSON ファイルを生成・更新できます。
JSON ファイルを新規生成
@echo off
rem JSON ファイルを新規作成
powershell -NoProfile -Command ^
"@{ version = 1.0.0; env = production; date = (Get-Date -Format yyyy-MM-dd) }" ^
"| ConvertTo-Json | Set-Content output.json -Encoding UTF8"
echo output.json を作成しました
type output.json
既存 JSON の特定キーを更新
@echo off
setlocal
set "NEW_VER=2.0.0"
rem "version" キーの値を更新して上書き保存
powershell -NoProfile -Command ^
"$j = Get-Content config.json -Raw | ConvertFrom-Json;" ^
"$j.version = %NEW_VER%;" ^
"$j | ConvertTo-Json -Depth 10 | Set-Content config.json -Encoding UTF8"
echo バージョンを %NEW_VER% に更新しました
endlocal
実践例A: config.json からバージョンを取得してビルドフォルダを作成
@echo off
setlocal enabledelayedexpansion
cd /d "%~dp0"
set "CONFIG=config.json"
if not exist "%CONFIG%" (
echo [ERROR] %CONFIG% が見つかりません
exit /b 1
)
rem バージョン取得
for /f "usebackq delims=" %%A in (`
powershell -NoProfile -Command ^
"(Get-Content %CONFIG% -Raw | ConvertFrom-Json).version"
`) do set "VER=%%A"
if "%VER%"=="" (
echo [ERROR] バージョンを取得できませんでした
exit /b 1
)
rem 環境取得
for /f "usebackq delims=" %%A in (`
powershell -NoProfile -Command ^
"(Get-Content %CONFIG% -Raw | ConvertFrom-Json).env"
`) do set "ENV=%%A"
echo バージョン: %VER%
echo 環境: %ENV%
rem ビルドフォルダを作成
set "BUILD_DIR=build\%VER%_%ENV%"
if not exist "%BUILD_DIR%" mkdir "%BUILD_DIR%"
echo ビルドフォルダ作成: %BUILD_DIR%
endlocal
実践例B: API レスポンス(JSON)のエラーコードをチェック
@echo off
setlocal enabledelayedexpansion
rem curl で API を呼び出して JSON レスポンスをファイルに保存
curl -s -o response.json -w "%%{http_code}" https://api.example.com/status > http_code.tmp 2>nul
rem HTTP ステータスコードを確認
set /p HTTP_CODE=<http_code.tmp
del /q http_code.tmp
if not "%HTTP_CODE%"=="200" (
echo [ERROR] HTTP %HTTP_CODE%
exit /b 1
)
rem JSON から status フィールドを取得
for /f "usebackq delims=" %%A in (`
powershell -NoProfile -Command ^
"(Get-Content response.json -Raw | ConvertFrom-Json).status"
`) do set "STATUS=%%A"
rem JSON から message フィールドを取得
for /f "usebackq delims=" %%A in (`
powershell -NoProfile -Command ^
"(Get-Content response.json -Raw | ConvertFrom-Json).message"
`) do set "MESSAGE=%%A"
echo ステータス: %STATUS%
echo メッセージ: %MESSAGE%
if /i not "%STATUS%"=="ok" (
echo [ERROR] API エラー: %MESSAGE%
exit /b 1
)
echo [OK] API 正常
endlocal
実践例C: XML 設定ファイルから複数の接続情報を読み込む
@echo off
setlocal enabledelayedexpansion
rem db_config.xml の内容例:
rem <config>
rem <database server="db01.example.com" port="5432" name="mydb" user="app" />
rem </config>
set "XMLFILE=db_config.xml"
if not exist "%XMLFILE%" (
echo [ERROR] %XMLFILE% が見つかりません
exit /b 1
)
rem 複数の属性を一度に取得(| 区切りで1行に出力)
for /f "usebackq tokens=1,2,3,4 delims=|" %%A in (`
powershell -NoProfile -Command ^
"$x = [xml](Get-Content %XMLFILE%);" ^
"$db = $x.config.database;" ^
"$($db.server)|$($db.port)|$($db.name)|$($db.user)"
`) do (
set "DB_SERVER=%%A"
set "DB_PORT=%%B"
set "DB_NAME=%%C"
set "DB_USER=%%D"
)
echo === データベース接続情報 ===
echo サーバー: %DB_SERVER%
echo ポート: %DB_PORT%
echo DB名: %DB_NAME%
echo ユーザー: %DB_USER%
endlocal
よくある落とし穴
落とし穴1: for /f は空行を読み飛ばす
rem PowerShell の出力に空行が含まれると for /f がスキップする
rem 例: ConvertFrom-Json の出力が複数行になった場合
rem 対策: 値を明示的に文字列化して1行に収める
for /f "usebackq delims=" %%A in (`
powershell -NoProfile -Command ^
"[string](Get-Content config.json -Raw | ConvertFrom-Json).version"
`) do set "VER=%%A"
落とし穴2: シングルクォートの扱い(PowerShell と bat の混在)
rem bat からPowerShell を呼ぶとき、PowerShell 内のシングルクォートは (2個) でエスケープ
rem NG: シングルクォートを1個だけ使うと bat がコマンドを分割してしまう
powershell -Command "$x = value" ← これは bat の for /f バッククォートと混同しやすい
rem OK: -Command の中のシングルクォートは で記述
powershell -NoProfile -Command ^
"($j.items | Where-Object { $_.name -eq target }).value"
落とし穴3: 日本語・マルチバイト文字の文字化け
rem PowerShell の出力をパイプすると文字化けする場合がある
rem 対策1: Get-Content に -Encoding UTF8 を指定
for /f "usebackq delims=" %%A in (`
powershell -NoProfile -Command ^
"(Get-Content config.json -Encoding UTF8 -Raw | ConvertFrom-Json).name"
`) do set "NAME=%%A"
rem 対策2: PowerShell のコードページを UTF-8 に設定
chcp 65001 >nul
powershell -NoProfile -Command "..."
落とし穴4: JSON が1行(ミニファイ)されている場合
rem ConvertFrom-Json は整形済み・1行 JSON どちらも処理できる
rem findstr や for /f のテキスト行分割は1行JSONで失敗する
rem 1行JSON でも ConvertFrom-Json は正しく動作する
rem {"version":"1.0","env":"prod"} → Get-Content で1行読んでも ConvertFrom-Json OK
for /f "usebackq delims=" %%A in (`
powershell -NoProfile -Command ^
"(Get-Content config.json -Raw | ConvertFrom-Json).version"
`) do set "VER=%%A"
落とし穴5: ハット(^)のエスケープ漏れで長いコマンドが失敗する
rem bat で複数行に分けるとき ^ で行継続するが、^ の前後にスペースが必要
rem NG: ^ の後ろに改行以外の文字があるとエラー
powershell -Command ^
"$j = Get-Content config.json -Raw | ConvertFrom-Json; $j.version" ^
rem ↑ 最後の ^ のあとにコメントがあるのでエラー
rem OK: ^ は行末に置き、次の行は文字列の続きから始める
powershell -NoProfile -Command ^
"$j = Get-Content config.json -Raw | ConvertFrom-Json;" ^
"$j.version"
よくある質問(FAQ)
バッチ単体では JSON の正確なパースはできません。findstr での簡易検索(行単位)か、jq(軽量 JSON プロセッサ)を外部ツールとして導入するか、PowerShell を使うかの3択です。PowerShell は Windows 7 以降に標準搭載されているため、通常は追加インストール不要です。
PowerShell で配列要素を1行ずつ出力し、for /f で受け取ります。
@echo off
rem {"servers": ["192.168.1.1", "192.168.1.2", "192.168.1.3"]}
for /f "usebackq delims=" %%S in (`
powershell -NoProfile -Command ^
"(Get-Content config.json -Raw | ConvertFrom-Json).servers | ForEach-Object { $_ }"
`) do (
echo サーバー: %%S
rem %%S に対して処理を記述
)
名前空間付きの XML は NamespaceManager を使うか、ワイルドカード XPath //*[local-name()=tag] でアクセスします。
rem 名前空間を無視してローカル名でアクセス
for /f "usebackq delims=" %%A in (`
powershell -NoProfile -Command ^
"$x = [xml](Get-Content config.xml);" ^
"($x.SelectNodes(""//*[local-name()=Title]""))[0].InnerText"
`) do set "TITLE=%%A"
echo タイトル: %TITLE%
-NoProfile オプションを付けるとプロファイル読み込みをスキップして起動が速くなります。
複数の値を1回の PowerShell 呼び出しでまとめて取得すれば、起動オーバーヘッドを削減できます。
rem NG: 値ごとに PowerShell を起動(毎回数百ms のオーバーヘッド)
for /f %%A in (`powershell -NoProfile -Command "$j.version"`) do ...
for /f %%B in (`powershell -NoProfile -Command "$j.env"`) do ...
rem OK: 1回の呼び出しで複数値をまとめて取得
for /f "tokens=1,2 delims=|" %%A in (`
powershell -NoProfile -Command ^
"$j = Get-Content config.json -Raw | ConvertFrom-Json;" ^
"$($j.version)|$($j.env)"
`) do (
set "VERSION=%%A"
set "ENV=%%B"
)
ConvertTo-Json はデフォルトで深さ2までしか展開しません。-Depth オプションで深さを指定してください。
rem NG: デフォルトは -Depth 2(深いネストが省略される) $j | ConvertTo-Json rem OK: -Depth 10 で十分な深さまで展開 $j | ConvertTo-Json -Depth 10 | Set-Content output.json -Encoding UTF8
まとめ
| 目的 | 推奨方法 |
|---|---|
| キーワードの存在確認 | findstr /i /c:"keyword" file.json |
| JSON の値を変数に格納 | for /f + PowerShell ConvertFrom-Json |
| JSON ネスト・配列アクセス | ドット記法 .app.settings.key / .arr[0] |
| XML の属性・要素を取得 | PowerShell [xml] キャスト + ドット記法 |
| XML で属性値を絞り込み | Where-Object { $_.key -eq .. } |
| 複数値を一度に取得 | | 区切り で1行出力 + tokens= で分割 |
| JSON を生成・更新 | PowerShell ConvertTo-Json -Depth 10 |
| PowerShell 高速化 | -NoProfile + 1回の呼び出しで複数値を取得 |
バッチファイルでのファイル検索については 特定の文字列を含むファイルをコピーする方法 を、処理の並列実行については 大量ファイルを並列処理する方法 も合わせて参照してください。