use of org.thymeleaf.standard.expression.IStandardExpressionParser in project thymeleaf by thymeleaf.
the class AbstractStandardInliner method performInlining.
private void performInlining(final ITemplateContext context, final CharSequence text, final int offset, final int len, final String templateName, final int line, final int col, final StringBuilder strBuilder) {
final IStandardExpressionParser expressionParser = StandardExpressions.getExpressionParser(context.getConfiguration());
final int[] locator = new int[] { line, col };
int i = offset;
int current = i;
int maxi = offset + len;
int expStart, expEnd;
int currentLine = -1;
int currentCol = -1;
char innerClosingChar = 0x0;
boolean inExpression = false;
while (i < maxi) {
currentLine = locator[0];
currentCol = locator[1];
if (!inExpression) {
expStart = findNextStructureStart(text, i, maxi, locator);
if (expStart == -1) {
strBuilder.append(text, current, maxi);
return;
}
inExpression = true;
if (expStart > current) {
// We avoid empty-string text events
strBuilder.append(text, current, expStart);
}
innerClosingChar = ((text.charAt(expStart + 1) == '[') ? ']' : ')');
current = expStart;
i = current + 2;
} else {
// The inner closing char we will be looking for will depend on the type of expression we just found
expEnd = findNextStructureEndAvoidQuotes(text, i, maxi, innerClosingChar, locator);
if (expEnd < 0) {
strBuilder.append(text, current, maxi);
return;
}
final String expression = text.subSequence(current + 2, expEnd).toString();
final boolean escape = innerClosingChar == ']';
strBuilder.append(processExpression(context, expressionParser, expression, escape, templateName, currentLine, currentCol + 2));
// The ')]' or ']]' suffix will be considered as processed too
countChar(locator, text.charAt(expEnd));
countChar(locator, text.charAt(expEnd + 1));
inExpression = false;
current = expEnd + 2;
i = current;
}
}
if (inExpression) {
// Just in case input ended in '[[' or '[('
strBuilder.append(text, current, maxi);
}
}
use of org.thymeleaf.standard.expression.IStandardExpressionParser in project thymeleaf by thymeleaf.
the class AbstractStandardFragmentInsertionTagProcessor method computeFragment.
/*
* This can return a Fragment, NoOpToken (if nothing should be done) or null
*/
private static Object computeFragment(final ITemplateContext context, final String input) {
final IStandardExpressionParser expressionParser = StandardExpressions.getExpressionParser(context.getConfiguration());
final String trimmedInput = input.trim();
if (shouldBeWrappedAsFragmentExpression(trimmedInput)) {
// We do not know for sure that this is a complete standard expression, so we will consider it the
// content of a FragmentExpression for legacy compatibility reasons.
// We will only reach this point if the expression does not contain any Fragment Expressions expressed
// as ~{...} (excluding parameters), nor the "::" fragment selector separator.
// NOTE we are using the generic parseExpression() and not directly calling a parse method in the
// FragmentExpression class because we want to take advantage of the expression cache.
final FragmentExpression fragmentExpression = (FragmentExpression) expressionParser.parseExpression(context, "~{" + trimmedInput + "}");
final FragmentExpression.ExecutedFragmentExpression executedFragmentExpression = FragmentExpression.createExecutedFragmentExpression(context, fragmentExpression);
if (executedFragmentExpression.getFragmentSelectorExpressionResult() == null && executedFragmentExpression.getFragmentParameters() == null) {
// We might be in the scenario that what we thought was a template name in fact was instead an expression
// returning a Fragment itself, so we should simply return it
final Object templateNameExpressionResult = executedFragmentExpression.getTemplateNameExpressionResult();
if (templateNameExpressionResult != null) {
if (templateNameExpressionResult instanceof Fragment) {
return templateNameExpressionResult;
}
if (templateNameExpressionResult == NoOpToken.VALUE) {
return NoOpToken.VALUE;
}
}
}
// have to execute a (potentially costly) resource.exists() call on the resolved resource.
return FragmentExpression.resolveExecutedFragmentExpression(context, executedFragmentExpression, true);
}
// If we reached this point, we know for sure this is a complete fragment expression, so we just parse it
// as such and execute it
final IStandardExpression fragmentExpression = expressionParser.parseExpression(context, trimmedInput);
final Object fragmentExpressionResult;
if (fragmentExpression != null && fragmentExpression instanceof FragmentExpression) {
// This is not a complex expression but merely a FragmentExpression, so we can apply a shortcut
// so that we don't require a "null" result for this expression if the template does not exist. That will
// save a call to resource.exists() which might be costly.
final FragmentExpression.ExecutedFragmentExpression executedFragmentExpression = FragmentExpression.createExecutedFragmentExpression(context, (FragmentExpression) fragmentExpression);
fragmentExpressionResult = FragmentExpression.resolveExecutedFragmentExpression(context, executedFragmentExpression, true);
} else {
fragmentExpressionResult = fragmentExpression.execute(context);
}
if (fragmentExpressionResult == null || fragmentExpressionResult == NoOpToken.VALUE) {
return fragmentExpressionResult;
}
if (!(fragmentExpressionResult instanceof Fragment)) {
throw new TemplateProcessingException("Invalid fragment specification: \"" + input + "\": " + "expression does not return a Fragment object");
}
return fragmentExpressionResult;
}
use of org.thymeleaf.standard.expression.IStandardExpressionParser in project thymeleaf by thymeleaf.
the class AbstractStandardTargetSelectionTagProcessor method doProcess.
@Override
protected final void doProcess(final ITemplateContext context, final IProcessableElementTag tag, final AttributeName attributeName, final String attributeValue, final IElementTagStructureHandler structureHandler) {
final IStandardExpressionParser expressionParser = StandardExpressions.getExpressionParser(context.getConfiguration());
final IStandardExpression expression = expressionParser.parseExpression(context, attributeValue);
validateSelectionValue(context, tag, attributeName, attributeValue, expression);
final Object newSelectionTarget = expression.execute(context);
final Map<String, Object> additionalLocalVariables = computeAdditionalLocalVariables(context, tag, attributeName, attributeValue, expression);
if (additionalLocalVariables != null && additionalLocalVariables.size() > 0) {
for (final Map.Entry<String, Object> variableEntry : additionalLocalVariables.entrySet()) {
structureHandler.setLocalVariable(variableEntry.getKey(), variableEntry.getValue());
}
}
structureHandler.setSelectionTarget(newSelectionTarget);
}
use of org.thymeleaf.standard.expression.IStandardExpressionParser in project thymeleaf by thymeleaf.
the class StandardSwitchTagProcessor method doProcess.
@Override
protected void doProcess(final ITemplateContext context, final IProcessableElementTag tag, final AttributeName attributeName, final String attributeValue, final IElementTagStructureHandler structureHandler) {
final IStandardExpressionParser expressionParser = StandardExpressions.getExpressionParser(context.getConfiguration());
final IStandardExpression switchExpression = expressionParser.parseExpression(context, attributeValue);
structureHandler.setLocalVariable(SWITCH_VARIABLE_NAME, new SwitchStructure(switchExpression));
}
use of org.thymeleaf.standard.expression.IStandardExpressionParser in project thymeleaf by thymeleaf.
the class StandardUtextTagProcessor method doProcess.
@Override
protected void doProcess(final ITemplateContext context, final IProcessableElementTag tag, final AttributeName attributeName, final String attributeValue, final IElementTagStructureHandler structureHandler) {
final IEngineConfiguration configuration = context.getConfiguration();
final IStandardExpressionParser expressionParser = StandardExpressions.getExpressionParser(configuration);
final IStandardExpression expression = expressionParser.parseExpression(context, attributeValue);
final Object expressionResult;
if (expression != null && expression instanceof FragmentExpression) {
// This is merely a FragmentExpression (not complex, not combined with anything), so we can apply a shortcut
// so that we don't require a "null" result for this expression if the template does not exist. That will
// save a call to resource.exists() which might be costly.
final FragmentExpression.ExecutedFragmentExpression executedFragmentExpression = FragmentExpression.createExecutedFragmentExpression(context, (FragmentExpression) expression);
expressionResult = FragmentExpression.resolveExecutedFragmentExpression(context, executedFragmentExpression, true);
} else {
expressionResult = expression.execute(context, StandardExpressionExecutionContext.RESTRICTED);
}
// If result is no-op, there's nothing to execute
if (expressionResult == NoOpToken.VALUE) {
return;
}
/*
* First of all we should check whether the expression result is a Fragment so that, in such case, we can
* avoid creating a String in memory for it and just append its model.
*/
if (expressionResult != null && expressionResult instanceof Fragment) {
if (expressionResult == Fragment.EMPTY_FRAGMENT) {
structureHandler.removeBody();
return;
}
structureHandler.setBody(((Fragment) expressionResult).getTemplateModel(), false);
return;
}
final String unescapedTextStr = (expressionResult == null ? "" : expressionResult.toString());
/*
* We will check if there are configured post processors or not. The reason we do this is because output
* inserted as a result of a th:utext attribute, even if it might be markup, will never be considered as
* 'processable', i.e. no other processors/inliner will ever be able to act on it. The main reason for this
* is to protect against code injection.
*
* So the only other agents that would be able to modify these th:utext results are POST-PROCESSORS. And
* they will indeed need markup to have been parsed in order to separate text from structures, so that's why
* we check if there actually are any post-processors and, if not (most common case), simply output the
* expression result as if it were a mere (unescaped) text node.
*/
final Set<IPostProcessor> postProcessors = configuration.getPostProcessors(getTemplateMode());
if (postProcessors.isEmpty()) {
structureHandler.setBody(unescapedTextStr, false);
return;
}
/*
* We have post-processors, so from here one we will have to decide whether we need to parse the unescaped
* text or not...
*/
if (!mightContainStructures(unescapedTextStr)) {
// If this text contains no markup structures, there would be no need to parse it or treat it as markup!
structureHandler.setBody(unescapedTextStr, false);
return;
}
/*
* We have post-processors AND this text might contain structures, so there is no alternative but parsing
*/
final TemplateModel parsedFragment = configuration.getTemplateManager().parseString(context.getTemplateData(), unescapedTextStr, // we won't apply offset here because the inserted text does not really come from the template itself
0, // we won't apply offset here because the inserted text does not really come from the template itself
0, // No template mode forcing required
null, // useCache == false because we could potentially pollute the cache with too many entries (th:utext is too variable!)
false);
// Setting 'processable' to false avoiding text inliners processing already generated text,
// which in turn avoids code injection.
structureHandler.setBody(parsedFragment, false);
}
Aggregations