@@ -0,0 +1,3355 @@
+package de.morphbit.thymeleaf.helper;%0D%0A%0D%0Aimport java.util.List;%0D%0A%0D%0Aimport org.thymeleaf.context.IEngineContext;%0D%0Aimport org.thymeleaf.context.ITemplateContext;%0D%0Aimport org.thymeleaf.exceptions.TemplateProcessingException;%0D%0Aimport org.thymeleaf.processor.element.IElementModelStructureHandler;%0D%0Aimport org.thymeleaf.standard.expression.Assignation;%0D%0Aimport org.thymeleaf.standard.expression.AssignationSequence;%0D%0Aimport org.thymeleaf.standard.expression.AssignationUtils;%0D%0Aimport org.thymeleaf.standard.expression.IStandardExpression;%0D%0Aimport org.thymeleaf.util.StringUtils;%0D%0A%0D%0Apublic class WithHelper %7B%0D%0A%0D%0A%09public static void processWith(ITemplateContext context, String attributeValue, IElementModelStructureHandler structureHandler) %7B%0D%0A%09%09final AssignationSequence assignations =%0D%0A                AssignationUtils.parseAssignationSequence(%0D%0A                        context, attributeValue, false /* no parameters without value */);%0D%0A        if (assignations == null) %7B%0D%0A            throw new TemplateProcessingException(%0D%0A                    %22Could not parse value as attribute assignations: %5C%22%22 + attributeValue + %22%5C%22%22);%0D%0A        %7D%0D%0A%0D%0A        // Normally we would just allow the structure handler to be in charge of declaring the local variables%0D%0A        // by using structureHandler.setLocalVariable(...) but in this case we want each variable defined at an%0D%0A        // expression to be available for the next expressions, and that forces us to cast our ITemplateContext into%0D%0A        // a more specific interface --which shouldn't be used directly except in this specific, special case-- and%0D%0A        // put the local variables directly into it.%0D%0A        IEngineContext engineContext = null;%0D%0A        if (context instanceof IEngineContext) %7B%0D%0A            // NOTE this interface is internal and should not be used in users' code%0D%0A            engineContext = (IEngineContext) context;%0D%0A        %7D%0D%0A%0D%0A        final List%3CAssignation%3E assignationValues = assignations.getAssignations();%0D%0A        final int assignationValuesLen = assignationValues.size();%0D%0A%0D%0A        for (int i = 0; i %3C assignationValuesLen; i++) %7B%0D%0A%0D%0A            final Assignation assignation = assignationValues.get(i);%0D%0A%0D%0A            final IStandardExpression leftExpr = assignation.getLeft();%0D%0A            final Object leftValue = leftExpr.execute(context);%0D%0A%0D%0A            final IStandardExpression rightExpr = assignation.getRight();%0D%0A            final Object rightValue = rightExpr.execute(context);%0D%0A%0D%0A            final String newVariableName = (leftValue == null? null : leftValue.toString());%0D%0A            if (StringUtils.isEmptyOrWhitespace(newVariableName)) %7B%0D%0A                throw new TemplateProcessingException(%0D%0A                        %22Variable name expression evaluated as null or empty: %5C%22%22 + leftExpr + %22%5C%22%22);%0D%0A            %7D%0D%0A%0D%0A            if (engineContext != null) %7B%0D%0A                // The advantage of this vs. using the structure handler is that we will be able to%0D%0A                // use this newly created value in other expressions in the same 'th:with'%0D%0A                engineContext.setVariable(newVariableName, rightValue);%0D%0A            %7D else %7B%0D%0A                // The problem is, these won't be available until we execute the next processor%0D%0A                structureHandler.setLocalVariable(newVariableName, rightValue);%0D%0A            %7D%0D%0A%0D%0A        %7D%0D%0A%09%7D%0D%0A%7D%0D%0A

Add WithHelper