最近工作中有涉及到新老API返回内容的比较,有时为了方便看Diff,需要干预一下API返回的Response,忽略一些期望的Diff,更好的发现一些期望之外的Diff,来发现Bug。
下面这个函数就是把API返回的结果做一些替换,减少Diff的干扰。因为Response返回的Html格式,为了方便操作把Body先转换成String,做正则匹配替换操作,为了方便Python脚本比较内容不同(具体内容可以参考这篇文章《Python DiffLib–比较文本内容》),再把Body解析成Html格式输出到Log文件里。
这里用到了Jsoup,Jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。
import org.jsoup.Jsoup;
import org.jsoup.select.Elements;
private Document getDocumentBody(String body)
{
String headingAlign = "" ;
body = body.replaceAll(headingAlign, "" );
String docMetadata = "[\\s\\S]* ";
body = body.replaceAll(docMetadata, " ");
String docChangeMC = " ";
body = body.replaceAll(docChangeMC, " ");
String refAnchor = "" ;
body = body.replaceAll(refAnchor, "");
Document doc = Jsoup.parseBodyFragment(body);
return doc;
}
从处理过的Body中提取需要比较的部分,
if (response.body() != null && !(response.body().asString().equals("")))
{
Elemnets seclaw = getDocumentBody(response.body().asString()).getElementsByTag("seclaw:seclaw");
stream.println(seclaw);
}
API返回的Response原样输出时,字符都是正常的,但是经过Jsoup处理后,发现有些转义字符原样输出了,这将影响内空比较结果。
代表空格
<
代表 <
>
代表 >
parseBodyFragment 方法创建一个空壳的文档,并插入解析过的HTML到body元素中。假如使用正常的 Jsoup.parse(String html) 方法,通常也可以得到相同的结果,但是明确将用户输入作为 body片段处理,以确保用户所提供的任何糟糕的HTML都将被解析成body元素。经过Jsoup的解析,将API原Response Body中的一些空格和<>符号以转义符的形式出现了。
<heading>
<title>Chapter 21 Bonds and Guarantees</title>
</heading>
<seclaw:level leveltype="unclassified">
<heading>
<title><emph typestyle="caps">Introduction to Bonds and Guarantees</emph></title>
</heading>
<seclaw:bodytext />
</seclaw:level>
为什么要用转义字符串?
这就要说到HTML转义字符串
转义字符串(Escape Sequence)也称字符实体(Character Entity)。在HTML中,定义转义字符串的原因有两个:
第一个原因是像“<”和“>”这类符号已经用来表示HTML标签,因此就不能直接当作文本中的符号来使用。为了在HTML文档中使用这些符号,就需要定义它的转义字符串。当解释程序遇到这类字符串时就把它解释为真实的字符。在输入转义字符串时,要严格遵守字母大小写的规则。
第二个原因是,有些字符在ASCII字符集中没有定义,因此需要使用转义字符串来表示。
转义字符串的组成
转义字符串(Escape Sequence),即字符实体(Character Entity)分成三部分:第一部分是一个&符号,英文叫ampersand;第二部分是实体(Entity)名字或者是#加上实体(Entity)编号;第三部分是一个分号。
比如,要显示小于号(<),就可以写 <
或者 < 。
用实体(Entity)名字的好处是比较好理解,一看lt,大概就猜出是less than的意思,但是其劣势在于并不是所有的浏览器都支持最新的Entity名字。而实体(Entity)编号,各种浏览器都能处理。
提示:
实体名称(Entity)是区分大小写的。
备注:同一个符号,可以用“实体名称”和“实体编号”两种方式引用,“实体名称”的优势在于便于记忆,但不能保证所有的浏览器都能顺利识别它,而“实体编号”则没有这种担忧,但它实在不方便记忆。
Java 中StringEscapeUtils 类进行转义和反转义,例如:
转义:
System.out.println(StringEscapeUtils.escapeHtml4(""));
输出:
<div></div>
反转义:
System.out.println(StringEscapeUtils.unescapeHtml4("<div></div>"));
输出:
<div></div>
所以有关转义的问题就可以得到解决了:
import org.apache.commons.lang3.StringEscapeUtils;
import org.jsoup.select.Elements;
if (response.body() != null && !(response.body().asString().equals("")))
{
Elements elements = getDocumentBody(response.body().asString()).getElementsByTag("seclaw:seclaw");
stream.println(StringEscapeUtils.unescapeHtml4(elements.toString()));
}
这样反转义一下,前面输出有转义符的问题就解决了。
<heading>
<title>Chapter 21 Bonds and Guarantees</title>
</heading>
<seclaw:level leveltype="unclassified">
<heading>
<title><emph typestyle="caps">Introduction to Bonds and Guarantees</emph></title>
</heading>
<seclaw:bodytext />
</seclaw:level>