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

net.thisptr.jackson.jq.internal.tree.StringInterpolation Maven / Gradle / Ivy

There is a newer version: 198
Show newest version
package net.thisptr.jackson.jq.internal.tree;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Stack;

import net.thisptr.jackson.jq.JsonQuery;
import net.thisptr.jackson.jq.Scope;
import net.thisptr.jackson.jq.exception.JsonQueryException;
import net.thisptr.jackson.jq.internal.misc.Pair;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.TextNode;

public class StringInterpolation extends JsonQuery {
	private List> interpolations;
	private String template;
	private JsonQuery formatter;

	public StringInterpolation(final String template, final List> interpolations, final JsonQuery formatter) {
		this.template = template;
		this.interpolations = interpolations;
		this.formatter = formatter;
	}

	@Override
	public List apply(final Scope scope, final JsonNode in) throws JsonQueryException {
		if (interpolations.isEmpty())
			return Collections. singletonList(new TextNode(template));

		final Stack>> values = new Stack<>();
		for (final Pair entry : interpolations) {
			List tmp = entry._2.apply(scope, in);
			if (formatter != null)
				tmp = formatter.apply(scope, tmp);
			values.push(Pair.of(entry._1, tmp));
		}

		final List out = new ArrayList<>();
		final Stack> stack = new Stack<>();
		recurse(out, stack, values);
		return out;
	}

	private void recurse(final List out, final Stack> stack, final Stack>> values) {
		if (values.isEmpty()) {
			final StringBuilder builder = new StringBuilder();

			int pos = 0;
			for (int index = stack.size() - 1; index >= 0; --index) {
				final Pair head = stack.get(index);
				builder.append(template.substring(pos, head._1));
				pos = head._1;

				builder.append(head._2.isValueNode() ? head._2.asText() : head._2.toString());
			}
			builder.append(template.substring(pos));
			out.add(new TextNode(builder.toString()));
		} else {
			final Pair> last = values.pop();
			for (final JsonNode value : last._2) {
				stack.push(Pair.of(last._1, value));
				recurse(out, stack, values);
				stack.pop();
			}
		}
	}

	@Override
	public String toString() {
		int pos = 0;
		final StringBuilder builder = new StringBuilder();
		if (formatter != null) {
			builder.append(formatter);
			builder.append(" ");
		}
		builder.append("\"");
		for (final Pair interpolation : interpolations) {
			copyEscaped(builder, template, pos, interpolation._1);
			pos = interpolation._1;
			builder.append("\\(");
			builder.append(interpolation._2);
			builder.append(")");
		}
		copyEscaped(builder, template, pos, template.length());
		builder.append("\"");
		return builder.toString();
	}

	private static void copyEscaped(final StringBuilder builder, final String text, final int begin, final int end) {
		for (int i = begin; i < end; ++i) {
			final char ch = text.charAt(i);
			switch (ch) {
				case '\\':
					builder.append("\\\\");
					break;
				case '"':
					builder.append("\\\"");
					break;
				case '\b':
					builder.append("\\b");
					break;
				case '\f':
					builder.append("\\f");
					break;
				case '\r':
					builder.append("\\r");
					break;
				case '\t':
					builder.append("\\t");
					break;
				case '\n':
					builder.append("\\n");
					break;
				default:
					builder.append(ch);
			}
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy