Java 在服务器端为ColdFusion实现shodown.js标记解析器

Java 在服务器端为ColdFusion实现shodown.js标记解析器,java,parsing,coldfusion,markdown,Java,Parsing,Coldfusion,Markdown,这是一个“事实调查”的问题,要了解创建一个ColdFusion UDF来解析服务器上的标记有多困难,因为已经有一个java实现利用了shodown.js(请参阅本文末尾的代码),我想了解如何为ColdFusion实现它。我没有Java方面的经验,我也不会特别称自己为“程序员”,但我不希望这阻止我尝试 摘要 我想运行服务器端,以便将标记转换为HTML 为什么? 保存一个用户条目的两个版本,一个是markdown格式,另一个是HTML格式,允许我们向最终用户显示原始的markdown版本,以防他们想

这是一个“事实调查”的问题,要了解创建一个ColdFusion UDF来解析服务器上的标记有多困难,因为已经有一个java实现利用了shodown.js(请参阅本文末尾的代码),我想了解如何为ColdFusion实现它。我没有Java方面的经验,我也不会特别称自己为“程序员”,但我不希望这阻止我尝试

摘要

我想运行服务器端,以便将标记转换为HTML

为什么?

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

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

原因有二:

  • 到目前为止,还没有专门用于此目的的ColdFusion markdown解析器
  • 在客户端使用shodown.js,然后在服务器端使用不同的解析器,将导致显示给客户端的预览与存储在数据库中的版本之间的标记不一致。鉴于标记是松散定义的,大多数解析器实现都会有细微的差异
  • 没有人讨论这个问题

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

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

    是否有任何现有的实施方案?

    有,但不是为了这个特殊的目的。相反,它用于处理页面上的输出。本教程的注释部分提供了一个由名为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或自定义标记来使用此实现,类似于


    因为我没有Java方面的经验,所以我想从用户那里得到一些关于如何开始这项任务的建议和意见。我创建了一个

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

    本·纳德尔有一个


    该示例包含了您所需的一切—假设您已经准备好javascript代码。

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

    如果您的目标只是:

  • 提供带有实时预览的客户端标记编辑器(如堆栈溢出问题/答案编辑器),以及
  • 存储生成的html的经过相同处理的副本,以供最终用户显示
  • 然后我只看到两种实物期权:

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

    在同一个目录中有文件和markdown.txt文件(下面的示例)

    决战。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>
    
    更新

    这是一个在CFC中实现所有功能的版本。注意,我使用了他在shodown.js末尾添加的一点魔法,并将其放入一个CFC函数中,该函数的返回值是附加的(即shodownAdapterjs())

    氟氯化碳

    
    #chr(13)##chr(10)#var u converter=new shodown.converter();
    __makeHtml(markdownText);
    
    用法

    
    #toHTML(markdowstring)#
    
    事实上,我已经在一个可以在ColdFusion中使用的Java库中完成了决战。我所提供的示例(我承认是糟糕的文档)使用了一个自定义标记,但是您可以像这样轻松地使用Java组件

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

    也许这有帮助?无论如何,降价万岁!:)

    这太棒了!我将尝试将其捆绑到CFWheels的组件插件中!目前的威胁安全吗?我不知道。我认为这与shodown.js有更多关系。当我浏览shodown.js代码时,有对全局变量(即共享状态)的引用,例如
    g_URL
    ,所以我猜不是这样。但是,如果每次我认为这可能是线程安全的时候都会创建一个新的决战实例(即
    new shodown.convert()
    )。如果您不介意,可以在CFC部分解释一下您的代码吗?特别是绑定部分。我不太明白那里发生了什么事。还有,为什么不把shodown.js文件放在variables范围内,而不是每次都调用它呢?Adam,出于某种原因,我觉得从客户端发送两个版本并不舒服。此外,如果JS被禁用,可能会造成混乱!从客户端发送两个版本有什么问题?你已经在发送1并转换它,所以你显然相信降价。。。如果JS在客户端被禁用,那么编辑器将不会有多大用处。我认为降价的优点之一是避免注入任意HTML导致跨站点脚本攻击。这是完全绕过如果你
    <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>
    
    <cfset obj = createObject('java', 'com.adampresley.cfshowdown.Showdown').init() />
    <cfset parsedText = obj.toHTML(trim(someMarkdownContent)) />