SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

C++でJSONを読む

Windows::Data::Json

 JSONパーサをもう一つ、Windows Storeアプリの実行環境:Windows Runtimeが提供する名前空間Windows::Data::Json配下のクラス群です。Storeアプリはマシン上のストレージに対するアクセスにはかなり厳しい制限を課しており、そのかわりネットワークにあるストレージ/サービスを簡単に使えるよう工夫されています。Windows RuntimeがJSONパーサを用意しているのもその一環なのでしょう。

 名前空間Windows::Data::JsonにはvalueのインターフェースIJsonValueと、それを実装したJsonValue,JsonArray,JsonObjectが用意されています。JSON textをパースするにはstaticメソッド:JsonValue::Parse(String^)にJSON textを与えるとJsonValue^が返ってきます。JsonValueから値を取り出すにはGetXXX():XXXはBoolean,Number,String,Array,Objectのいずれか。JsonValueが内包する値の型はValueTypeプロパティに型IDが入っています。またJsonArrayのn番目のvalueはJsonArray::GetXXXAt(n)、JSonObject内のkeyに対応するvalueはGetNamedXXX(key)で得られます。

 それではサンプルを。Webから拾ったJSON textをパースしてみましょうか。

 僕が利用しているサンプルコード投稿サイト:Qiitaは、投稿一つ一つに言語タグが付与されます。例えば「C++」とか「Java」とか。利用者は興味のあるタグの付いた投稿だけをブラウズってスンポーです。

 ありがたいことにQiitaは開発者APIを公開してくれてまして、これを使ってQiita専用アプリが作れます。その開発者APIが返してくるのがJSON textなんですわ。例えば登録されているタグ一覧を取得するには https://qiita.com/api/v1/tags/ をHTTP GETします。すると、タグのリストがJSON textで返ってきます。

 今回Storeアプリのお話は本筋じゃないので、C++/CXでコンソールアプリに仕立てます。Windows Runtimeを使ったC++/CXコンソールアプリは参照設定などややこしい準備が必要なのですが、「CxxWinRTTemplate for Windows 8.1」という拡張機能をVisual Studioにインストールすると、コンソールアプリのひな型があっさり作れちゃいます。インストールと使い方をQiitaに投稿しておいたので併せてご一読ください。

 Windows RuntimeのおかげでHTTP GETを投げて応答を受け取るコードはほんの数行で書けてしまいますから、あとはJSONパーサに食わすだけ。ただしHTTP GETを投げてその応答を受け取るのは、ネットワーク越しであるがゆえそれ相応の時間がかかります。Windows Runtimeでは長時間ベタ待ちになるのは御法度で、非同期処理を扱わにゃなりません。「Visul C++ Compiler November 2013 CTP」で追加された resumable/await で楽させていただきました。

list04
#include <ppltasks.h>
#include <pplawait.h>
#include <functional>
#include <cassert>

using namespace concurrency;

using namespace Windows::Foundation;
using namespace Windows::Data::Json;

task<void> getTags(std::function<void(Platform::String^)> fun) __resumable {
  auto client = ref new Windows::Web::Http::HttpClient();
  auto jval = JsonValue::Parse(
                __await client->GetStringAsync(
                                  ref new Uri(L"https://qiita.com/api/v1/tags")));
  assert( jval->ValueType == JsonValueType::Array );
  auto jary = jval->GetArray();
  for ( unsigned int i = 0; i < jary->Size; ++i ) {
    fun(jary->GetObjectAt(i)->GetNamedString(L"name"));
  }
}

int main(Platform::Array<Platform::String^>^) {
  auto task = getTags([](Platform::String^ name) {
                Platform::Details::Console::WriteLine(name);
              });
  task.wait();
  return 0;
}
/* 実行結果:
Qiita
Java
Ruby
Python
Perl
PHP
Emacs
Vim
ShellScript
C
C++
Objective-C
HTML
...
*/

 せっかくだからStoreアプリでもやってみました。コンソールと大きな差はありませんね。

list05
//
// MainPage.xaml.cpp
// MainPage クラスの実装。
//
#include "pch.h"
#include <pplawait.h>
#include "MainPage.xaml.h"

using namespace App1;
using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::UI::Xaml;
using namespace Windows::Web::Http;
using namespace Windows::Data::Json;

 /*
    <ListView x:Name="TagList" >
        <ListView.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding}" FontSize="32"/>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
 */

MainPage::MainPage() {
  InitializeComponent();
}

void App1::MainPage::Button_Click(Object^ sender, RoutedEventArgs^ e) __resumable {

  /* GET https://qiita.com/api/v1/tags
   * により、Qittaからタグ列を手に入れる。
   */
  HttpClient^ client = ref new HttpClient();
  String^ response = __await client->GetStringAsync(ref new Uri(L"https://qiita.com/api/v1/tags"));

  /* Qiita-APIから手に入れた JSON文字列を 
     Windows::Data::Json::JsonValue::Parse でパースし、JsonValueを手に入れてJsonArrayを取り出す。
 */
  JsonValue^ val = JsonValue::Parse(response);
  JsonArray^ ary = val->GetArray();

  /* ListView::ItemsourceにVector<String^>^ を与える。
  */
  auto tags = ref new Platform::Collections::Vector<String^>();
  for ( unsigned int i = 0; i < ary->Size; ++i ) {
    tags->Append(ary->GetObjectAt(i)->GetNamedString(L"name"));
  }
  TagList->ItemsSource = tags;
}

 ...なんだかさっくりできちゃったけど、いかがでしょう。JSONはXMLよりずっとシンプル。スキーマ定義なくても受け取る側があらかじめその構造を知ってさえいれば問題ないわけで、通信を伴うアプリケーション実装の手駒の一つとして、知っててソンはありませんです。

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
特集記事連載記事一覧

もっと読む

この記事の著者

επιστημη(エピステーメー)

C++に首まで浸かったプログラマ。Microsoft MVP, Visual C++ (2004.01~2018.06) "だった"りわんくま同盟でたまにセッションスピーカやったり中国茶淹れてにわか茶...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/7735 2014/05/13 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー