Search code examples
thymeleaf

Wrap text with CDATA in XML


I have a template that produces XML. Something like:

<items>
    <item th:each="itemEntry: ${rs1}">
        <name th:text="${itemEntry.value['ITEM_NAME']}"></name>
    </item>
</items>

What would I have to do to wrap the text of element name in CDATA, so that the result would be:

<items>
    <item>
        <name><![CDATA[My text]]></name>
    </item>
</items>

Solution

  • At the end it was quite simple. I had to create my own dialect:

    public class KovicaDialect extends AbstractDialect implements IExpressionObjectDialect {
        private static final XMLExpressionObjectFactory xmlExpressionObjectFactory = new XMLExpressionObjectFactory();
    
        public KovicaDialect() {
            super("kovica");
        }
    
        @Override
        public IExpressionObjectFactory getExpressionObjectFactory() {
            return xmlExpressionObjectFactory;
        }
    }
    

    The expression object factory looks like this:

    public class XMLExpressionObjectFactory implements IExpressionObjectFactory {
        private static final String EXPRESSION_OBJECT_PREFIX = "xml";
        private static final Set<String> EXPRESSION_OBJECT_NAMES = Collections.unmodifiableSet(new HashSet(Arrays.asList(EXPRESSION_OBJECT_PREFIX)));
    
        @Override
        public Set<String> getAllExpressionObjectNames() {
            return EXPRESSION_OBJECT_NAMES;
        }
    
        @Override
        public Object buildObject(IExpressionContext context, String expressionObjectName) {
            if (expressionObjectName.equals(EXPRESSION_OBJECT_PREFIX) == true) {
                return new XMLUtils();
            }
    
            return null;
        }
    
        @Override
        public boolean isCacheable(String expressionObjectName) {
            return true;
        }
    }
    

    And the util class:

    public class XMLUtils {
        public String cdata(String str) {
            String returnString = null;
    
            if (str != null) {
                returnString = "<![CDATA[" + str + "]]>";
            }
    
            return returnString;
        }
    }
    

    You have to set this dialect:

    org.thymeleaf.TemplateEngine templateEngine = new org.thymeleaf.TemplateEngine();
    templateEngine.addDialect(new KovicaDialect());
    

    then you can use it like this (it has to be an th:utext):

    <name th:utext="${#xml.cdata(itemEntry.value['ITEM_NAMESMALL'])}"></name>