CSVOとYAML
前回の記事(CSVOの表現力 - はじめてのフォーマット)の最後のほうで 行/列を入れ替えたCSVOデータを貼りましたが、YAMLに似ていると感じませんでしたか?
再掲
CSVOはもともと、VBAで業務ツールを作っていたときに、 設定情報をYAMLのような形式でワークシート上で管理できないか、 と考えたところから始まりました。
では、下のYAMLデータをCSVO形式に変換してみましょう。 (データはYAML Ain’t Markup Language (YAML™) Version 1.2のExample 2.27.を改変したもの)
invoice: 34843 date : 2001-01-23 bill-to: given : Chris family : Dumars address: lines: - 458 Walkman Dr. - Suite #292 city : Royal Oak state : MI postal : 48046 product: - sku : BL394D quantity : 4 description : Basketball price : 450.00 - sku : BL4438H quantity : 1 description : Super Hoop price : 2392.00 tax : 251.42 total: 4443.52 comments: - Late afternoon is best. - Backup contact is Nancy - Billsmer @ 338-4338.
スペースをタブにして貼り付けます。
値を一列にまとめます。
ネスト時の改行を無くして リストのマークを*に変えて完成です。
行/列を入れ替えたものと 出力したテキストデータも貼っておきましょう。
invoice:,date:,bill-to:,,,,,,,product:,,,,,,,,tax:,total:,comments:,, ,,given:,family:,address:,,,,,*,,,,*,,,,,,*,*,* ,,,,lines:,,city:,state:,postal:,sku:,quantity:,description:,price:,sku:,quantity:,description:,price:,,,,, ,,,,*,*,,,,,,,,,,,,,,,, ,,,,,,,,,,,,,,,,,,,,, 34843,2001-01-23,Chris,Dumars,458 Walkman Dr.,Suite #292,Royal Oak,MI,48046,BL394D,4,Basketball,450,BL4438H,1,Super Hoop,2392,251.42,4443.52,Late afternoon is best.,Backup contact is Nancy,Billsmer @ 338-4338.
CSVOの表現力
CSVOにはどのくらいの表現力があるのでしょうか。
JSONの公式サイトにあるJSONの例をCSVO形式に変換してみましょう。
例1
{ "glossary": { "title": "example glossary", "GlossDiv": { "title": "S", "GlossList": { "GlossEntry": { "ID": "SGML", "SortAs": "SGML", "GlossTerm": "Standard Generalized Markup Language", "Acronym": "SGML", "Abbrev": "ISO 8879:1986", "GlossDef": { "para": "A meta-markup language, used to create markup languages such as DocBook.", "GlossSeeAlso": ["GML", "XML"] }, "GlossSee": "markup" } } } } }
CSVO形式に変換してみましょう(CSVOはレコードのリストを表現するデータ形式なので、例1のJSONデータを1つ目のレコードとして扱った場合の結果となります)。
glossary,,,,,,,,,, title,GlossDiv,,,,,,,,, ,title,GlossList,,,,,,,, ,,GlossEntry,,,,,,,, ,,ID,SortAs,GlossTerm,Acronym,Abbrev,GlossDef,,,GlossSee ,,,,,,,para,GlossSeeAlso,, ,,,,,,,,*,*, ,,,,,,,,,, example glossary,S,SGML,SGML,Standard Generalized Markup Language,SGML,ISO 8879:1986,"A meta-markup language, used to create markup languages such as DocBook.",GML,XML,markup
見にくいですね…。
エクセルで見やすくしてみましょう。(参考:エクセルでCSVOを見やすくする - はじめてのフォーマット)
ほかの例も見ていきましょう。
例2
{"menu": { "id": "file", "value": "File", "popup": { "menuitem": [ {"value": "New", "onclick": "CreateNewDoc()"}, {"value": "Open", "onclick": "OpenDoc()"}, {"value": "Close", "onclick": "CloseDoc()"} ] } }}
CSVO形式
例3
{"widget": { "debug": "on", "window": { "title": "Sample Konfabulator Widget", "name": "main_window", "width": 500, "height": 500 }, "image": { "src": "Images/Sun.png", "name": "sun1", "hOffset": 250, "vOffset": 250, "alignment": "center" }, "text": { "data": "Click Here", "size": 36, "style": "bold", "name": "text1", "hOffset": 250, "vOffset": 100, "alignment": "center", "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" } }}
CSVO形式
例4
{"web-app": { "servlet": [ { "servlet-name": "cofaxCDS", "servlet-class": "org.cofax.cds.CDSServlet", "init-param": { "configGlossary:installationAt": "Philadelphia, PA", "configGlossary:adminEmail": "ksm@pobox.com", "configGlossary:poweredBy": "Cofax", "configGlossary:poweredByIcon": "/images/cofax.gif", "configGlossary:staticPath": "/content/static", "templateProcessorClass": "org.cofax.WysiwygTemplate", "templateLoaderClass": "org.cofax.FilesTemplateLoader", "templatePath": "templates", "templateOverridePath": "", "defaultListTemplate": "listTemplate.htm", "defaultFileTemplate": "articleTemplate.htm", "useJSP": false, "jspListTemplate": "listTemplate.jsp", "jspFileTemplate": "articleTemplate.jsp", "cachePackageTagsTrack": 200, "cachePackageTagsStore": 200, "cachePackageTagsRefresh": 60, "cacheTemplatesTrack": 100, "cacheTemplatesStore": 50, "cacheTemplatesRefresh": 15, "cachePagesTrack": 200, "cachePagesStore": 100, "cachePagesRefresh": 10, "cachePagesDirtyRead": 10, "searchEngineListTemplate": "forSearchEnginesList.htm", "searchEngineFileTemplate": "forSearchEngines.htm", "searchEngineRobotsDb": "WEB-INF/robots.db", "useDataStore": true, "dataStoreClass": "org.cofax.SqlDataStore", "redirectionClass": "org.cofax.SqlRedirection", "dataStoreName": "cofax", "dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver", "dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon", "dataStoreUser": "sa", "dataStorePassword": "dataStoreTestQuery", "dataStoreTestQuery": "SET NOCOUNT ON;select test='test';", "dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log", "dataStoreInitConns": 10, "dataStoreMaxConns": 100, "dataStoreConnUsageLimit": 100, "dataStoreLogLevel": "debug", "maxUrlLength": 500}}, { "servlet-name": "cofaxEmail", "servlet-class": "org.cofax.cds.EmailServlet", "init-param": { "mailHost": "mail1", "mailHostOverride": "mail2"}}, { "servlet-name": "cofaxAdmin", "servlet-class": "org.cofax.cds.AdminServlet"}, { "servlet-name": "fileServlet", "servlet-class": "org.cofax.cds.FileServlet"}, { "servlet-name": "cofaxTools", "servlet-class": "org.cofax.cms.CofaxToolsServlet", "init-param": { "templatePath": "toolstemplates/", "log": 1, "logLocation": "/usr/local/tomcat/logs/CofaxTools.log", "logMaxSize": "", "dataLog": 1, "dataLogLocation": "/usr/local/tomcat/logs/dataLog.log", "dataLogMaxSize": "", "removePageCache": "/content/admin/remove?cache=pages&id=", "removeTemplateCache": "/content/admin/remove?cache=templates&id=", "fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder", "lookInContext": 1, "adminGroupID": 4, "betaServer": true}}], "servlet-mapping": { "cofaxCDS": "/", "cofaxEmail": "/cofaxutil/aemail/*", "cofaxAdmin": "/admin/*", "fileServlet": "/static/*", "cofaxTools": "/tools/*"}, "taglib": { "taglib-uri": "cofax.tld", "taglib-location": "/WEB-INF/tlds/cofax.tld"}}}
CSVO形式
見えない…。
行/列を入れ替えてみましょう。
見やすくなりました。
例5
{"menu": { "header": "SVG Viewer", "items": [ {"id": "Open"}, {"id": "OpenNew", "label": "Open New"}, null, {"id": "ZoomIn", "label": "Zoom In"}, {"id": "ZoomOut", "label": "Zoom Out"}, {"id": "OriginalView", "label": "Original View"}, null, {"id": "Quality"}, {"id": "Pause"}, {"id": "Mute"}, null, {"id": "Find", "label": "Find..."}, {"id": "FindAgain", "label": "Find Again"}, {"id": "Copy"}, {"id": "CopyAgain", "label": "Copy Again"}, {"id": "CopySVG", "label": "Copy SVG"}, {"id": "ViewSVG", "label": "View SVG"}, {"id": "ViewSource", "label": "View Source"}, {"id": "SaveAs", "label": "Save As"}, null, {"id": "Help"}, {"id": "About", "label": "About Adobe CVG Viewer..."} ] }}
CSVO形式
こちらも行/列を入れ替えてみましょう。
さまざまなJSONデータをCSVO形式に変換してみました。
エクセルでCSVOを見やすくする
こちらで作ったデータを見やすくしてみましょう。
このようなデータです。
K1,,,K2,,, K1-1,,K1-2,*,,*, K1-1-1,K1-1-2,,K2-1,K2-2,K2-1,K2-2 ,,,,,, R1V1,R1V2,R1V3,R1V4,R1V5,R1V6,R1V7 R2V1,R2V2,R2V3,R2V4,R2V5,R2V6,R2V7
エクセルで開きます。
項目から次の項目の手前のセルまで選択し、
結合します(結合が好きではない場合は文字の横位置を「選択範囲内で中央」にしましょう)。
他の項目や下の階層の項目も結合しましょう。
縦方向も結合してしまいましょう(結合が好きではない場合は、文字の縦位置には「選択範囲内で中央」がないので、そのままにしておきましょう)。
出来ました。 データの構造がわかりやすくなりましたね。
そのままCSV形式で保存すると整形前とまったく同じデータが出力されます。
K1,,,K2,,, K1-1,,K1-2,*,,*, K1-1-1,K1-1-2,,K2-1,K2-2,K2-1,K2-2 ,,,,,, R1V1,R1V2,R1V3,R1V4,R1V5,R1V6,R1V7 R2V1,R2V2,R2V3,R2V4,R2V5,R2V6,R2V7
エクセルでCSVOデータを作る
手入力でCSVOのデータを作るならエクセルを使うとかんたんです。
CSVOの書き方はこちらを見てください。
エクセルでデータを入力します。
ファイルの種類をCSVにして保存します。
保存したファイルをメモ帳などで開いてみましょう。
K1,,,K2,,, K1-1,,K1-2,*,,*, K1-1-1,K1-1-2,,K2-1,K2-2,K2-1,K2-2 ,,,,,, R1V1,R1V2,R1V3,R1V4,R1V5,R1V6,R1V7 R2V1,R2V2,R2V3,R2V4,R2V5,R2V6,R2V7
出来ましたね。
ネストしたデータも表現できるCSV
一般的なCSVはネストしたデータをうまく表現できません。
そこでネストしたデータを自然に表現できるようにCSVを拡張したデータ形式を考えました。
このデータ形式をCSVO(CSV for Object)と仮に名付けます。
概要を見ていきましょう。
ヘッダ
CSVではヘッダは必須ではありません。
ヘッダがある場合は1行目がヘッダであり、2行目からデータがはじまります。
こんな感じですね。
(※以降のサンプルでは見やすいように適宜空白を入れています。)
K1, K2, K3 R1V1, R1V2, R1V3 R2V1, R2V2, R2V3
1行目はヘッダ行です。
このデータをJSONで表すと以下のようになります。
[ {"K1": "R1V1", "K2": "R1V2", "K3": "R1V3"}, {"K1": "R2V1", "K2": "R2V2", "K3": "R2V3"} ]
このデータをCSVOでは以下のように書きます。
K1, K2, K3 R1V1, R1V2, R1V3 R2V1, R2V2, R2V3
CSVOではヘッダとデータの間には空行をはさみます。
あるいはカンマなどの区切り文字は残っていてもよいでしょう。
K1, K2, K3 ,, R1V1, R1V2, R1V3 R2V1, R2V2, R2V3
そしてヘッダは複数行になることができます。
そのことでネストが表現できるようになります。
ネストの表現
こんなデータから始めましょう。
K1, K2 V1, V2
JSONで表すとこうですね。
(以降ではすべてのサンプルにそのデータのJSON表現をつけます。)
[ { "K1": "V1", "K2": "V2" } ]
K2をネストさせてみましょう。
ネストが始まったらヘッダ行を増やして次の行に移動します。
K1, K2 , , K2-1, K2-2 V1, V2-1, V2-2
[ { "K1": "V1", "K2": { "K2-1": "V2-1", "K2-2": "V2-2", } } ]
ネストが終わったら元の行に戻ります。
K1, K2 , , K3 , K2-1, K2-2, V1, V2-1, V2-2, V3
[ { "K1": "V1", "K2": { "K2-1": "V2-1", "K2-2": "V2-2", }, "K3": "V3" } ]
配列の表現
配列も表現できるようにしましょう。
配列は「*」をキーの代わりに使います。
*, *, * V1, V2, V3
[ ["V1", "V2", "V3"] ]
こちらもネストできます。
K1 , , , * , , * , K1-1, K1-2, K1-1, K1-2 V1 , V2 , V3 , V4
[ { "K1": [ {"K1-1": "V1", "K1-2": "V2"}, {"K1-1": "V3", "K1-2": "V4"} ] } ]
これでいろんなデータが表現できますね。