Replacing an element of same type with a tag processor

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Replacing an element of same type with a tag processor

Ertug Karamatli
Hi,

I'm trying to replace an element using a tag processor that the new element is also of the same type (i.e. img) and I also want to run value processors before my tag processor is called.
To ensure the value processors are run, I add necessary value processors as dependencies in my tag processor.

You might say why do you try to replace it instead of modifying the element, this is due to a design constraint.

Here is what I have tried so far:
- If I extend AbstractMarkupSubstitutionTagProcessor and return the same type of element, it creates an endless loop.
- If I replace the element in-place and return NO_ACTION, the value processors are not run.
- If I mark the new element as TemplateEngine.THYMELEAF_NON_EXECUTABLE_NODE, the value processors are not run.
- If I put an indicator in the element's user data that shows it was already processed, the user data is not preserved in the consecutive calls.


Here is my workaround:

public TagProcessResult process(...)
{
    Element newElement = ...;

    String processedIndicator = "processed";
    if (newElement.getAttribute(processedIndicator) == null)
    {
        newElement.setAttribute(processedIndicator, "true");
        return TagProcessResult.forSubstituteTag(Arrays.asList(SubstitutionTag.forNode(newElement)));
    }
    else
    {
        return TagProcessResult.NO_ACTION;
    }
}

Instead of storing "processed" indicator in user data, I stored it as an attribute which is, I think, not an elegant solution.

At least, it should preserve user data for this kind of functionality.

Is there a better way to do it?

Thanks,
Ertug
Reply | Threaded
Open this post in threaded view
|

Re: Replacing an element of same type with a tag processor

danielfernandez
Administrator
Hi,

I suppose you mean "attribute processors" most of the times you write "value processors" in your text. If it is so, I understand your problem.

Your solution is not bad, and is probably a quite adequate one for Thymeleaf 1.0.x. I honestly did never think about substituting a tag for another one which would trigger the same processor... resulting, as you say, in an infinite loop...

There is a way in which you could avoid that "if", though. If your sustitution tag (the one you write into the DOM as a replacement for the original one) has some special feature (for example, a specific attribute with a specific value), you could use the TagApplicabilities in your tag processor to specify that it should NOT be executed when the processed tag includes that attribute set to that value. That way you'd avoid the second (and looping) execution.

If you do not have such attribute as a natural and valid one, you could create your own one, with whichever value, and then create an attribute processor for that attribute that simply removes it. As attribute processors execute after tag processors, you'd avoid the infinite loop.

Anyway, your problem has made me think. For Thymeleaf 1.1.0 I'll include:

1. New constants in TemplateEngine like for example THYMELEAF_NON_EXECUTABLE_TAG and THYMELEAF_NON_EXECUTABLE_ATTR, which Thymeleaf's DOM processor will honor and consequently avoid the processing of the tag marked with those. This would mean that all you'd have to do is add such constants to the new tag's user data and your tag processor would not be executed again for it.

2. Add TagApplicability/AttrApplicability filters that could be based in UserInfo items (and not only in tag names / attributes).

Until 1.1.0 is released, though (which should happen soon, maybe just a week), you'd probably be fine with your current implementation.

Regards,
Daniel.
Reply | Threaded
Open this post in threaded view
|

Re: Replacing an element of same type with a tag processor

Ertug Karamatli
Yes, I actually meant attribute processors which is, in turn, related with value processors.

I think I will stick with my current implementation for now and wait for 1.1.0. What you have mentioned for 1.1.0 are surely going to sort it out.

Thanks for your reply.

Regards,
Ertug
Reply | Threaded
Open this post in threaded view
|

Re: Replacing an element of same type with a tag processor

danielfernandez
Administrator
Hi,

Yesterday, a new snapshot release has been uploaded to the Sonatype snapshot Maven repository that already includes this feature.

Specifically, you will now be able to use two methods:

DOMExecution.setExecutableNode(node, false);

and

DOMExecution.setExecutableTree(node, false);

As their names imply, the former method will avoid any further execution on your newly created node, and only on that node. The latter method will avoid execution of both the specified node AND any of its children.

This feature will go into the upcoming 1.1.0 version release.

Regards,
Daniel.