仅在文本部分用jsoup替换字符串

时间:2015-12-17 17:02:26

标签: java 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>
  1. 在我介绍的新元素之前和之后插入换行符。这不是一个真正的问题,因为如果我使用#change#来进行替换并且在doc.toString()之后我将它们删除它们,我将它们再次替换为所需的值(使用&lt;&gt;)。

  2. 真正的问题:href中的网址已被修改,我不希望它发生。

  3. 想法? THX。

3 个答案:

答案 0 :(得分:3)

我认为您的问题是您要更换元素html而不仅仅是文本,更改:

e.html(e.html().replaceAll("changeme","<changed>changeme</changed>"));

e.text(e.text().replaceAll("changeme","<changed>changeme</changed>"));

在执行doc.outputSettings().prettyPrint(false);

之前,可以通过html = doc.toString();来解决换行问题

答案 1 :(得分:1)

最后,我尝试了这个解决方案(在问题的最后),使用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。

唯一的问题是我并不真正理解使用TextNodeElement.text()的区别。如果有人想提供一些信息,将非常感激。

感谢。

答案 2 :(得分:1)

这是我的解决方案:

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元素。在您的原始方法中,使用替换为changme字符串的新HTML替换元素的HTML。您只检查changeme是TextNodes内容的一部分,但是替换元素的HTML字符串中的每个匹配项,包括TextNodes之外的所有匹配项。

我的解决方案基本上与您的解决方案类似,但我使用JSoup方法textNodes()。这样我就不需要进行类型转换。

P.S。 当然,我的解决方案和您的解决方案最终将包含&lt;changed&gt;changeme&lt;/changed&gt;而不是<changed>changeme</changed>。这可能是也可能不是你想要的。如果您不想这样,那么您的结果就不再是有效的HTML,因为changed不是有效的HTML标记。在这种情况下,Jsoup不会帮助你。但是,您当然可以再次在结果字符串中替换所有&lt;changed&gt;changeme&lt;/changed&gt; - 在JSoup之外。