避免使用 Thymeleaf 转义自定义属性中的换行符
Avoid escaping line breaks in a custom attribute using Thymeleaf
我使用 Thymeleaf 处理 SVG 模板并在替换 base64 编码的嵌入图像时遇到问题。
因此,源标记如下所示:
<image
width="100"
height="100"
id="image123"
x="0"
y="0"
preserveAspectRatio="none"
th:attr="'xlink:href'='data:image/png;base64,' + ${imageBase64}"
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAIAAAAiOjnJAAAAAXNSR0IArs4c6QAAAARnQU1BAACx
jwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAoRSURBVHhe7d09cts6FAVg663FSuHxCqgVyG5c
<MORE BASE64 DATA HERE...>
ggUqECxQgWCBCgQLVCBYoALBAhUIFqhAsEAFggUqECxQgWABwFicnf0PDRO+cnclXPUAAAAASUVO
RK5CYII=
"
/>
每行 base64 编码的图像数据由 76 个字符和一个换行符 (LF) 组成,我想保留这种结构,因为一些 SVG 渲染器在文件包含很长的行时会中断。
问题是,当我将 imageBase64
上下文变量设置为带换行符的 base64 字符串时,Thymeleaf 将 LF 字符转义为 

,显然,这会破坏 base64 解码器。
我知道,有一个适用于标签内部文本的 th:utext
属性,但是有没有办法在使用自定义属性时避免内容转义?
复制者
https://github.com/d-bykov/thymeleaf-escaping-reproducer
运行 此项目将生成 this SVG file,其中包含带有 

个标记而不是换行符的 Base64 编码图像。
GitHub 可以很好地呈现它,但其他一些应用程序却不能。
总结
如您所见,XML 处理程序会将换行符转义为 

。但这不是 HTML 所要求的,因此请尝试使用 HTML 模板模式。
我的测试
在您的 Kotlin 中,您将模板模式设置为 XML:
templateResolver.templateMode = TemplateMode.XML
而是使用 HTML
templateResolver.templateMode = TemplateMode.HTML
在我的 Java 版本的代码中,我实际上使用了这个:
templateResolver.setTemplateMode(TemplateMode.HTML);
当我使用自己的 PNG 时,最终结果是以下内容:
<svg width="512" height="512" viewBox="0 0 135.46666 135.46667" version="1.1" id="svg33251" inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)" sodipodi:docname="template.svg" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview id="namedview33253" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageshadow="2" inkscape:pageopacity="0.0" inkscape:pagecheckerboard="0" inkscape:document-units="mm" showgrid="false" units="px" inkscape:zoom="0.77771465" inkscape:cx="270.02192" inkscape:cy="560.61693" inkscape:window-width="1718" inkscape:window-height="1368" inkscape:window-x="1713" inkscape:window-y="0" inkscape:window-maximized="0" inkscape:current-layer="layer1"/>
<defs id="defs33248"/>
<g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1">
<image width="67.73333" height="67.73333" preserveAspectRatio="none" id="image33388" x="33.866669" y="33.866669" xlink:href="data:image/png;base64,
iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAADd0lEQVRoge1aW2sTQRT+UshDLBTi
pYJP6kPxB4hUwQsqlP0DQi1CHwRvfahihSoqKBIr1CLoT5DihaSvlqpQEW99aBvanbRo6WssfanE
pjtwfJhsdjfJ7k72kk2KAx+BZM7M+XLmzJw5Z4CAGhHiPAeFM0xwht+cgWsqyAzOwEu/TfAcFCLE
g5rfVyNCXFOR4iqKlUrLoiSbioQUrSKpqch6Vd4BWVpFMnwChDaNYToEAlYwTBOhLRQSmoqe0AlU
oydQElxFOgISug+lgyHBsBIViTIZhhW/lliLmoTJMmstawnflonSJyQsI+czWjS7U71w3s2I0NYE
SkrB8Zzxetg9GAQB4jNMGQsYpmtbQ4QddQ+4MSsU0rExG45MTavUCmc0j7HTYL9VqcH+cGRskK30
jbjXtZrssCqV7AhHxtYq5qhZU5HyOlAsZlUqFgtHxgGpMhE/9wmzQjrCkLEDV1H0vayagUh5efEc
FD+DNMHSIp6DAs6Q8TNI1M6uqSDOkAFnyPsZJOLtVyeSR61sRz2I8kA0EeHwM4COSEKUCgRCpBnw
n0izwdXZ176DRodBl3tBxcXGKVZcBF3qBT0dFjo49eUM3Hb7LWRBe3Zad5fxscYReTlqnbtzF+hv
1pZI3vZAfHbXOtCjG41fLg+vW3V4ft+WSMY2RNlSQekXoFNHxCBXzjeeyMVzYu7T3UKXLbullYPi
GjT++hBMPOQFsZIlVj469yvfSdzC+PaEGHBkqHEkHt8Uc7YnnPuVw3iZi9XXN8Y6Ldg4XJAozBvz
/Ui79jcuVjJ3kq79xu4RNhF9tzx00L1vVYFIc0k+bC4Y94gzR8Mjcbrb8Mnigmt/a/IBkEsHLU0a
Jj97LDwSAGh5SsIadtUtmQTdp3Fjsr27g/GZwjyo03T4fn4lIWeXoCv5ilTKlL2zXlef3PJOYmTI
euVdmpSTcy3NaZJJ7M0FYwPQlRi4AFqfcZddnwFd67P+GV0HpHxCh1xJrp6ywpfXoB2J6mTCvk6Q
chJ0tU9AOSG+q0w8tCdA397KW7DuUly9hZ7lKdDxw9WK1kIsJvr+fF/fMvRcgvNaetuYE5Yauw26
NyAwdkd892fOmy95Lr15tUwY8F0MNVmm9cvTetO2w4MBvW2LJxwWQq3+qKaKUKs/c6rVTA/PMpwh
7/DwLM8ZMkE/PPsHuS6jvp3tkTwAAAAASUVORK5CYII="/>
</g>
</svg>
(我在 base64 字符串的开头添加了一个换行符,同样,只是为了让整个字符串内容在文件中左对齐——您可能不需要或不想这样做)。
我使用 Thymeleaf 处理 SVG 模板并在替换 base64 编码的嵌入图像时遇到问题。
因此,源标记如下所示:
<image
width="100"
height="100"
id="image123"
x="0"
y="0"
preserveAspectRatio="none"
th:attr="'xlink:href'='data:image/png;base64,' + ${imageBase64}"
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAIAAAAiOjnJAAAAAXNSR0IArs4c6QAAAARnQU1BAACx
jwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAoRSURBVHhe7d09cts6FAVg663FSuHxCqgVyG5c
<MORE BASE64 DATA HERE...>
ggUqECxQgWCBCgQLVCBYoALBAhUIFqhAsEAFggUqECxQgWABwFicnf0PDRO+cnclXPUAAAAASUVO
RK5CYII=
"
/>
每行 base64 编码的图像数据由 76 个字符和一个换行符 (LF) 组成,我想保留这种结构,因为一些 SVG 渲染器在文件包含很长的行时会中断。
问题是,当我将 imageBase64
上下文变量设置为带换行符的 base64 字符串时,Thymeleaf 将 LF 字符转义为 

,显然,这会破坏 base64 解码器。
我知道,有一个适用于标签内部文本的 th:utext
属性,但是有没有办法在使用自定义属性时避免内容转义?
复制者
https://github.com/d-bykov/thymeleaf-escaping-reproducer
运行 此项目将生成 this SVG file,其中包含带有 

个标记而不是换行符的 Base64 编码图像。
GitHub 可以很好地呈现它,但其他一些应用程序却不能。
总结
如您所见,XML 处理程序会将换行符转义为 

。但这不是 HTML 所要求的,因此请尝试使用 HTML 模板模式。
我的测试
在您的 Kotlin 中,您将模板模式设置为 XML:
templateResolver.templateMode = TemplateMode.XML
而是使用 HTML
templateResolver.templateMode = TemplateMode.HTML
在我的 Java 版本的代码中,我实际上使用了这个:
templateResolver.setTemplateMode(TemplateMode.HTML);
当我使用自己的 PNG 时,最终结果是以下内容:
<svg width="512" height="512" viewBox="0 0 135.46666 135.46667" version="1.1" id="svg33251" inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)" sodipodi:docname="template.svg" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview id="namedview33253" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageshadow="2" inkscape:pageopacity="0.0" inkscape:pagecheckerboard="0" inkscape:document-units="mm" showgrid="false" units="px" inkscape:zoom="0.77771465" inkscape:cx="270.02192" inkscape:cy="560.61693" inkscape:window-width="1718" inkscape:window-height="1368" inkscape:window-x="1713" inkscape:window-y="0" inkscape:window-maximized="0" inkscape:current-layer="layer1"/>
<defs id="defs33248"/>
<g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1">
<image width="67.73333" height="67.73333" preserveAspectRatio="none" id="image33388" x="33.866669" y="33.866669" xlink:href="data:image/png;base64,
iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAADd0lEQVRoge1aW2sTQRT+UshDLBTi
pYJP6kPxB4hUwQsqlP0DQi1CHwRvfahihSoqKBIr1CLoT5DihaSvlqpQEW99aBvanbRo6WssfanE
pjtwfJhsdjfJ7k72kk2KAx+BZM7M+XLmzJw5Z4CAGhHiPAeFM0xwht+cgWsqyAzOwEu/TfAcFCLE
g5rfVyNCXFOR4iqKlUrLoiSbioQUrSKpqch6Vd4BWVpFMnwChDaNYToEAlYwTBOhLRQSmoqe0AlU
oydQElxFOgISug+lgyHBsBIViTIZhhW/lliLmoTJMmstawnflonSJyQsI+czWjS7U71w3s2I0NYE
SkrB8Zzxetg9GAQB4jNMGQsYpmtbQ4QddQ+4MSsU0rExG45MTavUCmc0j7HTYL9VqcH+cGRskK30
jbjXtZrssCqV7AhHxtYq5qhZU5HyOlAsZlUqFgtHxgGpMhE/9wmzQjrCkLEDV1H0vayagUh5efEc
FD+DNMHSIp6DAs6Q8TNI1M6uqSDOkAFnyPsZJOLtVyeSR61sRz2I8kA0EeHwM4COSEKUCgRCpBnw
n0izwdXZ176DRodBl3tBxcXGKVZcBF3qBT0dFjo49eUM3Hb7LWRBe3Zad5fxscYReTlqnbtzF+hv
1pZI3vZAfHbXOtCjG41fLg+vW3V4ft+WSMY2RNlSQekXoFNHxCBXzjeeyMVzYu7T3UKXLbullYPi
GjT++hBMPOQFsZIlVj469yvfSdzC+PaEGHBkqHEkHt8Uc7YnnPuVw3iZi9XXN8Y6Ldg4XJAozBvz
/Ui79jcuVjJ3kq79xu4RNhF9tzx00L1vVYFIc0k+bC4Y94gzR8Mjcbrb8Mnigmt/a/IBkEsHLU0a
Jj97LDwSAGh5SsIadtUtmQTdp3Fjsr27g/GZwjyo03T4fn4lIWeXoCv5ilTKlL2zXlef3PJOYmTI
euVdmpSTcy3NaZJJ7M0FYwPQlRi4AFqfcZddnwFd67P+GV0HpHxCh1xJrp6ywpfXoB2J6mTCvk6Q
chJ0tU9AOSG+q0w8tCdA397KW7DuUly9hZ7lKdDxw9WK1kIsJvr+fF/fMvRcgvNaetuYE5Yauw26
NyAwdkd892fOmy95Lr15tUwY8F0MNVmm9cvTetO2w4MBvW2LJxwWQq3+qKaKUKs/c6rVTA/PMpwh
7/DwLM8ZMkE/PPsHuS6jvp3tkTwAAAAASUVORK5CYII="/>
</g>
</svg>
(我在 base64 字符串的开头添加了一个换行符,同样,只是为了让整个字符串内容在文件中左对齐——您可能不需要或不想这样做)。