JSONのVisitorPatternをやってみた
背景もどき
諸般の事情があり、JSONをVisitorパターン的に取り扱うことになりました。JSONはツリー構造になっているので、Visitorパターンが使える仕組みがあるのかとおもったのですが、org.jsonのAPIにはVisitorパターンはサポートされていないようです。
下記のような話もあったようですが、進展があるようには思われませんでした。
[JSON_PROCESSING_SPEC-64] Implement visitor pattern for JSON traversal - Java.net JIRA
どちらかというと、JSONとJavaオブジェクトを相互にマッピングすることのほうが、世の中的には、着目されているとおもいます。
ともあれ、jsonにてvisitorパターンを使う方法を考えてみました。
なお、ここのエントリでのjsonのライブラリはandroidで使っているjsonライブラリです。
json - platform/libcore - Git at Google
実装のアイデア
すでにあるライブラリのインターフェースにVisitorのインターフェースを加えたいわけです。ただ、Androidでの利用を考えると、リフレクション的なことはパフォーマンスが遅くなり、できません。素直に(?)Jsonオブジェクトをラップすることにしました。
やりたいことは、JSONObjectでのVisitorパターンですが、visit対象となる型がJSONObjectしかないので、型による場合わけができません。この点は、JSONObjectをValueとした時の、key側で区別をすることにします。
また、JSONArrayの場合は、Arrayの中のJSONObjectを順次visitしていくわけですが、インデッックスもインターフェースすることにします。
ネストの深さのインターフェースも考えましたが、同じキーで深さの異なるJSONObjectは、論理的にありえても、実際の業務ではなさそうな気がするのでやめました。
下記で、org.json1となっているのは、Android Studio上で、素のJavaアプリとして動かしたかったので、上述のjsonのソースをダウンロードして、パッケージ名を変えて、プロジェクトに突っ込んで言います。あくまで便宜的にやっています。(もっと上手い方法があるとはおもいますが、やりかたがわかりませんでした。)
実装1
Visitorインターフェース
package com.example.test08; import org.json1.JSONObject; public interface Visitor2 { void visit(String key, int idx, JSONObject obj); }
Visitorの実装
とりあえずコンソールに表示するだけで、今の段階ではキーごとの振り分けはやっていません。
package com.example.test08; import org.json1.JSONObject; public class LogVisitor2 implements Visitor2 { @Override public void visit(String key, int idx, JSONObject obj) { System.out.println(key + "[" + idx +"]:" + obj); } }
使い方
jsonファイルがあるとして、それを読み込んで、JSONObjectにします。それをラップしたうえで、Visitorを使います。
private static void visitorLog(String path) throws FileNotFoundException, JSONException { String content = new Scanner(new File(path)).useDelimiter("\\Z").next(); log(content); JSONObject obj = new JSONObject(content); LogVisitor2 v = new LogVisitor2(); new JSONVisitedWrapper2("root", 0, obj).accept(v); // (実装をサボっているため)ルートのキーとindexを渡しておく }
ラッパー実装
JSONObjectの中身は、キーがわかっていない場合は、keyのitereterをつかってアクセスするしか方法がありません。 また、keyに対するvalueは、下記の場合分けとしました。
- 普通の値(String, int, ..) -> Visitの対象としない
- JSONObject -> Visitの対象とする
- JSONArray -> 要素がJSONObjectの場合再帰してVisitの対象とする
- ヌル -> 対象とするかしないかはフラグで判断する
こんな感じの実装になると思います。かなり雑ですが。
package com.example.test08; import org.json1.JSONArray; import org.json1.JSONException; import org.json1.JSONObject; import java.util.Iterator; public class JSONVisitedWrapper2 { private boolean isNullSkip = true; // ヌルはvisitの対象としない private JSONObject json; private String key; // 処理対象のjsonのキー(最初に与えるJSON(いわゆるルートノード)のキーは外から与える) private int idx; // JSONArrayのインデックス(JSONObjectの場合はゼロとする) public JSONVisitedWrapper2(String key, int idx, JSONObject json) { this.key = key; this.idx = idx; this.json = json; } public JSONVisitedWrapper2(String key, int idx, JSONObject json, boolean isNullSkip) { this.key = key; this.idx = idx; this.json = json; this.isNullSkip = isNullSkip; } public void accept(Visitor2 visitor) { visitor.visit(this.key, this.idx, json); try { Iterator it = json.keys(); while (it.hasNext()) { String key = (String)it.next(); if (json.isNull(key)) { if (isNullSkip) { continue; } else { visitor.visit(key, 0, null); continue; } } Object next = json.get(key); if (next instanceof JSONObject) { // System.out.println("key=" + key); JSONObject jsonObj = (JSONObject)next; new JSONVisitedWrapper2(key, 0, jsonObj, this.isNullSkip).accept(visitor); } else if (next instanceof JSONArray) { JSONArray jsonArr = (JSONArray)next; for (int i=0; i < jsonArr.length(); i++) { if (jsonArr.isNull(i)) { if (isNullSkip) { continue; } else { visitor.visit(key, i, null); continue; } } Object obj = jsonArr.get(i); if (obj instanceof JSONObject) { new JSONVisitedWrapper2(key, i, (JSONObject)obj, this.isNullSkip).accept(visitor); } } } } } catch (JSONException e) { throw new RuntimeException(e);あ } } }
実行例
テストコードは下記
package com.example.test08; import org.json1.JSONException; import org.json1.JSONObject; import java.io.File; import java.io.FileNotFoundException; import java.util.Scanner; public class Test08_2 { public static void main(String[] args) throws JSONException, FileNotFoundException { String base = "foobar/Test08/app/data/"; String path; log("http://json.org/example.html"); path = "/Users/ogawanaoto/AndroidStudioProjects/Test08/app/data/json01.json"; visitorLog(path); log("----------------"); log("http://www.w3schools.com/json/ #1"); path = base + "json02.json"; visitorLog(path); log("----------------"); log("http://www.w3schools.com/json/ #2"); path = base + "json03.json"; visitorLog(path); log("----------------"); log("http://www.w3schools.com/json/ #3"); path = base + "json04.json"; visitorLog(path); log("----------------"); log("http://www.w3schools.com/json/ #4"); path = base + "json05.json"; visitorLog(path); log("----------------"); log("http://www.w3schools.com/json/ #5"); path = base + "json06.json"; visitorLog(path); } private static void visitorLog(String path) throws FileNotFoundException, JSONException { String content = new Scanner(new File(path)).useDelimiter("\\Z").next(); log(content); JSONObject obj = new JSONObject(content); LogVisitor2 v = new LogVisitor2(); new JSONVisitedWrapper2("root", 0, obj).accept(v); } private static void log(Object obj) { System.out.println(obj); } }
実行結果は下記
/Library/Java/JavaVirtualMachines/jdk1.8.0_05.jdk/Contents/Home/bin/java -Didea.launcher.port=7535 "-Didea.launcher.bin.path=/Applications/Android Studio.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath "/Users/ogawanaoto/java/adt-bundle-mac-x86_64-20140321/sdk/platforms/android-21/android.jar:/Users/ogawanaoto/java/adt-bundle-mac-x86_64-20140321/sdk/platforms/android-21/data/res:/Users/ogawanaoto/AndroidStudioProjects/Test08/app/build/intermediates/classes/debug:/Users/ogawanaoto/AndroidStudioProjects/Test08/app/build/intermediates/exploded-aar/com.android.support/appcompat-v7/21.0.3/jars/classes.jar:/Users/ogawanaoto/AndroidStudioProjects/Test08/app/build/intermediates/exploded-aar/com.android.support/appcompat-v7/21.0.3/res:/Users/ogawanaoto/AndroidStudioProjects/Test08/app/build/intermediates/exploded-aar/com.android.support/support-v4/21.0.3/jars/libs/internal_impl-21.0.3.jar:/Users/ogawanaoto/AndroidStudioProjects/Test08/app/build/intermediates/exploded-aar/com.android.support/support-v4/21.0.3/res:/Users/ogawanaoto/AndroidStudioProjects/Test08/app/build/intermediates/exploded-aar/com.android.support/support-v4/21.0.3/jars/classes.jar:/Users/ogawanaoto/java/adt-bundle-mac-x86_64-20140321/sdk/extras/android/m2repository/com/android/support/support-annotations/21.0.3/support-annotations-21.0.3.jar:/Applications/Android Studio.app/Contents/lib/idea_rt.jar" com.intellij.rt.execution.application.AppMain com.example.test08.Test08_2 http://json.org/example.html {"employees":[ {"firstName":"John", "lastName":"Doe"}, {"firstName":"Anna", "lastName":"Smith"}, {"firstName":"Peter", "lastName":"Jones"} ]} root[0]:{"employees":[{"firstName":"John","lastName":"Doe"},{"firstName":"Anna","lastName":"Smith"},{"firstName":"Peter","lastName":"Jones"}]} employees[0]:{"firstName":"John","lastName":"Doe"} employees[1]:{"firstName":"Anna","lastName":"Smith"} employees[2]:{"firstName":"Peter","lastName":"Jones"} ---------------- http://www.w3schools.com/json/ #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" } } } } } root[0]:{"glossary":{"title":"example glossary","GlossDiv":{"GlossList":{"GlossEntry":{"GlossTerm":"Standard Generalized Markup Language","GlossSee":"markup","SortAs":"SGML","GlossDef":{"para":"A meta-markup language, used to create markup languages such as DocBook.","GlossSeeAlso":["GML","XML"]},"ID":"SGML","Acronym":"SGML","Abbrev":"ISO 8879:1986"}},"title":"S"}}} glossary[0]:{"title":"example glossary","GlossDiv":{"GlossList":{"GlossEntry":{"GlossTerm":"Standard Generalized Markup Language","GlossSee":"markup","SortAs":"SGML","GlossDef":{"para":"A meta-markup language, used to create markup languages such as DocBook.","GlossSeeAlso":["GML","XML"]},"ID":"SGML","Acronym":"SGML","Abbrev":"ISO 8879:1986"}},"title":"S"}} GlossDiv[0]:{"GlossList":{"GlossEntry":{"GlossTerm":"Standard Generalized Markup Language","GlossSee":"markup","SortAs":"SGML","GlossDef":{"para":"A meta-markup language, used to create markup languages such as DocBook.","GlossSeeAlso":["GML","XML"]},"ID":"SGML","Acronym":"SGML","Abbrev":"ISO 8879:1986"}},"title":"S"} GlossList[0]:{"GlossEntry":{"GlossTerm":"Standard Generalized Markup Language","GlossSee":"markup","SortAs":"SGML","GlossDef":{"para":"A meta-markup language, used to create markup languages such as DocBook.","GlossSeeAlso":["GML","XML"]},"ID":"SGML","Acronym":"SGML","Abbrev":"ISO 8879:1986"}} GlossEntry[0]:{"GlossTerm":"Standard Generalized Markup Language","GlossSee":"markup","SortAs":"SGML","GlossDef":{"para":"A meta-markup language, used to create markup languages such as DocBook.","GlossSeeAlso":["GML","XML"]},"ID":"SGML","Acronym":"SGML","Abbrev":"ISO 8879:1986"} GlossDef[0]:{"para":"A meta-markup language, used to create markup languages such as DocBook.","GlossSeeAlso":["GML","XML"]} ---------------- http://www.w3schools.com/json/ #2 {"menu": { "id": "file", "value": "File", "popup": { "menuitem": [ {"value": "New", "onclick": "CreateNewDoc()"}, {"value": "Open", "onclick": "OpenDoc()"}, {"value": "Close", "onclick": "CloseDoc()"} ] } }} root[0]:{"menu":{"popup":{"menuitem":[{"onclick":"CreateNewDoc()","value":"New"},{"onclick":"OpenDoc()","value":"Open"},{"onclick":"CloseDoc()","value":"Close"}]},"id":"file","value":"File"}} menu[0]:{"popup":{"menuitem":[{"onclick":"CreateNewDoc()","value":"New"},{"onclick":"OpenDoc()","value":"Open"},{"onclick":"CloseDoc()","value":"Close"}]},"id":"file","value":"File"} popup[0]:{"menuitem":[{"onclick":"CreateNewDoc()","value":"New"},{"onclick":"OpenDoc()","value":"Open"},{"onclick":"CloseDoc()","value":"Close"}]} menuitem[0]:{"onclick":"CreateNewDoc()","value":"New"} menuitem[1]:{"onclick":"OpenDoc()","value":"Open"} menuitem[2]:{"onclick":"CloseDoc()","value":"Close"} ---------------- http://www.w3schools.com/json/ #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;" } }} root[0]:{"widget":{"image":{"vOffset":250,"src":"Images\/Sun.png","name":"sun1","alignment":"center","hOffset":250},"debug":"on","window":{"name":"main_window","width":500,"title":"Sample Konfabulator Widget","height":500},"text":{"vOffset":100,"data":"Click Here","size":36,"name":"text1","style":"bold","alignment":"center","onMouseUp":"sun1.opacity = (sun1.opacity \/ 100) * 90;","hOffset":250}}} widget[0]:{"image":{"vOffset":250,"src":"Images\/Sun.png","name":"sun1","alignment":"center","hOffset":250},"debug":"on","window":{"name":"main_window","width":500,"title":"Sample Konfabulator Widget","height":500},"text":{"vOffset":100,"data":"Click Here","size":36,"name":"text1","style":"bold","alignment":"center","onMouseUp":"sun1.opacity = (sun1.opacity \/ 100) * 90;","hOffset":250}} image[0]:{"vOffset":250,"src":"Images\/Sun.png","name":"sun1","alignment":"center","hOffset":250} window[0]:{"name":"main_window","width":500,"title":"Sample Konfabulator Widget","height":500} text[0]:{"vOffset":100,"data":"Click Here","size":36,"name":"text1","style":"bold","alignment":"center","onMouseUp":"sun1.opacity = (sun1.opacity \/ 100) * 90;","hOffset":250} ---------------- http://www.w3schools.com/json/ #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"}}} root[0]:{"web-app":{"servlet-mapping":{"cofaxAdmin":"\/admin\/*","cofaxCDS":"\/","cofaxEmail":"\/cofaxutil\/aemail\/*","fileServlet":"\/static\/*","cofaxTools":"\/tools\/*"},"taglib":{"taglib-location":"\/WEB-INF\/tlds\/cofax.tld","taglib-uri":"cofax.tld"},"servlet":[{"init-param":{"cachePackageTagsTrack":200,"redirectionClass":"org.cofax.SqlRedirection","configGlossary:staticPath":"\/content\/static","jspFileTemplate":"articleTemplate.jsp","cacheTemplatesRefresh":15,"dataStorePassword":"dataStoreTestQuery","dataStoreClass":"org.cofax.SqlDataStore","configGlossary:installationAt":"Philadelphia, PA","cacheTemplatesTrack":100,"configGlossary:poweredBy":"Cofax","searchEngineFileTemplate":"forSearchEngines.htm","defaultFileTemplate":"articleTemplate.htm","configGlossary:adminEmail":"ksm@pobox.com","templateProcessorClass":"org.cofax.WysiwygTemplate","searchEngineListTemplate":"forSearchEnginesList.htm","cachePagesStore":100,"useDataStore":true,"templateLoaderClass":"org.cofax.FilesTemplateLoader","configGlossary:poweredByIcon":"\/images\/cofax.gif","cachePagesTrack":200,"searchEngineRobotsDb":"WEB-INF\/robots.db","cachePagesDirtyRead":10,"cachePackageTagsStore":200,"cachePackageTagsRefresh":60,"dataStoreConnUsageLimit":100,"useJSP":false,"dataStoreLogLevel":"debug","dataStoreUrl":"jdbc:microsoft:sqlserver:\/\/LOCALHOST:1433;DatabaseName=goon","templatePath":"templates","cacheTemplatesStore":50,"jspListTemplate":"listTemplate.jsp","dataStoreTestQuery":"SET NOCOUNT ON;select test='test';","dataStoreMaxConns":100,"dataStoreName":"cofax","maxUrlLength":500,"templateOverridePath":"","cachePagesRefresh":10,"dataStoreDriver":"com.microsoft.jdbc.sqlserver.SQLServerDriver","dataStoreUser":"sa","dataStoreLogFile":"\/usr\/local\/tomcat\/logs\/datastore.log","defaultListTemplate":"listTemplate.htm","dataStoreInitConns":10},"servlet-name":"cofaxCDS","servlet-class":"org.cofax.cds.CDSServlet"},{"init-param":{"mailHost":"mail1","mailHostOverride":"mail2"},"servlet-name":"cofaxEmail","servlet-class":"org.cofax.cds.EmailServlet"},{"servlet-name":"cofaxAdmin","servlet-class":"org.cofax.cds.AdminServlet"},{"servlet-name":"fileServlet","servlet-class":"org.cofax.cds.FileServlet"},{"init-param":{"dataLogMaxSize":"","log":1,"logMaxSize":"","templatePath":"toolstemplates\/","fileTransferFolder":"\/usr\/local\/tomcat\/webapps\/content\/fileTransferFolder","removeTemplateCache":"\/content\/admin\/remove?cache=templates&id=","dataLogLocation":"\/usr\/local\/tomcat\/logs\/dataLog.log","lookInContext":1,"removePageCache":"\/content\/admin\/remove?cache=pages&id=","adminGroupID":4,"betaServer":true,"logLocation":"\/usr\/local\/tomcat\/logs\/CofaxTools.log","dataLog":1},"servlet-name":"cofaxTools","servlet-class":"org.cofax.cms.CofaxToolsServlet"}]}} web-app[0]:{"servlet-mapping":{"cofaxAdmin":"\/admin\/*","cofaxCDS":"\/","cofaxEmail":"\/cofaxutil\/aemail\/*","fileServlet":"\/static\/*","cofaxTools":"\/tools\/*"},"taglib":{"taglib-location":"\/WEB-INF\/tlds\/cofax.tld","taglib-uri":"cofax.tld"},"servlet":[{"init-param":{"cachePackageTagsTrack":200,"redirectionClass":"org.cofax.SqlRedirection","configGlossary:staticPath":"\/content\/static","jspFileTemplate":"articleTemplate.jsp","cacheTemplatesRefresh":15,"dataStorePassword":"dataStoreTestQuery","dataStoreClass":"org.cofax.SqlDataStore","configGlossary:installationAt":"Philadelphia, PA","cacheTemplatesTrack":100,"configGlossary:poweredBy":"Cofax","searchEngineFileTemplate":"forSearchEngines.htm","defaultFileTemplate":"articleTemplate.htm","configGlossary:adminEmail":"ksm@pobox.com","templateProcessorClass":"org.cofax.WysiwygTemplate","searchEngineListTemplate":"forSearchEnginesList.htm","cachePagesStore":100,"useDataStore":true,"templateLoaderClass":"org.cofax.FilesTemplateLoader","configGlossary:poweredByIcon":"\/images\/cofax.gif","cachePagesTrack":200,"searchEngineRobotsDb":"WEB-INF\/robots.db","cachePagesDirtyRead":10,"cachePackageTagsStore":200,"cachePackageTagsRefresh":60,"dataStoreConnUsageLimit":100,"useJSP":false,"dataStoreLogLevel":"debug","dataStoreUrl":"jdbc:microsoft:sqlserver:\/\/LOCALHOST:1433;DatabaseName=goon","templatePath":"templates","cacheTemplatesStore":50,"jspListTemplate":"listTemplate.jsp","dataStoreTestQuery":"SET NOCOUNT ON;select test='test';","dataStoreMaxConns":100,"dataStoreName":"cofax","maxUrlLength":500,"templateOverridePath":"","cachePagesRefresh":10,"dataStoreDriver":"com.microsoft.jdbc.sqlserver.SQLServerDriver","dataStoreUser":"sa","dataStoreLogFile":"\/usr\/local\/tomcat\/logs\/datastore.log","defaultListTemplate":"listTemplate.htm","dataStoreInitConns":10},"servlet-name":"cofaxCDS","servlet-class":"org.cofax.cds.CDSServlet"},{"init-param":{"mailHost":"mail1","mailHostOverride":"mail2"},"servlet-name":"cofaxEmail","servlet-class":"org.cofax.cds.EmailServlet"},{"servlet-name":"cofaxAdmin","servlet-class":"org.cofax.cds.AdminServlet"},{"servlet-name":"fileServlet","servlet-class":"org.cofax.cds.FileServlet"},{"init-param":{"dataLogMaxSize":"","log":1,"logMaxSize":"","templatePath":"toolstemplates\/","fileTransferFolder":"\/usr\/local\/tomcat\/webapps\/content\/fileTransferFolder","removeTemplateCache":"\/content\/admin\/remove?cache=templates&id=","dataLogLocation":"\/usr\/local\/tomcat\/logs\/dataLog.log","lookInContext":1,"removePageCache":"\/content\/admin\/remove?cache=pages&id=","adminGroupID":4,"betaServer":true,"logLocation":"\/usr\/local\/tomcat\/logs\/CofaxTools.log","dataLog":1},"servlet-name":"cofaxTools","servlet-class":"org.cofax.cms.CofaxToolsServlet"}]} servlet-mapping[0]:{"cofaxAdmin":"\/admin\/*","cofaxCDS":"\/","cofaxEmail":"\/cofaxutil\/aemail\/*","fileServlet":"\/static\/*","cofaxTools":"\/tools\/*"} taglib[0]:{"taglib-location":"\/WEB-INF\/tlds\/cofax.tld","taglib-uri":"cofax.tld"} servlet[0]:{"init-param":{"cachePackageTagsTrack":200,"redirectionClass":"org.cofax.SqlRedirection","configGlossary:staticPath":"\/content\/static","jspFileTemplate":"articleTemplate.jsp","cacheTemplatesRefresh":15,"dataStorePassword":"dataStoreTestQuery","dataStoreClass":"org.cofax.SqlDataStore","configGlossary:installationAt":"Philadelphia, PA","cacheTemplatesTrack":100,"configGlossary:poweredBy":"Cofax","searchEngineFileTemplate":"forSearchEngines.htm","defaultFileTemplate":"articleTemplate.htm","configGlossary:adminEmail":"ksm@pobox.com","templateProcessorClass":"org.cofax.WysiwygTemplate","searchEngineListTemplate":"forSearchEnginesList.htm","cachePagesStore":100,"useDataStore":true,"templateLoaderClass":"org.cofax.FilesTemplateLoader","configGlossary:poweredByIcon":"\/images\/cofax.gif","cachePagesTrack":200,"searchEngineRobotsDb":"WEB-INF\/robots.db","cachePagesDirtyRead":10,"cachePackageTagsStore":200,"cachePackageTagsRefresh":60,"dataStoreConnUsageLimit":100,"useJSP":false,"dataStoreLogLevel":"debug","dataStoreUrl":"jdbc:microsoft:sqlserver:\/\/LOCALHOST:1433;DatabaseName=goon","templatePath":"templates","cacheTemplatesStore":50,"jspListTemplate":"listTemplate.jsp","dataStoreTestQuery":"SET NOCOUNT ON;select test='test';","dataStoreMaxConns":100,"dataStoreName":"cofax","maxUrlLength":500,"templateOverridePath":"","cachePagesRefresh":10,"dataStoreDriver":"com.microsoft.jdbc.sqlserver.SQLServerDriver","dataStoreUser":"sa","dataStoreLogFile":"\/usr\/local\/tomcat\/logs\/datastore.log","defaultListTemplate":"listTemplate.htm","dataStoreInitConns":10},"servlet-name":"cofaxCDS","servlet-class":"org.cofax.cds.CDSServlet"} init-param[0]:{"cachePackageTagsTrack":200,"redirectionClass":"org.cofax.SqlRedirection","configGlossary:staticPath":"\/content\/static","jspFileTemplate":"articleTemplate.jsp","cacheTemplatesRefresh":15,"dataStorePassword":"dataStoreTestQuery","dataStoreClass":"org.cofax.SqlDataStore","configGlossary:installationAt":"Philadelphia, PA","cacheTemplatesTrack":100,"configGlossary:poweredBy":"Cofax","searchEngineFileTemplate":"forSearchEngines.htm","defaultFileTemplate":"articleTemplate.htm","configGlossary:adminEmail":"ksm@pobox.com","templateProcessorClass":"org.cofax.WysiwygTemplate","searchEngineListTemplate":"forSearchEnginesList.htm","cachePagesStore":100,"useDataStore":true,"templateLoaderClass":"org.cofax.FilesTemplateLoader","configGlossary:poweredByIcon":"\/images\/cofax.gif","cachePagesTrack":200,"searchEngineRobotsDb":"WEB-INF\/robots.db","cachePagesDirtyRead":10,"cachePackageTagsStore":200,"cachePackageTagsRefresh":60,"dataStoreConnUsageLimit":100,"useJSP":false,"dataStoreLogLevel":"debug","dataStoreUrl":"jdbc:microsoft:sqlserver:\/\/LOCALHOST:1433;DatabaseName=goon","templatePath":"templates","cacheTemplatesStore":50,"jspListTemplate":"listTemplate.jsp","dataStoreTestQuery":"SET NOCOUNT ON;select test='test';","dataStoreMaxConns":100,"dataStoreName":"cofax","maxUrlLength":500,"templateOverridePath":"","cachePagesRefresh":10,"dataStoreDriver":"com.microsoft.jdbc.sqlserver.SQLServerDriver","dataStoreUser":"sa","dataStoreLogFile":"\/usr\/local\/tomcat\/logs\/datastore.log","defaultListTemplate":"listTemplate.htm","dataStoreInitConns":10} servlet[1]:{"init-param":{"mailHost":"mail1","mailHostOverride":"mail2"},"servlet-name":"cofaxEmail","servlet-class":"org.cofax.cds.EmailServlet"} init-param[0]:{"mailHost":"mail1","mailHostOverride":"mail2"} servlet[2]:{"servlet-name":"cofaxAdmin","servlet-class":"org.cofax.cds.AdminServlet"} servlet[3]:{"servlet-name":"fileServlet","servlet-class":"org.cofax.cds.FileServlet"} servlet[4]:{"init-param":{"dataLogMaxSize":"","log":1,"logMaxSize":"","templatePath":"toolstemplates\/","fileTransferFolder":"\/usr\/local\/tomcat\/webapps\/content\/fileTransferFolder","removeTemplateCache":"\/content\/admin\/remove?cache=templates&id=","dataLogLocation":"\/usr\/local\/tomcat\/logs\/dataLog.log","lookInContext":1,"removePageCache":"\/content\/admin\/remove?cache=pages&id=","adminGroupID":4,"betaServer":true,"logLocation":"\/usr\/local\/tomcat\/logs\/CofaxTools.log","dataLog":1},"servlet-name":"cofaxTools","servlet-class":"org.cofax.cms.CofaxToolsServlet"} init-param[0]:{"dataLogMaxSize":"","log":1,"logMaxSize":"","templatePath":"toolstemplates\/","fileTransferFolder":"\/usr\/local\/tomcat\/webapps\/content\/fileTransferFolder","removeTemplateCache":"\/content\/admin\/remove?cache=templates&id=","dataLogLocation":"\/usr\/local\/tomcat\/logs\/dataLog.log","lookInContext":1,"removePageCache":"\/content\/admin\/remove?cache=pages&id=","adminGroupID":4,"betaServer":true,"logLocation":"\/usr\/local\/tomcat\/logs\/CofaxTools.log","dataLog":1} ---------------- http://www.w3schools.com/json/ #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..."} ] }} root[0]:{"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..."}]}} menu[0]:{"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..."}]} items[0]:{"id":"Open"} items[1]:{"id":"OpenNew","label":"Open New"} items[3]:{"id":"ZoomIn","label":"Zoom In"} items[4]:{"id":"ZoomOut","label":"Zoom Out"} items[5]:{"id":"OriginalView","label":"Original View"} items[7]:{"id":"Quality"} items[8]:{"id":"Pause"} items[9]:{"id":"Mute"} items[11]:{"id":"Find","label":"Find..."} items[12]:{"id":"FindAgain","label":"Find Again"} items[13]:{"id":"Copy"} items[14]:{"id":"CopyAgain","label":"Copy Again"} items[15]:{"id":"CopySVG","label":"Copy SVG"} items[16]:{"id":"ViewSVG","label":"View SVG"} items[17]:{"id":"ViewSource","label":"View Source"} items[18]:{"id":"SaveAs","label":"Save As"} items[20]:{"id":"Help"} items[21]:{"id":"About","label":"About Adobe CVG Viewer..."} Process finished with exit code 0
実装2
実際に使う時は下記のように業務に合わせてJSONObjectの場合わけをすることになると思います。
package com.example.test08; import org.json1.JSONObject; public abstract class LogVisitor2_Servlet implements Visitor2 { @Override public void visit(String key, int idx, JSONObject obj) { if ("root".equals(key)) { visitRoot(idx, obj); } else if ("web-app".equals(key)) { visitWebApp(idx, obj); }else if ("servlet".equals(key)) { visitServe(idx, obj); }else if ("servlet-mapping".equals(key)) { visitServeltMapping(idx, obj); }else if ("taglib".equals(key)) { visitTagLib(idx, obj); }else if ("init-param".equals(key)) { visitInitParam(idx, obj); } } abstract void visitRoot(int idx, JSONObject obj); abstract void visitWebApp(int idx, JSONObject obj) ; abstract void visitServe(int idx, JSONObject obj); abstract void visitServeltMapping(int idx, JSONObject obj); abstract void visitTagLib(int idx, JSONObject obj); abstract void visitInitParam(int idx, JSONObject obj); }
所感
- Visito対象とするノードの情報を外から与えるほうがよいと思う。ここでの実装は効率的ではない。
- ここでの実装は真偽値の対応ができていない。
- Nullの取り扱いが面倒。JSONではヌルは明示的にテキスト上nullという表現になる。
- 時間があったらテストしたい。いろいろ直したい。