在服务器端为ColdFusion实现Showdown.js markdown解析器

时间:2011-01-05 03:17:27

标签: java parsing coldfusion markdown

这是一个“事实发现”问题,看看使用{{3}创建ColdFusion UDF以解析服务器上的markdown是多么困难已经有一个利用showdown.js的java实现(参见代码在这篇文章的最后)我想看看如何为ColdFusion实现它。我没有Java经验,我不会特别称自己为“程序员”,但我不希望这会阻止我尝试。

摘要

我想运行showdown.js parser.服务器端,以便将markdown转换为HTML。

为什么吗

保存两个版本的用户条目,一个是降价格式,另一个是HTML格式,允许我们向最终用户显示原始降价版本,以防他们想要编辑他们的条目。

为什么不使用服务器端解析器?

有两个原因:

  1. 截至目前,没有针对此特定目的的ColdFusion markdown解析器
  2. 在客户端使用Showdown.js,然后服务器端的不同解析器将导致显示给客户端的预览与存储在数据库中的版本之间出现不一致的标记。鉴于markdown定义松散,大多数解析器实现都会有细微差别。
  3. Shadown.js讨论了这个问题。

    为什么不在客户端进行所有解析并发布两个版本?

    这并不是一个安全的解决方案。我还认为用户可能会使用不匹配的HTML发布降价。

    现有实施吗?

    a very good blog entry,但不是出于这个特定目的。相反,它是用于处理页面上的输出。 one implementation called CFShowdown的评论部分包含一个名为David的用户编写的纯Java实现:

    ScriptEngineManager manager = new ScriptEngineManager();
    ScriptEngine jsEngine = manager.getEngineByName("js");
    try
    {
        jsEngine.eval(new InputStreamReader(getClass().getResourceAsStream("showdown.js")));
        showdownConverter = jsEngine.eval("new Showdown.converter()");
    }
    catch (Exception e)
    {
        log.error("could not create showdown converter", e);
    }
    
    try
    {
        return ((Invocable) jsEngine).invokeMethod(
            showdownConverter, 
            "makeHtml", 
            markdownString
        ) + "";
    }
    catch (Exception e)
    {
        log.error("error while converting markdown to html", e);
        return "[could not convert input]";
    }
    

    目标

    创建一个java类,允许我们将此实现与ColdFusion UDF或组件内的自定义标记一起使用,类似于<cfset html = getMarkdown(string)>

    由于我没有Java经验,我想从用户那里获得一些建议和意见,了解在哪里以及如何开始这项任务。我创建了一个

4 个答案:

答案 0 :(得分:4)

将文件showdown.js和文件markdown.txt(下面的示例)放在同一目录中。

<强> showdown.cfm

<cfscript>
manager = createObject("java", "javax.script.ScriptEngineManager").init();
jsEngine = manager.getEngineByName("js");

showdownJS = fileRead('#getDirectoryFromPath(getCurrentTemplatePath())#/showdown.js');

jsEngine.eval(showdownJS);
showdownConverter = jsEngine.eval("new Showdown.converter()");

markdownString = fileRead("#getDirectoryFromPath(getCurrentTemplatePath())#/markdown.txt");

args = [markdownString];

result = jsEngine.invokeMethod(
    showdownConverter,
    "makeHtml",
    args
) & "";
</cfscript>

<强> markdown.txt

Showdown Demo
-------------

You can try out Showdown on this page:

  - Type some [Markdown] text on the left side.
  - See the corresponding HTML on the right.

For a Markdown cheat-sheet, switch the right-hand window from *Preview* to *Syntax Guide*.

Showdown is a JavaScript port of the original Perl version of Markdown.  You can get the full [source code] by clicking on the version number at the bottom of the page.

Also check out [WMD, the Wysiwym Markdown Editor][wmd].  It'll be open source soon; email me at the address below if you'd like to help me test the standalone version.

**Start with a [blank page] or edit this document in the left window.**

  [Markdown]: http://daringfireball.net/projects/markdown/
  [source code]: http://attacklab.net/showdown/showdown-v0.9.zip
  [wmd]: http://wmd-editor.com/
  [blank page]: ?blank=1 "Clear all text"

<强>更新

这是一个采用Adam Presley's work in Java并在CFC中完成所有操作的版本。注意我在showdown.js的末尾添加了一点魔法并将其放入一个附加了返回值的CFC函数(即showdownAdapterJS())。

CFC

<cfcomponent output="false" accessors="true">
    <cffunction name="init" output="false" access="public" returntype="Showdown" hint="Constructor">
        <cfset variables.manager = createObject("java", "javax.script.ScriptEngineManager").init()>
        <cfset variables.engine = manager.getEngineByName("javascript")>
        <cfreturn this/>
    </cffunction>

    <cffunction name="toHTML" output="false" access="public" returntype="any" hint="">
        <cfargument name="markdownText" type="string" required="true"/>
        <cfset var local = structNew()/>
        <cfset var bindings = variables.engine.createBindings()>
        <cfset var result = "">

        <cftry>
            <cfset bindings.put("markdownText", arguments.markdownText)>
            <cfset variables.engine.setBindings(bindings, createObject("java", "javax.script.ScriptContext").ENGINE_SCOPE)>
            <cfset var showdownJS = fileRead('#getDirectoryFromPath(getCurrentTemplatePath())#/showdown.js')>
            <cfset showdownJS &= showdownAdapterJS()>
            <cfset result = engine.eval(showdownJS)>
            <cfcatch type="javax.script.ScriptException">
                <cfset result = "The script had an error: " & cfcatch.Message>
            </cfcatch>
        </cftry>

        <cfreturn result>
    </cffunction>

    <cffunction name="showdownAdapterJS" output="false" access="private" returntype="string" hint="">
        <cfset var local = structNew()/>
<cfsavecontent variable="local.javascript">
<cfoutput>#chr(13)##chr(10)#var __converter = new Showdown.converter();
__converter.makeHtml(markdownText);</cfoutput>
</cfsavecontent>
        <cfreturn local.javascript>
    </cffunction>
</cfcomponent>

用法

<cfset showdown = createObject("component", "Showdown").init()>
<cfset markdownString = fileRead("#getDirectoryFromPath(getCurrentTemplatePath())#/markdown.txt")>
<cfoutput>#showdown.toHTML(markdownString)#</cfoutput>

答案 1 :(得分:3)

您可以使用CFGroovy在CF中运行服务器端javascript - 这基本上允许您使用CFML内联运行任何JSR-223脚本语言。

Ben Nadel有example of running server-side javascript using CFGroovy and Rhino

该示例包含您需要的所有内容 - 假设您已将javascript代码放在一起。

答案 2 :(得分:3)

实际上,我已经将Showdown包装在可以在ColdFusion中使用的Java库中。我提供的示例,我承认的是糟糕的文档,使用自定义标记,但您可以像使用Java组件一样容易。

<cfset obj = createObject('java', 'com.adampresley.cfshowdown.Showdown').init() />
<cfset parsedText = obj.toHTML(trim(someMarkdownContent)) />

也许这有帮助吗?无论哪种方式,Markdown万岁! :)

答案 3 :(得分:1)

鉴于Markdown不是常规语言,并且大多数实现都是一系列正则表达式,正如您所指出的那样,它们之间必然存在差异。几乎没有避免它。

如果你的目标只是:

  1. 提供带有实时预览的客户端降价编辑器(如Stack Overflow问题/答案编辑器)和
  2. 存储生成的html的相同处理副本以供最终用户显示
  3. 然后我只看到两个真正的选择:

    1. 在服务器端执行所有降价处理,并使用AJAX完成预览以提交降价并获取更新的预览html(使用您最终用于生成存储的html的相同库),或
    2. 对客户端进行所有降价处理,并将 两者 原始降价和生成的HTML作为内容合成表单的一部分提交并存储;这样您就可以显示原始标记以进行编辑,并生成HTML以供显示。
    3. 就个人而言,我会选择2。