code: package com.taxonic.carml.engine;
  
  import com.taxonic.carml.engine.template.Template;
  import com.taxonic.carml.engine.template.Template.Expression;
  import com.taxonic.carml.rdf_mapper.util.ImmutableCollectors;
  import java.util.Collection;
  import java.util.Objects;
  import java.util.Optional;
  import java.util.Set;
  import java.util.function.Function;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  class GetTemplateValue implements Function<EvaluateExpression, Optional<Object>> {
  
  	private static final Logger LOG = LoggerFactory.getLogger(GetTemplateValue.class);
  
  	private Template template;
  	private Set<Expression> expressions;
  	private Function<String, String> transformValue;
  	private Function<Object, String> createNaturalRdfLexicalForm;
  
  	GetTemplateValue(
  		Template template,
  		Set<Expression> expressions,
  		Function<String, String> transformValue,
  		Function<Object, String> createNaturalRdfLexicalForm
  	) {
  		this.template = template;
  		this.expressions = expressions;
  		this.transformValue = transformValue;
  		this.createNaturalRdfLexicalForm = createNaturalRdfLexicalForm;
  	}
  
  	@Override
  	public Optional<Object> apply(EvaluateExpression evaluateExpression) {
  		if (LOG.isTraceEnabled()) {
  			LOG.trace("Processing template: {}", template.toTemplateString());
  		}
  		Template.Builder templateBuilder = template.newBuilder();
  		expressions.forEach(e -> bindTemplateExpression(e, evaluateExpression, templateBuilder));
  		return templateBuilder.create();
  	}
  
  	private Template.Builder bindTemplateExpression(
  		Expression expression,
  		EvaluateExpression evaluateExpression,
  		Template.Builder templateBuilder
  	) {
  		return templateBuilder.bind(
  			expression,
  			e -> evaluateExpression
  				.apply(e.getValue())
  				.map(this::prepareValueForTemplate)
  		);
  	}
  
  	/**
  	 * See https://www.w3.org/TR/r2rml/#from-template
  	 * @param raw
  	 * @return
  	 */
  	private Object prepareValueForTemplate(Object raw) {
  		Objects.requireNonNull(raw);
  
  		if (raw instanceof Collection<?>) {
  			return ((Collection<?>) raw).stream()
  			.map(createNaturalRdfLexicalForm::apply)
  			.map(transformValue::apply)
  			.collect(ImmutableCollectors.toImmutableList());
  		} else {
  			String value = createNaturalRdfLexicalForm.apply(raw);
  			return transformValue.apply(value);
  		}
  	}
  
  }
  