5

Rails ERB ファイルを Hpricot/Nokogiri タイプの方法で評価するのではなく、解析しようとしています。解析しようとしているファイルには、ERB (標準レール ビュー ファイル) を使用して生成された動的コンテンツが混在する HTML フラグメントが含まれています。Hpricot や Nokogiri と同じように、周囲のコンテンツを解析するだけでなく、処理するライブラリを探しています。 ERB シンボル、<%、<%= など、あたかも html/xml タグであるかのように。

理想的には、<%、<%= などの記号が独自のノード タイプとして含まれる DOM のような構造を取得します。

正規表現を使用して何かを一緒にハックできることは知っていますが、html コンテンツと erb コンテンツの両方が含まれる非常に大きなビュー コード ベースで実行する必要があるツールを開発しているため、もう少し信頼できるものを探していました。重要です。

たとえば、次のようなコンテンツです。

何とか何とか何とか
<div>My Great Text <%= my_dynamic_expression %></div>

次のようなツリー構造を返します。

根
 - text_node (何とか何とか)
 - 要素 (div)
    - text_node (マイ グレート テキスト)
        - erb_node (<%=)
4

2 に答える 2

5

最終的に、次の文法を持つ lex の ruby​​ バージョンであるRLex ( http://raa.ruby-lang.org/project/ruby-lex/ ) を使用して、この問題を解決することになりました。

%{

#NUM 257 を定義

#OPTOK 258 の定義
#IDENT 259 の定義
#OPETOK 260 の定義
#定義 CLSTOK 261
#CLTOK 262 の定義
#define FLOAT 263
#定義 FIXNUM 264
#定義ワード 265
#define STRING_DOUBLE_QUOTE 266
#define STRING_SINGLE_QUOTE 267

#定義 TAG_START 268
#定義 TAG_END 269
#define TAG_SELF_CONTAINED 270
#定義 ERB_BLOCK_START 271
#定義ERB_BLOCK_END 272
#定義 ERB_STRING_START 273
#定義ERB_STRING_END 274
#define TAG_NO_TEXT_START 275
#定義 TAG_NO_TEXT_END 276
#定義する WHITE_SPACE 277
%}

数字 [0-9]
空欄 [ ]
文字 [A-Z-z]
name1 [A-Za-z_]
name2 [A-Za-z_0-9]
valid_tag_character [A-Za-z0-9"'=@_():/ ]
ignore_tags スタイル|スクリプト
%%

{空白}+"\n" { return [ WHITE_SPACE, yytext ] }
"\n"{空白}+ { return [ WHITE_SPACE, yytext ] }
{空白}+"\n"{空白}+ { return [ WHITE_SPACE, yytext ] }

"\r" { return [ WHITE_SPACE, yytext ] }
"\n" { return[ yytext[0], yytext[0..0] ] };
"\t" { return[ yytext[0], yytext[0..0] ] };

^{空白}+ { return [ WHITE_SPACE, yytext ] }

{空白}+$ { return [ WHITE_SPACE, yytext ] };

"" { return [ TAG_NO_TEXT_START, yytext ] }
"" { return [ TAG_NO_TEXT_END, yytext ] }
"" { return [ TAG_SELF_CONTAINED, yytext ] }
"" { return [ TAG_SELF_CONTAINED, yytext ] }
"" { return [ TAG_START, yytext ] }
"" { return [ TAG_END, yytext ] }

"" { return [ ERB_BLOCK_END, yytext ] }
"" { return [ ERB_STRING_END, yytext ] }


{文字}+ { return [ WORD, yytext ] }


\".*\" { return [ STRING_DOUBLE_QUOTE, yytext ] }
'.*' { return [ STRING_SINGLE_QUOTE, yytext ] }
. { return [ yytext[0], yytext[0..0] ] }

%%

これは完全な文法ではありませんが、テキストの検索と再発行という私の目的のためには機能しました。その文法を次の小さなコードと組み合わせました。

    text_handler = MakeYourOwnCallbackHandler.new

    l = Erblex.new
    l.yyin = File.open(ファイル名, "r")

    ループする
      a,v = l.yylex
      a == 0 の場合は中断

      if( a < WORD )
        text_handler.character( v.to_s, a )
      そうしないと
        ケースa
        ワードのとき
          text_handler.text( v.to_s )
        TAG_START時
          text_handler.start_tag( v.to_s )
        TAG_END時
          text_handler.end_tag( v.to_s )
        ホワイトスペースのとき
          text_handler.white_space( v.to_s )
        ERB_BLOCK_START時
          text_handler.erb_block_start( v.to_s )
        ERB_BLOCK_END の場合
          text_handler.erb_block_end( v.to_s )      
        ERB_STRING_START時
          text_handler.erb_string_start( v.to_s )
        ERB_STRING_END時
          self.text_handler.erb_string_end( v.to_s )
        TAG_NO_TEXT_START時
          text_handler.ignorable_tag_start( v.to_s )
        TAG_NO_TEXT_END時
          text_handler.ignorable_tag_end( v.to_s )
        STRING_DOUBLE_QUOTEのとき
          text_handler.string_double_quote( v.to_s )
        STRING_SINGLE_QUOTEのとき
          text_handler.string_single_quote( v.to_s )
        TAG_SELF_CONTAINED の場合
          text_handler.tag_self_contained( v.to_s )
        終わり
      終わり  
    終わり
于 2010-04-09T22:46:41.780 に答える
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

于 2011-01-20T00:08:41.670 に答える