package org.basex.query.util.json; import org.basex.query.QueryException; import org.basex.query.item.Bln; import org.basex.query.item.Dbl; import org.basex.query.item.Empty; import org.basex.query.item.Int; import org.basex.query.item.Str; import org.basex.query.item.Value; import org.basex.query.item.map.Map; import org.basex.util.InputInfo; import org.basex.util.list.TokenList; /** * <p>Provides a method for parsing a JSON string and converting it to an XQuery * item made of nested maps. * * <p>The mapping from JSON to XQuery is the following: * <p><dl> * <dt>string<dd>xs:string * <dt>number<dd>xs:double * <dt>boolean<dd>xs:boolean * <dt>null<dd>an empty sequence <code>()</code> * <dt>array (e.g. {@code ["foo", true, 123]}) * <dd>an XQuery map with integer keys, starting by 1 (e.g. * <code>map{1:='foo', 2:=true(), 3:=123}</code>) * <dt>object (e.g. <code>{"foo": 42, "bar": null}</code>) * <dd>an XQuery map (e.g. * <code>map{'foo':=42, 'bar':=()}</code>) * </dl> * @author BaseX Team 2005-12, BSD License * @author Leo Woerteler */ public final class JsonMapConverter { /** Hidden default constructor. */ private JsonMapConverter() { /* void */ } /** * Parses a JSON string and converts it to an XQuery item made of nested maps. * @param json JSON string * @param ii input info * @return XQuery item * @throws QueryException exception */ public static Value parse(final byte[] json, final InputInfo ii) throws QueryException { return convert(new JSONParser(json, ii).parse()); } /** * Converts a JSON AST into an XQuery expression. * @param nd JSON node * @return XQuery value * @throws QueryException exception */ private static Value convert(final JValue nd) throws QueryException { if(nd instanceof JAtom) { final byte[] type = nd.type(), val = ((JAtom) nd).value(); switch(type[0]) { case 'b': return Bln.get(val[0] == 't'); case 'n': return type[2] == 'm' ? Dbl.get(val, null) : Empty.SEQ; default: return Str.get(val); } } Map map = Map.EMPTY; final JStruct st = (JStruct) nd; final TokenList names = st instanceof JObject ? ((JObject) st).names : null; for(int i = st.size(); --i >= 0;) { map = map.insert(names == null ? Int.get(i + 1) : Str.get(names.get(i)), convert(st.value(i)), null); } return map; } }