【问题标题】:Library to parse ERB files解析 ERB 文件的库
【发布时间】:2010-04-06 23:14:07
【问题描述】:

我正在尝试以 Hpricot/Nokogiri 类型的方式解析而不是评估 rails ERB 文件。我尝试解析的文件包含与使用 ERB(标准 Rails 视图文件)生成的动态内容混合的 HTML 片段ERB 符号、

理想情况下,我会得到一个类似 DOM 的结构,其中

我知道可以使用正则表达式一起破解某些东西,但我正在寻找更可靠的东西,因为我正在开发一个我需要在一个非常大的视图代码库上运行的工具,其中 html 内容和erb的内容很重要。

例如内容如:

等等等等等等
我的好文 &lt%= my_dynamic_expression %>

会返回一个像这样的树形结构:

根 - text_node(等等等等) - 元素(div) - text_node(我的好文) - erb_node (

【问题讨论】:

    标签: ruby parsing erb lex


    【解决方案1】:

    我最终通过使用 RLex http://raa.ruby-lang.org/project/ruby-lex/ 解决了这个问题,这是 lex 的 ruby​​ 版本,语法如下:

    %{ #define 数字 257 #define OPTOK 258 #define IDENT 259 #define OPETOK 260 #define CLSTOK 261 #定义CLTOK 262 #define 浮点数 263 #define FIXNUM 264 #定义字265 #define STRING_DOUBLE_QUOTE 266 #define STRING_SINGLE_QUOTE 267 #define TAG_START 268 #定义 TAG_END 269 #define TAG_SELF_CONTAINED 270 #define ERB_BLOCK_START 271 #define ERB_BLOCK_END 272 #define ERB_STRING_START 273 #define ERB_STRING_END 274 #define TAG_NO_TEXT_START 275 #define TAG_NO_TEXT_END 276 #define WHITE_SPACE 277 %} 数字 [0-9] 空白的 [ ] 字母 [A-Z-Z] name1 [A-Za-z_] 名称2 [A-Za-z_0-9] valid_tag_character [A-Za-z0-9"'=@_():/ ] 忽略标签样式|脚本 %% {空白}+"\n" { 返回 [ WHITE_SPACE, yytext ] } "\n"{空白}+ { 返回 [ WHITE_SPACE, yytext ] } {空白}+"\n"{空白}+ { 返回 [ WHITE_SPACE, yytext ] } "\r" { 返回 [ WHITE_SPACE, yytext ] } "\n" { return[ yytext[0], yytext[0..0] ] }; "\t" { return[ yytext[0], yytext[0..0] ] }; ^{空白}+ { 返回 [ WHITE_SPACE, yytext ] } {空白}+$ { 返回 [ WHITE_SPACE, yytext ] }; "" { 返回 [TAG_NO_TEXT_START, yytext] } "" { 返回 [TAG_NO_TEXT_END, yytext] } “”{返回[TAG_SELF_CONTAINED,yytext]} “”{返回[TAG_SELF_CONTAINED,yytext]} "" { 返回 [ TAG_START, yytext ] } "" { 返回 [TAG_END, yytext ] } "" { 返回 [ERB_BLOCK_END, yytext ] } "" { 返回 [ERB_STRING_END, yytext] } {字母}+ { 返回 [ WORD, yytext ] } \".*\" { 返回 [ STRING_DOUBLE_QUOTE, yytext ] } '.*' { 返回 [ STRING_SINGLE_QUOTE, yytext ] } . { 返回 [ yytext[0], yytext[0..0] ] } %%

    这不是一个完整的语法,但出于我的目的,定位和重新发送文本,它有效。我把那个语法和一小段代码结合起来:

    text_handler = MakeYourOwnCallbackHandler.new l = Erblex.new l.yyin = File.open(file_name, "r") 循环做 a,v = l.yylex 如果 a == 0 则中断 如果(一个

    【讨论】:

    • rlex 生成的 Lexer.rb/Erblex.rb 不完整有什么问题吗?我在 OS X 和 Ubuntu 中都试过了,但是生成的词法分析器 RB 突然在一个大的 case/when 块的中间结束。我只试过rlex grammarrlex --output LexerClassName grammar,其中'grammar' 对应于一个名为'grammar.rl' 的文件。我有 Ruby 1.8.7。
    • 嗨莎拉,我确实有这个问题。我向 rlex 所有者提交了一个错误修复。如果您有兴趣,我可以将补丁文件发送给您,但这是您必须修复 ir rlex 的错误。
    • 你能以某种方式发布补丁吗?
    • 在使用 Treetop 而不是 RLex 创建 HerbGobbler(i18n 的开源英文文本提取器)时,我最终找到了更好的解决方案。少了很多越野车。更容易支持。我的语法可以在这里找到:github.com/douglasjsellers/herbgobbler/blob/master/grammer/…
    【解决方案2】:

    我最近遇到了类似的问题。我采用的方法是编写一个小脚本(erblint.rb)进行字符串替换,将 ERB 标签(<% %><%= %>)转换为 XML 标签,然后使用 Nokogiri 进行解析。

    看下面的代码明白我的意思:

    #!/usr/bin/env ruby
    require 'rubygems'
    require 'nokogiri'
    
    # This is a simple program that reads in a Ruby ERB file, and parses
    # it as an XHTML file. Specifically, it makes a decent attempt at
    # converting the ERB tags (<% %> and <%= %>) to XML tags (<erb-disp/>
    # and <erb-eval/> respectively.
    #
    # Once the document has been parsed, it will be validated and any
    # error messages will be displayed.
    #
    # More complex option and error handling is left as an exercise to the user.
    
    abort 'Usage: erb.rb <filename>' if ARGV.empty?
    
    filename = ARGV[0]
    
    begin
      doc = ""
      File.open(filename) do |file|
        puts "\n*** Parsing #{filename} ***\n\n"
        file.read(nil, s = "")
    
        # Substitute the standard ERB tags to convert them to XML tags
        #   <%= ... %> for <erb-disp> ... </erb-disp>
        #   <% ... %>  for <erb-eval> ... </erb-eval>
        #
        # Note that this won't work for more complex expressions such as:
        #   <a href=<% @some_object.generate_url -%> >link text</a>
        # Of course, this is not great style, anyway...
        s.gsub!(/<%=(.+?)%>/m, '<erb-disp>\1</erb-disp>')
        s.gsub!(/<%(.+?)%>/m, '<erb-eval>\1</erb-eval>')
        doc = Nokogiri::XML(s) do |config|
          # put more config options here if required
          # config.strict
        end
      end
    
      puts doc.to_xhtml(:indent => 2, :encoding => 'UTF-8')
      puts "Huzzah, no errors!" if doc.errors.empty?
    
      # Otherwise, print each error message
      doc.errors.each { |e| puts "Error at line #{e.line}: #{e}" }
    rescue
      puts "Oops! Cannot open #{filename}"
    end
    

    我已将此作为要点发布在 Github 上:https://gist.github.com/787145

    【讨论】:

    • 爱它!我实际上把它放在一个 html 注释中,以避免 ERB 中任何会重新编码 html value = value.gsub(/&lt;%=(.+?)%&gt;/m, '&lt;erb-disp&gt;&lt;!--\1--&gt;&lt;/erb-disp&gt;') 的东西之间的干扰
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-29
    • 1970-01-01
    • 2018-09-16
    • 1970-01-01
    • 1970-01-01
    • 2011-09-05
    • 2015-01-14
    相关资源
    最近更新 更多