<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>橋本商会 &#187; JSON</title>
	<atom:link href="http://shokai.org/blog/archives/tag/json/feed" rel="self" type="application/rss+xml" />
	<link>http://shokai.org/blog</link>
	<description>なんか作ったりした記録を忘れないうちに書くblog</description>
	<lastBuildDate>Sun, 20 May 2012 10:50:20 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
<atom:link rel="hub" href="http://pubsubhubbub.appspot.com/" />
			<item>
		<title>OpenCVで画像サイズを求めるgearman workerをdaemontoolsで管理する</title>
		<link>http://shokai.org/blog/archives/5254</link>
		<comments>http://shokai.org/blog/archives/5254#comments</comments>
		<pubDate>Sun, 25 Jul 2010 16:02:54 +0000</pubDate>
		<dc:creator>shokai</dc:creator>
				<category><![CDATA[未分類]]></category>
		<category><![CDATA[boost]]></category>
		<category><![CDATA[cpp]]></category>
		<category><![CDATA[gearman]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[json_builder.h]]></category>
		<category><![CDATA[OpenCV]]></category>
		<category><![CDATA[Tech]]></category>

		<guid isPermaLink="false">http://shokai.org/blog/?p=5254</guid>
		<description><![CDATA[OpenCVで画像のサイズを求めるgearman workerを作って、Rubyから呼ぶで作ったworkerをpreforkさせて、そいつらをdaemontoolsで管理できるようにした。あらかじめCPU個数+いくつかf [...]]]></description>
			<content:encoded><![CDATA[<p>
<a href="http://shokai.org/blog/archives/4987">OpenCVで画像のサイズを求めるgearman workerを作って、Rubyから呼ぶ</a>で作ったworkerをpreforkさせて、そいつらをdaemontoolsで管理できるようにした。あらかじめCPU個数+いくつかforkしておくと、CPUが複数あるマシンを生かせるし、解析前にlibcurlで画像を取得している時のI/O待ちが少なくなって良い。（この記事のworkerはlibcurl使ってない版だけど）<br />
あと、返り値は自分で作った<a href="http://github.com/shokai/json_builder-cpp">json_builder.h</a>を使って返すようにした。<br />
<br />
なにげに大量の画像の中からダウンロード失敗した破損画像を見つけるのに重宝している。<br />
<br />
まずdaemontoolsをインストールしておく<br />
<ul>
  <li><a href="http://d.hatena.ne.jp/shokai/20100724/1279996402">Macにdaemontoolsインストール &#8211; 橋本詳解</a></li>
  <li><a href="http://d.hatena.ne.jp/shokai/20100725/1280014778">Ubuntu10.04にdaemontoolsインストール &#8211; 橋本詳解</a></li>
</ul>
gearmandもdaemontoolsで自動起動するようにしておく。<br />
<br />
<br />
daemontoolsで管理できるようにする。<br />
普通にforkしただけだと、daemontoolsでsvc -dしてプロセスを止めようとしてもforkした子プロセスの方が止まらない。<br />
<br />
Perlの場合の良い例があった。<br />
<a href="http://d.hatena.ne.jp/tokuhirom/20100201/1264989237">How to manage Gearman worker processes. &#8211; TokuLog 改メ tokuhirom’s blog</a><br />
<a href="http://search.cpan.org/~kazuho/Parallel-Prefork/lib/Parallel/Prefork.pm">Parallel::Prefork</a>を使っている。Parallel::Preforkのソースを読んでみたら、trap_signalsオプションで親プロセスがSIGTERMとSIGHUPをフックして、子プロセスにkillを送っていた。<br />
よく考えたら普通のforkで親が子を殺すというやつだった。<br />
<br />
<br />
Parallel::Preforkと同じ様にやる。<br />
forkした後親が子のpidのリストを持っておいて、SIGTERM/SIGHUPをフックして、子を全部killする処理を追加した。<br />
<br />
daemontoolsのrunスクリプトはこれ<br />
<pre class="prettyprint">
#!/bin/sh<br />
exec&nbsp;2&gt;&amp;1<br />
exec&nbsp;setuidgid&nbsp;sho&nbsp;/Users/sho/src/gearmand-study/imgsize/imgsizeWorker&nbsp;-s&nbsp;localhost&nbsp;-p&nbsp;7003&nbsp;--fork&nbsp;5<br />
</pre>
起動すると5個にプロセスが増える。親はdaemontoolsのsuperviseが管理してくれる。<br />
これでsvc -dとか-uとかすればまとめて起動終了するようになった。<br />
<br />
<a href="http://shokai.org/projects/gearman-study/index.cgi/file/6b0da8ba1769/imgsize/imgsizeWorker.cpp">imgsizeWorker.cpp</a><br />
<pre class="prettyprint">
//&nbsp;画像サイズを返すgearman&nbsp;worker<br />
#include&nbsp;&lt;stdio.h&gt;<br />
#include&nbsp;&lt;stdlib.h&gt;<br />
#include&nbsp;&lt;unistd.h&gt;<br />
#include&nbsp;&lt;signal.h&gt;<br />
#include&nbsp;&lt;string&gt;<br />
#include&nbsp;&lt;iostream&gt;<br />
#include&nbsp;&lt;cv.h&gt;<br />
#include&nbsp;&lt;highgui.h&gt;<br />
#include&nbsp;&lt;boost/program_options.hpp&gt;<br />
#include&nbsp;&lt;boost/regex.hpp&gt;<br />
#include&nbsp;&lt;boost/format.hpp&gt;<br />
#include&nbsp;&lt;boost/tuple/tuple.hpp&gt;<br />
#include&nbsp;&lt;boost/tuple/tuple_io.hpp&gt;<br />
#include&nbsp;&lt;boost/any.hpp&gt;<br />
#include&nbsp;&lt;libgearman/gearman.h&gt;<br />
#include&nbsp;"json_builder.h"<br />
<br />
using&nbsp;namespace&nbsp;boost;<br />
using&nbsp;namespace&nbsp;std;<br />
<br />
tuple&lt;int,&nbsp;int&gt;&nbsp;get_size(const&nbsp;string&amp;&nbsp;fileName);&nbsp;//&nbsp;画像のwidth,heightを返す<br />
map&lt;string,any&gt;&nbsp;imgsize(const&nbsp;string&amp;&nbsp;fileName);&nbsp;//&nbsp;gearman&nbsp;workerとしてclientに返すためのJSON&nbsp;Objectを作る<br />
void&nbsp;*job_imgsize(gearman_job_st&nbsp;*job,&nbsp;void&nbsp;*cb_arg,&nbsp;size_t&nbsp;*result_size,&nbsp;gearman_return_t&nbsp;*ret_ptr);<br />
void&nbsp;on_exit_signal(int&nbsp;sig);<br />
vector&lt;int&gt;&nbsp;pids;<br />
<br />
int&nbsp;main(int&nbsp;argc,&nbsp;char*&nbsp;argv[])&nbsp;{<br />
&nbsp;&nbsp;program_options::options_description&nbsp;opts("options");<br />
&nbsp;&nbsp;opts.add_options()<br />
&nbsp;&nbsp;&nbsp;&nbsp;("help,h",&nbsp;"helpを表示")<br />
&nbsp;&nbsp;&nbsp;&nbsp;("server,s",&nbsp;program_options::value&lt;string&gt;(),&nbsp;"gearmanサーバーのアドレス")<br />
&nbsp;&nbsp;&nbsp;&nbsp;("port,p",&nbsp;program_options::value&lt;int&gt;(),&nbsp;"gearmanサーバーのport番号")<br />
&nbsp;&nbsp;&nbsp;&nbsp;("fork",&nbsp;program_options::value&lt;int&gt;(),&nbsp;"preforkする数")<br />
&nbsp;&nbsp;&nbsp;&nbsp;("test,t",&nbsp;program_options::value&lt;string&gt;(),&nbsp;"gearman&nbsp;worker単体テスト用query");<br />
&nbsp;&nbsp;program_options::variables_map&nbsp;argmap;<br />
&nbsp;&nbsp;program_options::store(parse_command_line(argc,&nbsp;argv,&nbsp;opts),&nbsp;argmap);<br />
&nbsp;&nbsp;program_options::notify(argmap);<br />
<br />
&nbsp;&nbsp;if(!argmap.count("help")){<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(argmap.count("test")){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;"---test---"&nbsp;&lt;&lt;&nbsp;endl;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string&nbsp;gearman_param&nbsp;=&nbsp;argmap["test"].as&lt;string&gt;();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;json_builder::toJson(imgsize(gearman_param))&nbsp;&lt;&lt;&nbsp;endl;&nbsp;//&nbsp;単体でworkerとしてのテスト<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}else&nbsp;if(argmap.count("server")&nbsp;&amp;&amp;&nbsp;argmap.count("port")){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(argmap.count("fork")){<br />
	int&nbsp;i,&nbsp;pid;<br />
	for(i&nbsp;=&nbsp;1;&nbsp;i&nbsp;&lt;&nbsp;argmap["fork"].as&lt;int&gt;();&nbsp;i++){<br />
	&nbsp;&nbsp;pid&nbsp;=&nbsp;fork();<br />
	&nbsp;&nbsp;if(pid&nbsp;==&nbsp;0){&nbsp;//&nbsp;子プロセス<br />
	&nbsp;&nbsp;&nbsp;&nbsp;pids.clear();<br />
	&nbsp;&nbsp;&nbsp;&nbsp;break;<br />
	&nbsp;&nbsp;}<br />
	&nbsp;&nbsp;else{&nbsp;//&nbsp;親プロセス<br />
	&nbsp;&nbsp;&nbsp;&nbsp;pids.push_back(pid);<br />
	&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;str(format("fork:%d&nbsp;-&nbsp;parent:%d&nbsp;child:%d")&nbsp;%&nbsp;<br />
			i&nbsp;%<br />
			getpid()&nbsp;%<br />
			pid)&nbsp;&lt;&lt;&nbsp;endl;<br />
	&nbsp;&nbsp;}<br />
	}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(pids.size()&nbsp;&gt;&nbsp;0){&nbsp;//&nbsp;親プロセスの終了シグナルをフックする<br />
	signal(SIGTERM,&nbsp;on_exit_signal);<br />
	signal(SIGHUP,&nbsp;on_exit_signal);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gearman_worker_st&nbsp;worker;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gearman_worker_create(&amp;worker);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string&nbsp;g_server&nbsp;=&nbsp;argmap["server"].as&lt;string&gt;();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;g_port&nbsp;=&nbsp;argmap["port"].as&lt;int&gt;();<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;hostent&nbsp;*g_host&nbsp;=&nbsp;gethostbyname((char*)g_server.c_str());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string&nbsp;g_server_addr&nbsp;=&nbsp;str(format("%d.%d.%d.%d")&nbsp;%<br />
				&nbsp;(uint)(uchar)g_host-&gt;h_addr[0]&nbsp;%<br />
				&nbsp;(uint)(uchar)g_host-&gt;h_addr[1]&nbsp;%<br />
				&nbsp;(uint)(uchar)g_host-&gt;h_addr[2]&nbsp;%<br />
				&nbsp;(uint)(uchar)g_host-&gt;h_addr[3]);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gearman_worker_add_server(&amp;worker,&nbsp;g_server_addr.c_str(),&nbsp;g_port);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gearman_worker_add_function(&amp;worker,&nbsp;"img_size",&nbsp;0,&nbsp;job_imgsize,&nbsp;NULL);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;str(format("---start&nbsp;worker&nbsp;(%s:%d)---")&nbsp;%<br />
		&nbsp;&nbsp;g_server_addr&nbsp;%&nbsp;g_port)&nbsp;&lt;&lt;&nbsp;endl;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(true)&nbsp;gearman_worker_work(&amp;worker);&nbsp;//&nbsp;workerとして待機<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;cerr&nbsp;&lt;&lt;&nbsp;"server,portが必要です"&nbsp;&lt;&lt;&nbsp;endl;<br />
&nbsp;&nbsp;cerr&nbsp;&lt;&lt;&nbsp;opts&nbsp;&lt;&lt;&nbsp;endl;<br />
&nbsp;&nbsp;return&nbsp;1;<br />
&nbsp;&nbsp;<br />
}<br />
<br />
//&nbsp;opencvで画像サイズを取得<br />
tuple&lt;int,&nbsp;int&gt;&nbsp;get_size(const&nbsp;string&amp;&nbsp;fileName){<br />
&nbsp;&nbsp;IplImage&nbsp;*img&nbsp;=&nbsp;cvLoadImage(fileName.c_str());<br />
&nbsp;&nbsp;if(!img){<br />
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;make_tuple(-1,&nbsp;-1);<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;else{<br />
&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;width&nbsp;=&nbsp;img-&gt;width;<br />
&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;height&nbsp;=&nbsp;img-&gt;height;<br />
&nbsp;&nbsp;&nbsp;&nbsp;cvReleaseImage(&amp;img);<br />
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;make_tuple(width,&nbsp;height);<br />
&nbsp;&nbsp;}<br />
}<br />
<br />
//&nbsp;画像サイズを取得してgearman&nbsp;serverに返すJSON&nbsp;Objectを作る<br />
map&lt;string,any&gt;&nbsp;imgsize(const&nbsp;string&amp;&nbsp;fileName){<br />
&nbsp;&nbsp;map&lt;string,any&gt;&nbsp;result_m;<br />
&nbsp;&nbsp;int&nbsp;width,&nbsp;height;<br />
&nbsp;&nbsp;tie(width,&nbsp;height)&nbsp;=&nbsp;get_size(fileName);<br />
&nbsp;&nbsp;if(width&nbsp;&gt;&nbsp;0&nbsp;&amp;&amp;&nbsp;height&nbsp;&gt;&nbsp;0){<br />
&nbsp;&nbsp;&nbsp;&nbsp;result_m["width"]&nbsp;=&nbsp;width;<br />
&nbsp;&nbsp;&nbsp;&nbsp;result_m["height"]&nbsp;=&nbsp;height;<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;else{<br />
&nbsp;&nbsp;&nbsp;&nbsp;result_m["error"]&nbsp;=&nbsp;string("image&nbsp;load&nbsp;error");<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;return&nbsp;result_m;<br />
}<br />
<br />
//&nbsp;gearman&nbsp;worker&nbsp;job<br />
void&nbsp;*job_imgsize(gearman_job_st&nbsp;*job,&nbsp;void&nbsp;*cb_arg,&nbsp;size_t&nbsp;*result_size,&nbsp;gearman_return_t&nbsp;*ret_ptr){<br />
&nbsp;&nbsp;string&nbsp;fileName&nbsp;=&nbsp;(char*)gearman_job_workload(job);<br />
&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;fileName&nbsp;&lt;&lt;&nbsp;endl;<br />
&nbsp;&nbsp;string&nbsp;result_str&nbsp;=&nbsp;json_builder::toJson(imgsize(fileName));<br />
&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;"&nbsp;=&gt;&nbsp;"&nbsp;&lt;&lt;&nbsp;result_str&nbsp;&lt;&lt;&nbsp;endl;<br />
&nbsp;&nbsp;char&nbsp;*result&nbsp;=&nbsp;(char*)strdup(result_str.c_str());<br />
&nbsp;&nbsp;*result_size&nbsp;=&nbsp;result_str.size();<br />
&nbsp;&nbsp;*ret_ptr&nbsp;=&nbsp;GEARMAN_SUCCESS;<br />
&nbsp;&nbsp;return&nbsp;result;<br />
}<br />
<br />
void&nbsp;on_exit_signal(int&nbsp;sig){<br />
&nbsp;&nbsp;for(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;pids.size();&nbsp;i++){<br />
&nbsp;&nbsp;&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;str(format("kill&nbsp;(pid:%d)")&nbsp;%&nbsp;pids[i])&nbsp;&lt;&lt;&nbsp;endl;<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(kill(pids[i],&nbsp;SIGKILL)&nbsp;&lt;&nbsp;0){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cerr&nbsp;&lt;&lt;&nbsp;str(format("kill&nbsp;failed&nbsp;(pid:%d)")&nbsp;%&nbsp;pids[i])&nbsp;&lt;&lt;&nbsp;endl;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;exit(0);<br />
}<br />
</pre>
</p>
]]></content:encoded>
			<wfw:commentRss>http://shokai.org/blog/archives/5254/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>json_buiilderをgithubに移動させた</title>
		<link>http://shokai.org/blog/archives/5199</link>
		<comments>http://shokai.org/blog/archives/5199#comments</comments>
		<pubDate>Tue, 15 Jun 2010 16:01:02 +0000</pubDate>
		<dc:creator>shokai</dc:creator>
				<category><![CDATA[未分類]]></category>
		<category><![CDATA[cpp]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[json_builder.h]]></category>
		<category><![CDATA[Tech]]></category>

		<guid isPermaLink="false">http://shokai.org/blog/?p=5199</guid>
		<description><![CDATA[bitbucketからhttp://github.com/shokai/json_builder-cppに移動した。 ちょっとまじめにREADMEを書いたりした。 githubのreadmeにはmarkdown形式を使っ [...]]]></description>
			<content:encoded><![CDATA[<p>
bitbucketから<a href="http://github.com/shokai/json_builder-cpp">http://github.com/shokai/json_builder-cpp</a>に移動した。<br />
<br />
ちょっとまじめにREADMEを書いたりした。<br />
githubのreadmeにはmarkdown形式を使った。<a href="http://d.hatena.ne.jp/shokai/20100608/1275998764">markdownをインストールすればローカルでもマークアップがプレビューできて良い</a><br />
<br />
json_builder.hはヘッダファイル単体でstd::mapやvectorをjsonにシリアライズするC++用のライブラリ。parseはできない。</p>
]]></content:encoded>
			<wfw:commentRss>http://shokai.org/blog/archives/5199/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>json_builderを特殊文字のエスケープ、true、false、nullに対応させた</title>
		<link>http://shokai.org/blog/archives/5046</link>
		<comments>http://shokai.org/blog/archives/5046#comments</comments>
		<pubDate>Sat, 30 Jan 2010 01:56:23 +0000</pubDate>
		<dc:creator>shokai</dc:creator>
				<category><![CDATA[未分類]]></category>
		<category><![CDATA[cpp]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[json_builder.h]]></category>
		<category><![CDATA[Tech]]></category>

		<guid isPermaLink="false">http://shokai.org/blog/?p=5046</guid>
		<description><![CDATA[前：橋本商会 C++でmapやvectorをJSON出力するjson_builder.hを作った ダブルクオートなどを含む文字列を値に保持するためのエスケープ処理にboost::regexを使ったので、libboost_ [...]]]></description>
			<content:encoded><![CDATA[<p>
前：<a href="http://shokai.org/blog/archives/5021">橋本商会  C++でmapやvectorをJSON出力するjson_builder.hを作った</a><br />
<br />
<br />
ダブルクオートなどを含む文字列を値に保持するためのエスケープ処理にboost::regexを使ったので、libboost_regex-mt.aをコンパイル時に読み込まないとならなくなった → <a href="http://bitbucket.org/shokai/json-builder/src/abbc9d0a382d/test/Makefile">Makefileの例</a><br />
まさかboost::regex_replaceで頭にバックスラッシュをつけるのに、<a href="http://d.hatena.ne.jp/shokai/20100127/1264606980">バックスラッシュ4つで置換</a>するとは思わなかった<br />
<br />
<br />
こんな風に使う。true, false, nullを入れられるようになった<br />
<a href="http://bitbucket.org/shokai/json-builder/src/abbc9d0a382d/test/test.cpp">test.cpp</a><br />
<pre class="prettyprint">
#include&nbsp;&lt;iostream&gt;<br />
#include&nbsp;&lt;string&gt;<br />
#include&nbsp;&lt;map&gt;<br />
#include&nbsp;&lt;boost/any.hpp&gt;<br />
#include&nbsp;"../json_builder.h"<br />
<br />
int&nbsp;main(int&nbsp;argc,&nbsp;char*&nbsp;argv[]){<br />
&nbsp;&nbsp;std::map&lt;string,boost::any&gt;&nbsp;user;<br />
&nbsp;&nbsp;user["name"]&nbsp;=&nbsp;std::string("shokai");<br />
&nbsp;&nbsp;user["fullname"]&nbsp;=&nbsp;std::string("sho&nbsp;hashimoto");<br />
&nbsp;&nbsp;user["age"]&nbsp;=&nbsp;25;<br />
&nbsp;&nbsp;user["test"]&nbsp;=&nbsp;1.23;<br />
&nbsp;&nbsp;user["null"]&nbsp;=&nbsp;json_builder::null;<br />
&nbsp;&nbsp;user["true"]&nbsp;=&nbsp;true;<br />
&nbsp;&nbsp;user["false"]&nbsp;=&nbsp;false;<br />
<br />
&nbsp;&nbsp;string&nbsp;json&nbsp;=&nbsp;json_builder::toJson(user);<br />
&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;json&nbsp;&lt;&lt;&nbsp;endl;<br />
&nbsp;&nbsp;return&nbsp;0;<br />
}<br />
</pre>
<br />
<br />
実行結果<br />
<pre>
{"age":"25","false":false,"fullname":"sho hashimoto","name":"shokai","null":null,"test":"1.23","true":true}<br />
</pre>
<br />
<br />
<br />
C++でnullを表現するために適当な構造体を定義してしまったけど、こういうので良いんだろうか？<br />
<a href="http://bitbucket.org/shokai/json-builder/src/abbc9d0a382d/json_builder.h">json_builder.h</a><br />
<pre class="prettyprint">
#include&nbsp;&lt;iostream&gt;<br />
#include&nbsp;&lt;string&gt;<br />
#include&nbsp;&lt;map&gt;<br />
#include&nbsp;&lt;vector&gt;<br />
#include&nbsp;&lt;boost/any.hpp&gt;<br />
#include&nbsp;&lt;boost/tuple/tuple.hpp&gt;<br />
#include&nbsp;&lt;boost/format.hpp&gt;<br />
#include&nbsp;&lt;boost/foreach.hpp&gt;<br />
#include&nbsp;&lt;boost/regex.hpp&gt;<br />
<br />
using&nbsp;namespace&nbsp;std;<br />
using&nbsp;namespace&nbsp;boost;<br />
<br />
#define&nbsp;null&nbsp;json_null()<br />
<br />
namespace&nbsp;json_builder{<br />
&nbsp;&nbsp;struct&nbsp;json_null{};<br />
<br />
&nbsp;&nbsp;string&nbsp;toJson(any&nbsp;value){<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(value.type()&nbsp;==&nbsp;typeid(vector&lt;any&gt;)){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string&nbsp;result_str;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vector&lt;any&gt;&nbsp;vec&nbsp;=&nbsp;any_cast&lt;vector&lt;any&gt;&nbsp;&gt;(value);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;vec.size();&nbsp;i++){<br />
	result_str&nbsp;+=&nbsp;toJson(vec[i]);<br />
	if(i&nbsp;&lt;&nbsp;vec.size()-1)&nbsp;result_str&nbsp;+=&nbsp;",";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result_str&nbsp;=&nbsp;str(format("[%s]")&nbsp;%&nbsp;result_str);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;result_str;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if(value.type()&nbsp;==&nbsp;typeid(map&lt;string,any&gt;)){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string&nbsp;result_str;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;map&lt;string,any&gt;&nbsp;m&nbsp;=&nbsp;any_cast&lt;map&lt;string,any&gt;&nbsp;&gt;(value);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string&nbsp;key;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;any&nbsp;value;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;i&nbsp;=&nbsp;0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BOOST_FOREACH(tie(key,value),&nbsp;m){<br />
	result_str&nbsp;+=&nbsp;str(format("\"%s\":%s")&nbsp;%&nbsp;key&nbsp;%&nbsp;toJson(value));<br />
	if(++i&nbsp;&lt;&nbsp;m.size())&nbsp;result_str&nbsp;+=&nbsp;",";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result_str&nbsp;=&nbsp;str(format("{%s}")&nbsp;%&nbsp;result_str);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;result_str;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if(value.type()&nbsp;==&nbsp;typeid(json_null)){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;string("null");<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if(value.type()&nbsp;==&nbsp;typeid(string)){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;str(format("\"%s\"")&nbsp;%&nbsp;<br />
		&nbsp;&nbsp;&nbsp;regex_replace(any_cast&lt;string&gt;(value),&nbsp;regex("[\"\'\\\\/]"),&nbsp;"\\\\$0"));<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if(value.type()&nbsp;==&nbsp;typeid(bool)){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(any_cast&lt;bool&gt;(value))&nbsp;return&nbsp;string("true");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;string("false");<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if(value.type()&nbsp;==&nbsp;typeid(int)){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;str(format("\"%d\"")&nbsp;%&nbsp;any_cast&lt;int&gt;(value));<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if(value.type()&nbsp;==&nbsp;typeid(double)){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;str(format("\"%d\"")&nbsp;%&nbsp;any_cast&lt;double&gt;(value));<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}<br />
<br />
}<br />
</pre>
<br />
</p>
]]></content:encoded>
			<wfw:commentRss>http://shokai.org/blog/archives/5046/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>C++でmapやvectorをJSON出力するjson_builder.hを作った</title>
		<link>http://shokai.org/blog/archives/5021</link>
		<comments>http://shokai.org/blog/archives/5021#comments</comments>
		<pubDate>Wed, 27 Jan 2010 04:08:06 +0000</pubDate>
		<dc:creator>shokai</dc:creator>
				<category><![CDATA[未分類]]></category>
		<category><![CDATA[cpp]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[json_builder.h]]></category>
		<category><![CDATA[Tech]]></category>

		<guid isPermaLink="false">http://shokai.org/blog/?p=5021</guid>
		<description><![CDATA[C++でJSONというと、json.orgにもライブラリがたくさん紹介されているとおり色々ある。でも単に出力するだけの物で、ヘッダファイル一つで簡単に使えるのが無かったので作ってみた。 ちょっとstringの連結コストが [...]]]></description>
			<content:encoded><![CDATA[<p>
C++でJSONというと、<a href="http://www.json.org/json-ja.html">json.org</a>にもライブラリがたくさん紹介されているとおり色々ある。でも単に出力するだけの物で、ヘッダファイル一つで簡単に使えるのが無かったので作ってみた。<br />
ちょっとstringの連結コストがかかる気もするけど、まあいいか。<br />
<br />
今のところ、std::map&lt;string,any&gt;とstd::vector&lt;any&gt;とstringとintとdoubleが入る。つまりkeyはstringのみで、値はboost::anyをかぶせている。もちろんmapやvectorは入れ子にできる。<br />
<br />
boost::anyは何でも入れられる便利な型。<br />
参考：<a href="http://d.hatena.ne.jp/shokai/20100103/1262524286">boost::any &#8211; 橋本詳解</a><br />
<br />
<br />
必要なのはこれだけだけど、boost::any、tuple、format、foreachが必要。<br />
json_builder.h最新版は<a href="http://bitbucket.org/shokai/json-builder/src/tip/json_builder.h">bitbucketからどうぞ</a>。<br />
<br />
<a href="http://bitbucket.org/shokai/json-builder/src/c9959e7d40c2/json_builder.h">json_builder.h</a><br />
<pre class="prettyprint">
#include&nbsp;&lt;iostream&gt;<br />
#include&nbsp;&lt;string&gt;<br />
#include&nbsp;&lt;map&gt;<br />
#include&nbsp;&lt;vector&gt;<br />
#include&nbsp;&lt;boost/any.hpp&gt;<br />
#include&nbsp;&lt;boost/tuple/tuple.hpp&gt;<br />
#include&nbsp;&lt;boost/format.hpp&gt;<br />
#include&nbsp;&lt;boost/foreach.hpp&gt;<br />
<br />
using&nbsp;namespace&nbsp;std;<br />
using&nbsp;namespace&nbsp;boost;<br />
<br />
namespace&nbsp;json_builder{<br />
&nbsp;&nbsp;string&nbsp;toJson(any&nbsp;value){<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(value.type()&nbsp;==&nbsp;typeid(vector&lt;any&gt;)){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string&nbsp;result_str;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vector&lt;any&gt;&nbsp;vec&nbsp;=&nbsp;any_cast&lt;vector&lt;any&gt;&nbsp;&gt;(value);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;vec.size();&nbsp;i++){<br />
	result_str&nbsp;+=&nbsp;toJson(vec[i]);<br />
	if(i&nbsp;&lt;&nbsp;vec.size()-1)&nbsp;result_str&nbsp;+=&nbsp;",";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result_str&nbsp;=&nbsp;str(format("[%s]")&nbsp;%&nbsp;result_str);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;result_str;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if(value.type()&nbsp;==&nbsp;typeid(map&lt;string,any&gt;)){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string&nbsp;result_str;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;map&lt;string,any&gt;&nbsp;m&nbsp;=&nbsp;any_cast&lt;map&lt;string,any&gt;&nbsp;&gt;(value);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string&nbsp;key;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;any&nbsp;value;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;i&nbsp;=&nbsp;0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BOOST_FOREACH(tie(key,value),&nbsp;m){<br />
	result_str&nbsp;+=&nbsp;str(format("\"%s\":%s")&nbsp;%&nbsp;key&nbsp;%&nbsp;toJson(value));<br />
	if(++i&nbsp;&lt;&nbsp;m.size())&nbsp;result_str&nbsp;+=&nbsp;",";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result_str&nbsp;=&nbsp;str(format("{%s}")&nbsp;%&nbsp;result_str);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;result_str;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if(value.type()&nbsp;==&nbsp;typeid(string)){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;str(format("\"%s\"")&nbsp;%&nbsp;any_cast&lt;string&gt;(value));<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if(value.type()&nbsp;==&nbsp;typeid(int)){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;str(format("\"%d\"")&nbsp;%&nbsp;any_cast&lt;int&gt;(value));<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;if(value.type()&nbsp;==&nbsp;typeid(double)){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;str(format("\"%d\"")&nbsp;%&nbsp;any_cast&lt;double&gt;(value));<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}<br />
<br />
}<br />
</pre>
jsonは要素数不定のただの木なので、再帰でtree walkして要素の型を見て文字列に直して連結し直すだけの関数一つになった。シンプル。<br />
見ての通り、&#8221;や&#8217;や[や{はescapeしていないので、それらを含む文字列をtoJsonするとparseできないjsonができる。とりあえず今は入れる前にescapeしておいてほしい。<br />
単純にバックスラッシュつければいいだけなのかな？ → <a href="http://shokai.org/blog/archives/5046">対応した</a><br />
<br />
<br />
使ってみる。一つのstd::mapをjsonのhashとして標準出力する例<br />
<a href="http://bitbucket.org/shokai/json-builder/src/c9959e7d40c2/test/test.cpp">test.cpp</a><br />
<pre class="prettyprint">
#include&nbsp;&lt;iostream&gt;<br />
#include&nbsp;&lt;string&gt;<br />
#include&nbsp;&lt;map&gt;<br />
#include&nbsp;&lt;boost/any.hpp&gt;<br />
#include&nbsp;"../json_builder.h"<br />
<br />
int&nbsp;main(int&nbsp;argc,&nbsp;char*&nbsp;argv[]){<br />
&nbsp;&nbsp;std::map&lt;string,boost::any&gt;&nbsp;user;<br />
&nbsp;&nbsp;user["name"]&nbsp;=&nbsp;std::string(&#8220;shokai&#8221;);&nbsp;//&nbsp;string<br />
&nbsp;&nbsp;user["fullname"]&nbsp;=&nbsp;std::string(&#8220;sho&nbsp;hashimoto&#8221;);<br />
&nbsp;&nbsp;user["age"]&nbsp;=&nbsp;25;&nbsp;//&nbsp;int<br />
&nbsp;&nbsp;user["test"]&nbsp;=&nbsp;1.23;&nbsp;//&nbsp;double<br />
<br />
&nbsp;&nbsp;string&nbsp;json&nbsp;=&nbsp;json_builder::toJson(user);<br />
&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;json&nbsp;&lt;&lt;&nbsp;endl;<br />
&nbsp;&nbsp;return&nbsp;0;<br />
}<br />
</pre>
<br />
<br />
出力<br />
<pre class="prettyprint">
{"age":"25","fullname":"sho&nbsp;hashimoto","name":"shokai","test":"1.23"}<br />
</pre>
<br />
<br />
<br />
より複雑に、mapやvectorを入れ子にした例<br />
<a href="http://bitbucket.org/shokai/json-builder/src/c9959e7d40c2/test/test.cpp">test2.cpp</a><br />
<pre class="prettyprint">
#include&nbsp;&lt;iostream&gt;<br />
#include&nbsp;&lt;string&gt;<br />
#include&nbsp;&lt;map&gt;<br />
#include&nbsp;&lt;vector&gt;<br />
#include&nbsp;&lt;boost/any.hpp&gt;<br />
#include&nbsp;"../json_builder.h"<br />
<br />
using&nbsp;namespace&nbsp;json_builder;<br />
using&nbsp;namespace&nbsp;std;<br />
using&nbsp;namespace&nbsp;boost;<br />
<br />
int&nbsp;main(int&nbsp;argc,&nbsp;char*&nbsp;argv[]){<br />
&nbsp;&nbsp;map&lt;string,any&gt;&nbsp;obj;<br />
&nbsp;&nbsp;obj["test"]&nbsp;=&nbsp;string("testtest");<br />
<br />
&nbsp;&nbsp;map&lt;string,any&gt;&nbsp;user;<br />
&nbsp;&nbsp;user["name"]&nbsp;=&nbsp;string("shokai");<br />
&nbsp;&nbsp;user["fullname"]&nbsp;=&nbsp;string("sho&nbsp;hashimoto");<br />
&nbsp;&nbsp;user["age"]&nbsp;=&nbsp;25;<br />
&nbsp;&nbsp;user["test"]&nbsp;=&nbsp;6.78;<br />
&nbsp;&nbsp;obj["user"]&nbsp;=&nbsp;user;<br />
<br />
&nbsp;&nbsp;std::vector&lt;any&gt;&nbsp;vec;<br />
&nbsp;&nbsp;vec.push_back(string("aaaa"));<br />
&nbsp;&nbsp;vec.push_back(1234.56);<br />
&nbsp;&nbsp;vec.push_back(string("hello&nbsp;work"));<br />
&nbsp;&nbsp;<br />
<br />
&nbsp;&nbsp;vector&lt;any&gt;&nbsp;vec2;<br />
&nbsp;&nbsp;vec2.push_back(string("nested&nbsp;std::vector"));<br />
&nbsp;&nbsp;vec2.push_back(string("bbbbb"));<br />
&nbsp;&nbsp;vec.push_back(vec2);&nbsp;//&nbsp;std::vecotrの入れ子<br />
<br />
&nbsp;&nbsp;obj["params"]&nbsp;=&nbsp;vec;<br />
&nbsp;&nbsp;string&nbsp;json&nbsp;=&nbsp;json_builder::toJson(obj);<br />
&nbsp;&nbsp;cout&nbsp;&lt;&lt;&nbsp;json&nbsp;&lt;&lt;&nbsp;endl;<br />
<br />
&nbsp;&nbsp;return&nbsp;0;<br />
}<br />
</pre>
<br />
<br />
出力<br />
<pre class="prettyprint">
{"params":["aaaa","1234.56","hello work",["nested std::vector","bbbbb"]],<br />
"test":"testtest","user":{"age":"25","fullname":"sho hashimoto","name":"shokai","test":"6.78"}}<br />
</pre>
<br />
<br />
出力したjsonが正しいかどうか、確認するために<a href="http://bitbucket.org/shokai/json-builder/src/c9959e7d40c2/test/json-parse.rb">rubyのjsonモジュールでrubyのオブジェクトに読み込むコード</a>をtestフォルダに置いておいた。<br />
<pre class="prettyprint">
{"params"=>["aaaa", "1234.56", "hello work", ["nested std::vector", "bbbbb"]],<br />
 "user"=><br />
  {"name"=>"shokai", "fullname"=>"sho hashimoto", "test"=>"6.78", "age"=>"25"},<br />
 "test"=>"testtest"}<br />
parse success<br />
</pre>
ちゃんと読み込めた。<br />
<br />
<br />
<br />
BOOST_FOREACHが涙が出るほど便利だった！！<br />
<ul>
  <li><a href="http://d.hatena.ne.jp/faith_and_brave/20091002/1254469396">std::mapをBoost.Foreachで回すときにキーと値を簡単に取り出す - Faith and Brave - C++で遊ぼう</a></li>
  <li><a href="http://miyano.s53.xrea.com/cgi-bin/sb/sb.cgi?cid=3-boost%20-%20Foreach">Pasture | C++::boost - Foreach</a></li>
</ul>
</p>
]]></content:encoded>
			<wfw:commentRss>http://shokai.org/blog/archives/5021/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

