仅在文本部分用 jsoup 替换字符串
Replace string with jsoup only in text portions
我发现了几个有相似问题和有价值答案的主题,但我仍在为此苦苦挣扎:
我想用 Jsoup 解析一些 html 以便我可以替换,例如
"changeme"
和
<changed>changeme</changed>
,但仅当它出现在 html 的文本部分时,如果它是标签的一部分则不会。所以,从这个开始 html:
<body>
<p><a href="http://changeme.html">test changeme app</a></p>
</BODY>
</HTML>
我想讲这个:
<body>
<p><a href="http://changeme.html">test <changed>changeme</changed> app</a></p>
</BODY>
</HTML>
我尝试了几种方法,这个方法更接近我想要的结果:
Document doc = null;
try {
doc = Jsoup.parse(new File("tmp1450348256397.txt"), "UTF-8");
} catch (Exception ex) {
}
Elements els = doc.body().getAllElements();
for (Element e : els) {
if (e.text().contains("changeme")) {
e.html(e.html().replaceAll("changeme","<changed>changeme</changed>"));
}
}
html = doc.toString();
System.out.println(html);
但是使用这种方法我发现了两个问题:
<body>
<p><a href="http://<changed>changeme</changed> .html">test
<changed>
changeme
</changed>
app</a></p>
</BODY>
</HTML>
在我介绍的新元素前后插入了换行符。这不是一个真正的问题,因为如果我使用#changed# 进行替换并且在 doc.toString() 之后我再次将它们替换为所需的值(使用 < >),我可以摆脱它们。
真正的问题: href中的URL被修改了,我不希望它发生
想法?谢谢
我认为您的问题是您要替换元素 html 而不仅仅是其文本,更改:
e.html(e.html().replaceAll("changeme","<changed>changeme</changed>"));
到
e.text(e.text().replaceAll("changeme","<changed>changeme</changed>"));
换行问题可能可以通过在 html = doc.toString();
之前执行 doc.outputSettings().prettyPrint(false);
来解决
最后我尝试了这个解决方案(在问题的最后),使用 TextNodes:
How I can replace "text" in the each tag using Jsoup
这是结果代码:
Elements els = doc.body().getAllElements();
for (Element e : els) {
for (Node child : e.childNodes()){
if (child instanceof TextNode && !((TextNode) child).isBlank()) {
((TextNode)child).text(((TextNode)child).text().replaceAll("changeme","<changed>changeme</changed>"));
}
}
}
现在输出符合预期,甚至没有引入额外的断行。在这种情况下,prettyPrint 必须设置为 True。
唯一的问题是我不太明白使用 TextNode
和 Element.text()
的区别。如果有人想提供一些信息,将不胜感激。
谢谢。
这是我的解决方案:
String html=""
+"<p><a href=\"http://changeme.html\">"
+ "test changeme "
+ "<div class=\"changeme\">"
+ "inner text changeme"
+ "</div>"
+ " app</a>"
+"</p>";
Document doc = Jsoup.parse(html);
Elements els = doc.body().getAllElements();
for (Element e : els) {
List<TextNode> tnList = e.textNodes();
for (TextNode tn : tnList){
String orig = tn.text();
tn.text(orig.replaceAll("changeme","<changed>changeme</changed>"));
}
}
html = doc.toString();
System.out.println(html);
TextNodes 始终是叶节点,即它们不包含更多 HTML 元素。在您原来的方法中,您将元素的 HTML 替换为新的 HTML 和替换的 changme
字符串。您只检查 changeme 是否是 TextNodes 内容的一部分,但是您替换了元素的 HTML 字符串中的每个匹配项,包括 TextNodes 之外的所有匹配项。
我的解决方案基本上和你的一样,但我使用的是 JSoup 方法 textNodes()
。这样我就不需要打字了。
P.S。
当然,我的解决方案和您的解决方案最后都会包含 <changed>changeme</changed>
而不是 <changed>changeme</changed>
。这可能是也可能不是您想要的。如果您不想这样做,那么您的结果将不再有效 HTML,因为 changed
不是有效的 HTML 标记。在这种情况下,Jsoup 不会帮助你。但是,您当然可以再次替换结果字符串中的所有 <changed>changeme</changed>
- 在 JSoup.
之外
我发现了几个有相似问题和有价值答案的主题,但我仍在为此苦苦挣扎:
我想用 Jsoup 解析一些 html 以便我可以替换,例如
"changeme"
和
<changed>changeme</changed>
,但仅当它出现在 html 的文本部分时,如果它是标签的一部分则不会。所以,从这个开始 html:
<body>
<p><a href="http://changeme.html">test changeme app</a></p>
</BODY>
</HTML>
我想讲这个:
<body>
<p><a href="http://changeme.html">test <changed>changeme</changed> app</a></p>
</BODY>
</HTML>
我尝试了几种方法,这个方法更接近我想要的结果:
Document doc = null;
try {
doc = Jsoup.parse(new File("tmp1450348256397.txt"), "UTF-8");
} catch (Exception ex) {
}
Elements els = doc.body().getAllElements();
for (Element e : els) {
if (e.text().contains("changeme")) {
e.html(e.html().replaceAll("changeme","<changed>changeme</changed>"));
}
}
html = doc.toString();
System.out.println(html);
但是使用这种方法我发现了两个问题:
<body>
<p><a href="http://<changed>changeme</changed> .html">test
<changed>
changeme
</changed>
app</a></p>
</BODY>
</HTML>
在我介绍的新元素前后插入了换行符。这不是一个真正的问题,因为如果我使用#changed# 进行替换并且在 doc.toString() 之后我再次将它们替换为所需的值(使用 < >),我可以摆脱它们。
真正的问题: href中的URL被修改了,我不希望它发生
想法?谢谢
我认为您的问题是您要替换元素 html 而不仅仅是其文本,更改:
e.html(e.html().replaceAll("changeme","<changed>changeme</changed>"));
到
e.text(e.text().replaceAll("changeme","<changed>changeme</changed>"));
换行问题可能可以通过在 html = doc.toString();
doc.outputSettings().prettyPrint(false);
来解决
最后我尝试了这个解决方案(在问题的最后),使用 TextNodes:
How I can replace "text" in the each tag using Jsoup
这是结果代码:
Elements els = doc.body().getAllElements();
for (Element e : els) {
for (Node child : e.childNodes()){
if (child instanceof TextNode && !((TextNode) child).isBlank()) {
((TextNode)child).text(((TextNode)child).text().replaceAll("changeme","<changed>changeme</changed>"));
}
}
}
现在输出符合预期,甚至没有引入额外的断行。在这种情况下,prettyPrint 必须设置为 True。
唯一的问题是我不太明白使用 TextNode
和 Element.text()
的区别。如果有人想提供一些信息,将不胜感激。
谢谢。
这是我的解决方案:
String html=""
+"<p><a href=\"http://changeme.html\">"
+ "test changeme "
+ "<div class=\"changeme\">"
+ "inner text changeme"
+ "</div>"
+ " app</a>"
+"</p>";
Document doc = Jsoup.parse(html);
Elements els = doc.body().getAllElements();
for (Element e : els) {
List<TextNode> tnList = e.textNodes();
for (TextNode tn : tnList){
String orig = tn.text();
tn.text(orig.replaceAll("changeme","<changed>changeme</changed>"));
}
}
html = doc.toString();
System.out.println(html);
TextNodes 始终是叶节点,即它们不包含更多 HTML 元素。在您原来的方法中,您将元素的 HTML 替换为新的 HTML 和替换的 changme
字符串。您只检查 changeme 是否是 TextNodes 内容的一部分,但是您替换了元素的 HTML 字符串中的每个匹配项,包括 TextNodes 之外的所有匹配项。
我的解决方案基本上和你的一样,但我使用的是 JSoup 方法 textNodes()
。这样我就不需要打字了。
P.S。
当然,我的解决方案和您的解决方案最后都会包含 <changed>changeme</changed>
而不是 <changed>changeme</changed>
。这可能是也可能不是您想要的。如果您不想这样做,那么您的结果将不再有效 HTML,因为 changed
不是有效的 HTML 标记。在这种情况下,Jsoup 不会帮助你。但是,您当然可以再次替换结果字符串中的所有 <changed>changeme</changed>
- 在 JSoup.