この答えはあなたが探しているものではないかもしれません。確かに単純な解決策ではありません。このヘルパー クラスは、DOM-XML パーサーとは異なり、SAX-XML パーサーのように入力ファイルを読み取ります。
私のユースケースは、大規模な「ランダムに」構造化された json ファイルと更新データベース オブジェクトです。これにより、ドキュメント全体が RAM メモリに読み込まれることはありません。厳密に型指定されたオブジェクトを使用できないため、ハッシュマップ ソリューションを使用しました。
これは、入力ファイルをループし、指定されたブレークポイント オブジェクト パスごとにフィールド値を収集し、ハンドラー関数を呼び出します。Hashmap にはparent.entry.field=xxxxx値があり、keyval ペアをダンプして命名構文を確認します。
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Stack;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
public class JSONHandler {
private Stack<String> parents;
private String cachedParent;
private Map<String,String> entry;
private Map<String,String> parentEntry;
public JSONHandler(JSONHandler.EntryHandler handler, JsonParser jsonP,
String path) throws Exception {
parents = new Stack<String>();
entry = new LinkedHashMap<String,String>(16);// new HashMap<String,String>(16);
parentEntry = new LinkedHashMap<String,String>(8);
if (!path.endsWith(".")) path+=".";
boolean isParent=true;
int arrayIdx=-1;
cachedParent="";
JsonToken token;
boolean doProcess=true;
while ( (token=jsonP.nextToken()) != null) {
String name = jsonP.getCurrentName();
if (token == JsonToken.START_OBJECT) {
parents.push(name);
if (cachedParent.equals(path)) {
entry.clear(); // start new target entry
arrayIdx=0;
if (!parentEntry.isEmpty()) entry.putAll(parentEntry);
isParent=false;
} else if (!cachedParent.startsWith(path)) {
isParent=true; // add fields to parent entry
}
cachedParent = implodeStack(parents);
} else if (token == JsonToken.END_OBJECT) {
parents.pop();
cachedParent = implodeStack(parents);
if (cachedParent.equals(path)) {
doProcess=handler.process(entry);
arrayIdx=-1;
if (!doProcess) break;
} else if (name==null && cachedParent.startsWith(path)) {
String sArrayIdx = parents.peek(); // increment arrayIndex+1
parents.set(parents.size()-1, ""+(Integer.parseInt(sArrayIdx)+1) );
cachedParent = implodeStack(parents);
} else if (!cachedParent.startsWith(path)) {
Iterator<Map.Entry<String,String>> iter=parentEntry.entrySet().iterator();
while(iter.hasNext()) {
Map.Entry<String,String> me = iter.next();
if (me.getKey().startsWith(cachedParent))
iter.remove();
}
}
} else if (token == JsonToken.START_ARRAY) {
parents.push(name);
if (arrayIdx>-1) parents.push(String.valueOf(arrayIdx));
cachedParent = implodeStack(parents);
} else if (token == JsonToken.END_ARRAY) {
parents.pop();
if (arrayIdx>-1) {
parents.pop();
arrayIdx=0;
}
cachedParent = implodeStack(parents);
} else if (token == JsonToken.FIELD_NAME) {
//System.out.println("field="+jsonP.getCurrentName());
} else {
String value;
if (token == JsonToken.VALUE_NULL) value = null;
else if (token == JsonToken.VALUE_TRUE) value = "1";
else if (token == JsonToken.VALUE_FALSE) value = "0";
else value = jsonP.getText();
if (cachedParent.startsWith(path)) {
if (name==null && arrayIdx>-1) {
// simple array "values":["aa","bb","cc"],
// write parent.item.values.0=aa, .1=bb, .2=cc
parents.set(parents.size()-1, ""+(arrayIdx++) );
cachedParent = implodeStack(parents);
entry.put(cachedParent.substring(0,cachedParent.length()-1), value);
} else
entry.put(cachedParent+name, value);
} else if (isParent) {
parentEntry.put(cachedParent+name, value);
}
}
}
}
private String implodeStack(Stack<String> stack) {
StringBuilder sb = new StringBuilder();
for(String value : stack) {
if (value!=null)
sb.append(value + ".");
}
return sb.toString();
}
public static interface EntryHandler {
public void startDocument() throws Exception;
public boolean process(Map<String,String> entry) throws Exception;
}
}
クライアント例
JSONHandler.EntryHandler handler = new JSONHandler.EntryHandler() {
public void startDocument() throws Exception {};
public boolean process(Map<String,String> entry) throws Exception {
for(String key : entry.keySet())
System.out.println(key+"="+entry.get(key));
return true;
}
};
JsonFactory jsonF = new JsonFactory();
jsonF.enable(JsonParser.Feature.AUTO_CLOSE_SOURCE);
JsonParser jsonP = jsonF.createParser(file);
try {
handler.startDocument();
new JSONHandler(handler, jsonP, "list");
} finally {
jsonP.close();
}
(私のアプリケーションからの単純化をコピーペーストすると、構文エラーが発生する可能性があります)