如何在Java中去除HTML实体的转义,但保留<、>、&、"和'这些字符?

3

我有一个UTF-8编码的HTML输入。在这个输入中,重音字符以HTML实体的形式呈现。例如:

<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>&aacute;rv&iacute;zt&#x0171;r&#x0151;&lt;b</body>
</html>

我的目标是在Java中尽可能地用utf-8字符替换html实体,以“规范化”html。换句话说,替换所有实体,除了&lt; &gt; &amp; &quot; &apos;

这个目标:

<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>árvíztűrő&lt;b</body>
</html>

我需要这个来使测试中比较html更容易,并且对于肉眼阅读更容易(大量转义的重音字符使得阅读非常困难)。
我不关心cdata部分(输入中没有cdata)。
我尝试过JSOUP(https://jsoup.org/)和Apache的Commons Text(https://commons.apache.org/proper/commons-text/),但都失败了:
public void test() throws Exception {

    String html = 
            "<html><head><META http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">" +
            "</head><body>&aacute;rv&iacute;zt&#x0171;r&#x0151;&lt;b</body></html>";

    // this is not good, keeps only the text content
    String s1 = Jsoup.parse(html).text();
    System.out.println("s1: " + s1);

    // this is better, but it unescapes the &lt; which is not what I want
    String s2 = StringEscapeUtils.unescapeHtml4(html);
    System.out.println("s2: " + s2);
}

StringEscapeUtils.unescapeHtml4() 已经接近我所需,但不幸的是它也会将 < 进行反转义:

<body>árvíztűrő<b</body>

我该怎么做?

这里是一个最简演示:https://github.com/riskop/html_utf8_canon.git

1个回答

3

查看Commons Text源代码可以发现,StringEscapeUtils.unescapeHtml4()将工作委托给一个AggregateTranslator,它由4个CharSequenceTranslator组成:

new AggregateTranslator(
        new LookupTranslator(EntityArrays.BASIC_UNESCAPE),
        new LookupTranslator(EntityArrays.ISO8859_1_UNESCAPE),
        new LookupTranslator(EntityArrays.HTML40_EXTENDED_UNESCAPE),
        new NumericEntityUnescaper()
);

我需要仅有的三位翻译来实现我的目标。
所以这就是它:
    // this is what I needed!
    String s3 = new AggregateTranslator(
            new LookupTranslator(EntityArrays.ISO8859_1_UNESCAPE),
            new LookupTranslator(EntityArrays.HTML40_EXTENDED_UNESCAPE),
            new NumericEntityUnescaper()
    ).translate(html);
    System.out.println("s3: " + s3);

整体方法:

@Test
public void test() throws Exception {

    String html = 
            "<html><head><META http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">" +
            "</head><body>&aacute;rv&iacute;zt&#x0171;r&#x0151;&lt;b</body></html>";

    // this is what I needed!
    CharSequenceTranslator UNESCAPE_HTML_EXCEPT_BASIC = new AggregateTranslator(
            new LookupTranslator(EntityArrays.ISO8859_1_UNESCAPE),
            new LookupTranslator(EntityArrays.HTML40_EXTENDED_UNESCAPE),
            new NumericEntityUnescaper()
    );

    String s3 = UNESCAPE_HTML_EXCEPT_BASIC.translate(html);
    System.out.println("s3: " + s3);

}

结果:

<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>árvíztűrő&lt;b</body>
</html>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接