package com.github.mxab.thymeleaf.extras.dataattribute.dialect;

import org.attoparser.util.TextUtil;
import org.thymeleaf.context.ITemplateContext;
import org.thymeleaf.engine.AttributeDefinition;
import org.thymeleaf.engine.AttributeName;
import org.thymeleaf.exceptions.TemplateProcessingException;
import org.thymeleaf.model.IAttribute;
import org.thymeleaf.model.IProcessableElementTag;
import org.thymeleaf.processor.AbstractProcessor;
import org.thymeleaf.processor.element.IElementTagProcessor;
import org.thymeleaf.processor.element.IElementTagStructureHandler;
import org.thymeleaf.processor.element.MatchingAttributeName;
import org.thymeleaf.processor.element.MatchingElementName;
import org.thymeleaf.standard.expression.IStandardExpression;
import org.thymeleaf.standard.expression.IStandardExpressionParser;
import org.thymeleaf.standard.expression.NoOpToken;
import org.thymeleaf.standard.expression.StandardExpressions;
import org.thymeleaf.standard.util.StandardProcessorUtils;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.util.EscapedAttributeUtils;
import org.unbescape.html.HtmlEscape;

public class DataProcessor extends AbstractProcessor implements IElementTagProcessor {

	public static final int PRECEDENCE = 1100;

	private final String dialectPrefix;
	private final MatchingAttributeName matchingAttributeName;

	public DataProcessor(TemplateMode templateMode, String dialectPrefix) {
		super(templateMode, PRECEDENCE);
		this.dialectPrefix = dialectPrefix;
		matchingAttributeName = MatchingAttributeName.forAllAttributesWithPrefix(templateMode, dialectPrefix);
	}

	@Override
	public MatchingElementName getMatchingElementName() {
		return null;
	}

	@Override
	public MatchingAttributeName getMatchingAttributeName() {
		return matchingAttributeName;
	}

	@Override
	public void process(ITemplateContext context, IProcessableElementTag tag,
			IElementTagStructureHandler structureHandler) {
		for (IAttribute attribute : tag.getAllAttributes()) {
			AttributeDefinition attributeDefinition = attribute.getAttributeDefinition();
			AttributeName attributeName = attributeDefinition.getAttributeName();
			if (attributeName.isPrefixed() && TextUtil.equals(getTemplateMode().isCaseSensitive(), attributeName.getPrefix(), dialectPrefix)) {
				processDataAttribute(context, attribute, attributeDefinition, attributeName, structureHandler);
			}
		}
	}

	private void processDataAttribute(ITemplateContext context, IAttribute attribute, AttributeDefinition attributeDefinition, AttributeName attributeName, IElementTagStructureHandler structureHandler) {
		try {
			IStandardExpressionParser expressionParser = StandardExpressions.getExpressionParser(context.getConfiguration());
			String attributeValue = EscapedAttributeUtils.unescapeAttribute(context.getTemplateMode(), attribute.getValue());

			Object expressionResult;
			if (attributeValue != null) {
				IStandardExpression expression = expressionParser.parseExpression(context, attributeValue);
				expressionResult = expression.execute(context);
			} else {
				expressionResult = null;
			}

			String targetAttrCompleteName = String.format("data-%s", attributeName.getAttributeName());

			if (expressionResult != NoOpToken.VALUE) {
				structureHandler.removeAttribute(targetAttrCompleteName);
			}

			String newAttributeValue = HtmlEscape.escapeHtml4Xml(expressionResult == null ? null : expressionResult.toString());

			if (expressionResult == NoOpToken.VALUE || newAttributeValue == null || newAttributeValue.length() == 0) {
				structureHandler.removeAttribute(attributeName);
			} else {
				StandardProcessorUtils.replaceAttribute(structureHandler, attributeName, attributeDefinition, targetAttrCompleteName, newAttributeValue);
			}
		} catch (TemplateProcessingException e) {
			if (!e.hasTemplateName()) {
				e.setTemplateName(attribute.getTemplateName());
			}

			if (!e.hasLineAndCol()) {
				e.setLineAndCol(attribute.getLine(), attribute.getCol());
			}

			throw e;
		} catch (Exception e) {
			throw new TemplateProcessingException("Error during execution of processor '" + getClass().getName() + "'", attribute.getTemplateName(), attribute.getLine(), attribute.getCol(), e);
		}
	}

}

@@ -62,45 +62,8 @@
 t;%0A%0A
-import org.attoparser.util.TextUtil;%0A
 impo
@@ -1225,45 +1225,8 @@
 0;%0A%0A
-%09private final String dialectPrefix;%0A
 %09pri
@@ -1281,16 +1281,16 @@
 teName;%0A
+
 %0A%09public
@@ -1394,46 +1394,8 @@
 E);%0A
-%09%09this.dialectPrefix = dialectPrefix;%0A
 %09%09ma
@@ -1775,20 +1775,17 @@
 Tag tag,
-%0A%09%09%09
+ 
 IElement
@@ -2033,33 +2033,41 @@
 eName();%0A%09%09%09if (
-a
+matchingA
 ttributeName.isP
@@ -2067,117 +2067,29 @@
 ame.
-isPrefixed() && TextUtil.equals(getTemplateMode().isCaseSensitive(), attributeName.getPrefix(), dialectPrefix
+matches(attributeName
 )) %7B

Use predefined MatchingAttributeName