匹配 PegDown+JSoup 输出到 PageDown 输出

Matching PegDown+JSoup Output to PageDown Output

我正在尝试在客户端和服务器端解析和清理 markdown。

但是,我发现两者的输出不相同的情况。例如:

输入降价: how are <div>tags</div> treated?

PageDown 输出: <p>how are tags treated?</p>

PegDown/JSoup 输出:

<p>how are </p>tags treated?
<p></p>

我没有对 JSoup 做任何花哨的事情。这是我的代码:

public class Main {

    public static void main(String... args){

        PegDownProcessor pdp = new PegDownProcessor();

        String markdown = "how are <div>tags</div> treated?";

        String html = pdp.markdownToHtml(markdown);

        Whitelist whitelist = Whitelist.relaxed().removeTags("div");

        html = Jsoup.clean(html, whitelist);
        System.out.println(html);

        System.out.println("Done.");
    }
}

我明白为什么会这样,我对两个不同的系统产生两个不同的输出并不感到惊讶。 我的问题是: 我如何设置 JSoup 以便它只删除 <div> 标签而不是添加额外的 <p> 标签?

我的最终目标只是让服务器端 parsing/sanitizing 生成与客户端 parsing/sanitizing 相当相似的结果。如果有更好的方法可以做到这一点,我愿意接受建议。我真的不在乎两者的输出是否完全相同,但是用户会非常注意到额外的 <p> 标签之类的东西,所以我试图消除这一主要差异。

奖金问题:是否有PageDown可以输出的html标签和属性的列表?

编辑: 我也尝试过使用 the OWASP sanitizer,但我得到的结果非常相似:删除了 <div> 标签,但是 <p> 标签在上面的方式中是 "fixed",这导致 html 与 PageDown 的消毒剂不同。

how can I setup JSoup so that it simply removes the <div> tags instead of adding extra <p> tags?

HTML 5 规范拒绝在 p 元素中使用 div 元素。 Jsoup 尊重这些规范,这就是为什么在最终的 html 字符串中有两个 p 元素。

为了更好地理解为什么会发生这种情况,让我们看看 Jsoup#clean 是如何分三个步骤工作的:

  1. 解析脏html
  2. 调整结果树以符合HTML 5 规格
  3. 删除被拒绝的标签

在第 2 步中,第一个 <p> 标签在打开 div 之前关闭。第二个 p 也在同一步骤中获得了它的开始标签。由于 Jsoup 不知道这一段的合法内容从哪里开始,所以它将第二段的内容限制在严格的数量(即什么都没有)。

第 1 步和第 2 步中的操作会创建满足 HTML 5 规范的新 HTML 代码。在第 3 步中,现在可以删除 div

My end goal is to simply have the server-side parsing/sanitizing generate reasonably similar results to the client-side parsing/sanitizing.

为避免像此处发现的其他情况,您应该在客户端和服务器端使用相同的系统。由于 Pagedown 是用 Java 脚本编写的,您可以尝试 运行 服务器端 Java 脚本引擎中的它。

仅举几例:

  • Nashorn(内置Java8)
  • 犀牛
  • V8

示例代码

下面是一个示例,说明了 Nashorn 的用法:

Caller.java

ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.eval(new FileReader("script.js"));

Invocable invocable = (Invocable) engine;

Object result = invocable.invokeFunction("myFunction", "fooValue");

System.out.println(result);
System.out.println(result.getClass());

script.js

function myFunction(foo) {
   // ...
}

另见

  • How to embed V8 in a Java application?
  • List of HTML5 elements that can be nested inside P element?