如何在XSL中对比XML节点值并高亮差异字符?
如何用XSLT对比XML中res1和res2的字符差异并在HTML中高亮显示
要实现你需要的字符级差异高亮,我们得在XSLT里自定义递归模板来逐个对比res1和res2的每个字符,把不同的部分用高亮样式包裹。因为你使用的是XSLT 1.0,没有内置的字符串拆分工具,所以我们用递归的方式来处理每个字符位置。
修改后的完整XSL代码
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> <html> <body> <h2>Report</h2> <xsl:apply-templates/> </body> </html> </xsl:template> <xsl:template match="Message/DiffDetailMessage"> <table border="2"> <xsl:apply-templates select="TestCaseID"/> <tr> <td><b>Res1</b></td> <td> <xsl:call-template name="compare-characters"> <xsl:with-param name="str1" select="res1"/> <xsl:with-param name="str2" select="res2"/> <xsl:with-param name="position" select="1"/> <xsl:with-param name="is-res1" select="true()"/> </xsl:call-template> </td> </tr> <tr> <td><b>Res2</b></td> <td> <xsl:call-template name="compare-characters"> <xsl:with-param name="str1" select="res1"/> <xsl:with-param name="str2" select="res2"/> <xsl:with-param name="position" select="1"/> <xsl:with-param name="is-res1" select="false()"/> </xsl:call-template> </td> </tr> </table> <br/> </xsl:template> <xsl:template match="TestCaseID"> <tr> <td><b>Test CaseID </b></td> <td><xsl:value-of select="."/></td> </tr> </xsl:template> <!-- 递归模板:对比两个字符串的每个字符,返回带高亮的文本 --> <xsl:template name="compare-characters"> <xsl:param name="str1"/> <xsl:param name="str2"/> <xsl:param name="position"/> <xsl:param name="is-res1"/> <!-- 获取当前位置的字符 --> <xsl:variable name="char1" select="substring($str1, $position, 1)"/> <xsl:variable name="char2" select="substring($str2, $position, 1)"/> <!-- 判断是否需要高亮 --> <xsl:choose> <xsl:when test="$char1 != $char2 or ($position > string-length($str1) or $position > string-length($str2))"> <!-- 高亮不同的字符或超出长度的部分 --> <span style="background-color: yellow; font-weight: bold;"> <xsl:value-of select="if ($is-res1) then $char1 else $char2"/> </span> </xsl:when> <xsl:otherwise> <!-- 相同字符直接输出 --> <xsl:value-of select="if ($is-res1) then $char1 else $char2"/> </xsl:otherwise> </xsl:choose> <!-- 递归处理下一个字符,直到两个字符串都处理完 --> <xsl:if test="$position <= string-length($str1) or $position <= string-length($str2)"> <xsl:call-template name="compare-characters"> <xsl:with-param name="str1" select="$str1"/> <xsl:with-param name="str2" select="$str2"/> <xsl:with-param name="position" select="$position + 1"/> <xsl:with-param name="is-res1" select="$is-res1"/> </xsl:call-template> </xsl:if> </xsl:template> </xsl:stylesheet>
关键逻辑说明
递归对比模板
compare-characters:- 用
substring提取两个字符串对应位置的字符 - 如果字符不同,或者其中一个字符串已到末尾(另一个还有剩余字符),就用黄色背景的
<span>包裹该字符实现高亮 - 递归调用自身处理下一个字符,直到两个字符串的所有字符都处理完毕
- 用
res1/res2输出逻辑修改:
不再直接输出原始文本,而是调用对比模板,通过is-res1参数控制输出res1或res2的字符,保证两边的差异位置对应高亮。长度不一致处理:
如果两个字符串长度不同,超出的部分会自动高亮,比如res2末尾的空格也会被识别为差异。
Java转换代码示例
你可以用Java标准API执行XML到HTML的转换:
import javax.xml.transform.*; import javax.xml.transform.stream.*; import java.io.*; public class XmlToHtmlConverter { public static void main(String[] args) throws Exception { Source xmlSource = new StreamSource(new File("your-input.xml")); Source xsltSource = new StreamSource(new File("your-transform.xsl")); TransformerFactory factory = TransformerFactory.newInstance(); Transformer transformer = factory.newTransformer(xsltSource); Result result = new StreamResult(new File("output.html")); transformer.transform(xmlSource, result); System.out.println("HTML报告已生成!"); } }
内容的提问来源于stack exchange,提问作者new_programmer
相关产品推荐
相关产品推荐

