我创建了一个包含两个<script type="application/javascript">/* .. */</script>
元素的JSoup文档。
问题:当我致电.html()
或.toString()
时,JSoup将逃脱我的JavaScript。
if (foo && bar)
得
if (foo && bar)
是否可以将JSoup配置为在转义时忽略<script>
元素?
这是(基本上)我如何创建我的jsoup文档。
final Document doc = Document.createShell("");
final Element head = doc.head();
head.appendElement("meta").attr("charset", "utf-8");
final String myJS = ...;
head.appendElement("script").attr("type", "application/javascript").text(myJS);
我目前的解决方法是在String.replace
上用.html()
替换占位符。但这有点像黑客。
head.appendElement("script").attr("type", "application/javascript").text("$MYJS$");
String s = doc.html();
s = s.replace("$MYJS$", myJS);
答案 0 :(得分:4)
无法再覆盖outerHtmlHead方法。
这就是我使用的:
head
.appendElement("script")
.attr("type","text/javascript")
.appendChild(new DataNode(getJavaScript(),""));
答案 1 :(得分:-1)
你“无法”禁用它。通过“不能”我的意思是不容易。您必须拦截/重新实现/覆盖节点遍历,这是我认为太多了。你可以这样做
String dom = Parser.unescapeEntities(doc.html(), false);
<强>更新强>
首先,我们必须确定问题的位置。
<强> TextNode.java 强>
void outerHtmlHead(StringBuilder accum, int depth,
Document.OutputSettings out) {
if ((out.prettyPrint())
&& ((((siblingIndex() == 0)
&& (this.parentNode instanceof Element)
&& (((Element) this.parentNode).tag().formatAsBlock()) && (!(isBlank()))) || ((out
.outline()) && (siblingNodes().size() > 0) && (!(isBlank())))))) {
indent(accum, depth, out);
}
boolean normaliseWhite = (out.prettyPrint())
&& (parent() instanceof Element)
&& (!(Element.preserveWhitespace(parent())));
Entities.escape(accum, getWholeText(), out, false, normaliseWhite,
false);
}
特别是问题在这里
Entities.escape(accum, getWholeText(), out, false, normaliseWhite,false);
<强> Entities.java 强>
static void escape(StringBuilder accum, String string,
Document.OutputSettings out, boolean inAttribute,
boolean normaliseWhite, boolean stripLeadingWhite) {
boolean lastWasWhite = false;
boolean reachedNonWhite = false;
EscapeMode escapeMode = out.escapeMode();
CharsetEncoder encoder = out.encoder();
CoreCharset coreCharset = CoreCharset.access$300(encoder.charset()
.name());
Map map = escapeMode.getMap();
int length = string.length();
int codePoint;
for (int offset = 0; offset < length; offset += Character
.charCount(codePoint)) {
codePoint = string.codePointAt(offset);
if (normaliseWhite) {
if (StringUtil.isWhitespace(codePoint)) {
if ((stripLeadingWhite) && (!(reachedNonWhite)))
continue;
if (lastWasWhite)
continue;
accum.append(' ');
lastWasWhite = true;
continue;
}
lastWasWhite = false;
reachedNonWhite = true;
}
if (codePoint < 65536) {
char c = (char) codePoint;
switch (c) {
case '&':
accum.append("&");
break;
case ' ':
if (escapeMode != EscapeMode.xhtml)
accum.append(" ");
else
accum.append(" ");
break;
case '<':
if ((!(inAttribute)) || (escapeMode == EscapeMode.xhtml))
accum.append("<");
else
accum.append(c);
break;
case '>':
if (!(inAttribute))
accum.append(">");
else
accum.append(c);
break;
case '"':
if (inAttribute)
accum.append(""");
else
accum.append(c);
break;
default:
if (canEncode(coreCharset, c, encoder))
accum.append(c);
else if (map.containsKey(Character.valueOf(c)))
accum.append('&')
.append((String) map.get(Character.valueOf(c)))
.append(';');
else
accum.append("&#x")
.append(Integer.toHexString(codePoint))
.append(';');
}
} else {
String c = new String(Character.toChars(codePoint));
if (encoder.canEncode(c))
accum.append(c);
else
accum.append("&#x").append(Integer.toHexString(codePoint))
.append(';');
}
}
}
好了,现在我们已经确定了问题,那么解决方案是什么。那么这就是问题所在。通常你要做的是覆盖outerHtmlHead
(在调用html()
或toString()-calls outerHtml
或outerHtml()
时为每个节点调用。问题是这个方法是{{ 3}}所以它不可见,以便在包外面覆盖它。
一种简单的方法是下载Jsoup的源代码,并在同一个包中包含您的自定义类。另一种方法是将这两者的可见性改为受保护。
abstract void outerHtmlHead(StringBuilder paramStringBuilder, int paramInt, Document.OutputSettings paramOutputSettings);
abstract void outerHtmlTail(StringBuilder paramStringBuilder, int paramInt,Document.OutputSettings paramOutputSettings);
项目将在扩展class Node
的每个类中都有编译错误,因为无法降低重写方法的可见性。
将可见性也更改为protected
。
之后,您可以实现扩展TextNode
类的新类。这样的事情就足够了我相信
public class RawTextNode extends TextNode {
@Override
protected void outerHtmlHead(StringBuilder accum, int depth, OutputSettings out) {
if ((out.prettyPrint())
&& ((((siblingIndex() == 0)
&& (parentNode() instanceof Element)
&& (((Element) parentNode()).tag().formatAsBlock()) && (!(isBlank()))) || ((out
.outline()) && (siblingNodes().size() > 0) && (!(isBlank())))))) {
indent(accum, depth, out);
}
}
}
并且您的代码必须相应更改
head.appendElement("script").attr("type", "application/javascript").appendChild(new RawTextNode(myJS, ""));
如果保持原样,文本将由TextNode
表示,您需要明确说明文本必须由您的自定义类表示。
当然,您可以更深入地创建一个新类,以通用的方式处理script
部分。