仅在文本部分用 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>
  1. 在我介绍的新元素前后插入了换行符。这不是一个真正的问题,因为如果我使用#changed# 进行替换并且在 doc.toString() 之后我再次将它们替换为所需的值(使用 < >),我可以摆脱它们。

  2. 真正的问题: 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。

唯一的问题是我不太明白使用 TextNodeElement.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。 当然,我的解决方案和您的解决方案最后都会包含 &lt;changed&gt;changeme&lt;/changed&gt; 而不是 <changed>changeme</changed>。这可能是也可能不是您想要的。如果您不想这样做,那么您的结果将不再有效 HTML,因为 changed 不是有效的 HTML 标记。在这种情况下,Jsoup 不会帮助你。但是,您当然可以再次替换结果字符串中的所有 &lt;changed&gt;changeme&lt;/changed&gt; - 在 JSoup.

之外