All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.rathravane.till.data.json.JsonEval Maven / Gradle / Ivy

There is a newer version: 2.1.1
Show newest version
package com.rathravane.till.data.json;

import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONObject;

import com.rathravane.till.data.rrConvertor;
import com.rathravane.till.data.exprEval.ExprDataSource;
import com.rathravane.till.data.exprEval.ExpressionEvaluator;

public class JsonEval
{
	/**
	 * Evaluate an expression against a JSON structure. If the expression refers to a non-existent
	 * node, null is returned.
	 *  
	 * @param root
	 * @param expression
	 * @return a JSON element or a primitive
	 */
	public static Object eval ( JSONObject root, String expression )
	{
		final String[] parts = expression.split ( "\\." );
		if ( parts.length == 1 )
		{
			return evalToValue ( root, parts[0] );
		}
		else
		{
			final JSONObject o = evalToContainer ( root, parts[0] );
			if ( o != null )
			{
				return eval ( o, expression.substring ( expression.indexOf ( '.' ) + 1 ) );
			}
		}
		return null;
	}

	/**
	 * Evaluate the given expression against the given root JSON object and return 
	 * a string representation. If the evaluation is null, an empty string is returned.
	 * @param root
	 * @param expression
	 * @return a string
	 */
	public static String evalToString ( JSONObject root, String expression )
	{
		final Object result = eval ( root, expression );
		if ( result == null ) return "";
		return result.toString ();
	}

	/**
	 * Evaluate the given expression against the given root JSON object and return
	 * a boolean representation. If the evaluation is null, false is returned. If
	 * the evaluation results in a JSON boolean, the value is returned. Anything else
	 * is converted to a string (via toString) and converted to a boolean via
	 * rrConvertor.convertToBooleanBroad
	 * @param root
	 * @param expression
	 * @return true or false
	 */
	public static boolean evalToBoolean ( JSONObject root, String expression )
	{
		final Object result = eval ( root, expression );
		if ( result == null ) return false;
		if ( result instanceof Boolean )
		{
			return (Boolean) result;
		}
		return rrConvertor.convertToBooleanBroad ( result.toString () );
	}

	/**
	 * substitute any occurrence of ${<expr>} with the evaluation of that expression 
	 * @param sourceString
	 * @param root
	 * @return a string
	 */
	public static String substitute ( String sourceString, JSONObject root )
	{
		return ExpressionEvaluator.evaluate ( sourceString, new JsonDataSource ( root ) );
	}

	public static void setValue ( JSONObject root, String key, Object data )
	{
		final String[] parts = key.split ( "\\." );
		final List partList = new LinkedList ( Arrays.asList ( parts ) );

		final String lastPart = partList.remove ( partList.size () - 1 );
		final JSONObject container = getContainer ( root, partList, true );
		container.put ( lastPart, data );
	}

	public static boolean hasKey ( JSONObject root, String key )
	{
		try
		{
			final String[] parts = key.split ( "\\." );
			final List partList = new LinkedList ( Arrays.asList ( parts ) );

			final String lastPart = partList.remove ( partList.size () - 1 );
			final JSONObject container = getContainer ( root, partList, false );
			return container != null && container.has ( lastPart );
		}
		catch ( IllegalArgumentException e )
		{
			return false;
		}
	}

	public static JSONObject getContainer ( JSONObject root, String key )
	{
		final String[] parts = key.split ( "\\." );
		final List partList = new LinkedList ( Arrays.asList ( parts ) );
		return getContainer ( root, partList, false );
	}

	private static JSONObject getContainer ( JSONObject root, List parts, boolean withCreate )
	{
		JSONObject current = root;
		for ( String thisPart : parts )
		{
			final Object nextContainer = current.opt ( thisPart );
			if ( nextContainer == null )
			{
				if ( withCreate )
				{
					// no such thing. create it as an object.
					final JSONObject newObj = new JSONObject ();
					current.put ( thisPart, newObj );
					current = newObj;
				}
				else
				{
					return null;
				}
			}
			else if ( nextContainer instanceof JSONObject )
			{
				// normal case
				current = (JSONObject) nextContainer;
			}
			else
			{
				// not a container we can support
				throw new IllegalArgumentException ( "Intermediate part " + thisPart + " is not an object." );
			}
		}
		return current;
	}

	private static class JsonDataSource implements ExprDataSource 
	{
		public JsonDataSource ( JSONObject root )
		{
			fRoot = root;
		}

		@Override
		public Object eval ( String label )
		{
			return JsonEval.eval ( fRoot, label );
		}

		private final JSONObject fRoot;
	}
	
	private static Object termToArrayValue ( JSONObject root, String term )
	{
		final int openBrace = term.indexOf ( '[' );
		if ( openBrace > -1 && term.endsWith ( "]" ))		// note: foo[0[1]] would pass
		{
			final String key = term.substring ( 0, openBrace );
			final JSONArray a = root.optJSONArray ( key );
			if ( a != null )
			{
				try
				{
					final String indexStr = term.substring ( openBrace+1, term.length () - 1 );
					final int index = Integer.parseInt ( indexStr );
					return a.opt ( index );
				}
				catch ( NumberFormatException x )
				{
					return null;
				}
			}
		}
		return null;
	}

	private static Object evalToValue ( JSONObject root, String term )
	{
		final int openBrace = term.indexOf ( '[' );
		if ( openBrace > -1 && term.endsWith ( "]" ))		// note: foo[0[1]] would pass
		{
			return termToArrayValue ( root, term );
		}
		else
		{
			return root.opt ( term );
		}
	}

	private static JSONObject evalToContainer ( JSONObject root, String term )
	{
		final int openBrace = term.indexOf ( '[' );
		if ( openBrace > -1 && term.endsWith ( "]" ))		// note: foo[0[1]] would pass
		{
			final Object element = termToArrayValue ( root, term );
			if ( element instanceof JSONObject )
			{
				return (JSONObject) element;
			}
		}
		else
		{
			return root.optJSONObject ( term );
		}
		return null;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy