=begin Start of Document <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title>htmlsplit.rb</title> <link href="rubydoc.css" rel="stylesheet"> </head> <body> | <a href="./">提る</a> | <h1>HTML Split Library</h1> <p> HTMLを粕み今きする。 粕み哈んだ矢今はタグと矢机误の芹误になる。 to_sメソッドでHTMLに提すことが叫丸る。</p> <h2>クラス办枉</h2> <table bgcolor="#FFFFFF" border="1"> <tr><td><a href="#HTMLSplit">HTMLSplit</a><td>HTMLをタグと矢机デ〖タに尸充する。 <tr> <td><a href="#CharacterData">CharacterData</a> <td>矢机デ〖タ <tr><td><a href="#EmptyElementTag">EmptyElementTag</a> <td>鄂妥燎のタグ <tr> <td><a href="#StartTag">StartTag</a> <td>倡幌タグ <tr> <td><a href="#EndTag">EndTag</a> <td>姜位タグ <tr> <td><a href="#Comment">Comment</a> <td>コメント <tr> <td><a href="#Declaration">Declaration</a> <td>离咐(DOCTYPE) <tr> <td><a href="#SSI">SSI</a> <td>SSIⅷ <tr> <td><a href="#ERuby">ERuby</a> <td>eRuby/ASP/JSPスクリプトⅷ <tr> <td><a href="#PHP">PHP</a> <td>PHPスクリプトⅷ </table> ⅷタグの掳拉猛などに虽め哈まれたスクリプトは千急できません。 <h2>蝗い数 </h2> <h3>粕み哈み</h3> <pre class="Exception"><samp>#!/usr/bin/ruby require "htmlsplit" obj = HTMlSplit.new(ARGF.read)</samp></pre> <h3>叫蜗</h3> <pre> obj.document.each {|e| print e.to_s } </pre> <h3>掳拉の肋年</h3> <pre> img = Tag('img/') img['src']='xxx.png' #<img src="xxx.png"> o = Tag('option') o['selected']=true #<option selected> </pre> =end require "cgi" require "kconv" =begin EmptyElementTag <h2><a name="EmptyElementTag">EmptyElementTag</a></h2> 鄂妥燎のタグ <h3>クラスメソッド</h3> <dl compact> <dt>new(<var class="String">name</var>[,<var class="Hash">attr</var>]) <dd>糠しいオブジェクトを栏喇する。 <var class="String">name</var>はタグの叹涟 <var class="Hash">attr</var>はタグの掳拉nilまたはHash </dl> <h3>メソッド</h3> <dl compact> <dt class="String">name <dd>タグ叹を手す。 <dt class="Hash">attr <dd>掳拉を手す。 <dt class="String">to_s <dd>HTMLを手す。 <dt class="String">self[<var class="String">key</var>] <dd>keyに簇息づけられた掳拉猛を手します。 澈碰するキ〖が判峡されていない箕には·nilを手します。 <dt class="String">self[<var class="String">key</var>]= <var class="String">value</var> <dd><var class="String">key</var>に滦して<var class="String">value</var>を簇息づけます。 <var class="String">value</var>がnilの箕·<var class="String">key</var>に滦する簇息を艰り近きます。 </dl> =end class EmptyElementTag def initialize(name,attr=nil) @name = name.downcase @attr = attr end attr_accessor :name attr_accessor :attr def to_s if @attr "<"+@name+@attr.keys.sort.collect{|n| v = @attr[n] if v==true ' ' + n else ' ' + n + '="' + CGI::escapeHTML(v) + '"' end }.to_s+">" else "<#{@name}>" end end def [](key) attr and attr[key] end def []=(key,value) if attr attr[key]=value else attr = value and {key=>value} end end end =begin StartTag <h2>StartTag</h2> 倡幌タグ <h3>クラスメソッド</h3> <dl compact> <dt>new(<var class="String">name</var>[,<var class="Hash">attr</var>]) <dd>糠しいオブジェクトを栏喇する。 <var class="String">name</var>はタグの叹涟 <var class="Hash">attr</var>はタグの掳拉nilまたはHash </dl> <h3>メソッド</h3> <dl compact> <dt class="String">name <dd>タグ叹を手す。 <dt class="Hash">attr <dd>掳拉を手す。 <dt class="String">to_s <dd>HTMLを手す。 <dt class="String">self[<var class="String">key</var>] <dd>keyに簇息づけられた掳拉猛を手します。 澈碰するキ〖が判峡されていない箕には·nilを手します。 <dt class="String">self[<var class="String">key</var>]= <var class="String">value</var> <dd><var class="String">key</var>に滦して<var class="String">value</var>を簇息づけます。 <var class="String">value</var>がnilの箕·<var class="String">key</var>に滦する簇息を艰り近きます。 </dl> =end class StartTag attr_accessor :name attr_accessor :attr def initialize(name,attr=nil) @name = name.downcase @attr = attr end def to_s if @attr "<"+@name+@attr.keys.sort.collect{|n| v = @attr[n] if v==true ' ' + n else ' ' + n + '="' + CGI::escapeHTML(v) + '"' end }.to_s+">" else "<#{@name}>" end end def [](key) attr and attr[key] end def []=(key,value) if attr attr[key]=value else attr = value and {key=>value} end end end =begin EndTag <h2>EndTag</h2> 姜位タグ <h3>クラスメソッド</h3> <dl compact> <dt>new(<var class="String">name</var>) <dd>糠しいオブジェクトを栏喇する。 <var class="String">name</var>はタグの叹涟 </dl> <h3>メソッド</h3> <dl compact> <dt class="String">name <dd>タグ叹を手す。 <dt class="String">to_s <dd>HTMLを手す。 </dl> =end class EndTag def initialize(name) @name = name.downcase end attr_accessor :name def to_s "</#{@name}>" end end =begin CharacterData <h2>CharacterData</h2> 矢机デ〖タ <h3>クラスメソッド</h3> <dl compact> <dt>new(<var class="String">text</var>) <dd>糠しいオブジェクトを栏喇する。 <var class="String">text</var>はテキスト </dl> <h3>メソッド</h3> <dl compact> <dt class="String">text <dd>テキストを手す。 <dt class="String">to_s <dd>HTMLを手す。 </dl> =end class CharacterData def initialize(text) @text = text end attr_accessor :text def to_s @text end end =begin Declaraion <h2>Declaraion</h2> SGML离咐 <h3>クラスメソッド</h3> <dl compact> <dt>new(<var class="String">text</var>) <dd>糠しいオブジェクトを栏喇する。 <var class="String">text</var>はテキスト </dl> <h3>メソッド</h3> <dl compact> <dt class="String">text <dd>テキストを手す。 <dt class="String">to_s <dd>HTMLを手す。 </dl> =end class Declaration def initialize(text) @text = text end attr_accessor :text def to_s "<!#{@text}>" end end =begin Comment <h2>Comment</h2> コメント <h3>クラスメソッド</h3> <dl compact> <dt>new(<var class="String">text</var>) <dd>糠しいオブジェクトを栏喇する。 <var class="String">text</var>はテキスト </dl> <h3>メソッド</h3> <dl compact> <dt class="String">text <dd>テキストを手す。 <dt class="String">to_s <dd>HTMLを手す。 </dl> =end class Comment def initialize(text) @text = text end attr_accessor :text def to_s "<!--#{@text}-->" end end =begin SSI <h2>SSI</h2> SSI <h3>クラスメソッド</h3> <dl compact> <dt>new(<var class="String">text</var>) <dd>糠しいオブジェクトを栏喇する。 <var class="String">text</var>はテキスト </dl> <h3>メソッド</h3> <dl compact> <dt class="String">text <dd>テキストを手す。 <dt class="String">to_s <dd>HTMLを手す。 </dl> =end class SSI def initialize(text) @text = text end attr_accessor :text def to_s "<!--#{@text}-->" end end =begin ERuby <h2>ERuby</h2> eRuby/ASP/JSPスクリプト <h3>クラスメソッド</h3> <dl compact> <dt>new(<var class="String">text</var>) <dd>糠しいオブジェクトを栏喇する。 <var class="String">text</var>はテキスト </dl> <h3>メソッド</h3> <dl compact> <dt class="String">text <dd>テキストを手す。 <dt class="String">to_s <dd>HTMLを手す。 </dl> =end class ERuby def initialize(text) @text = text end attr_accessor :text def to_s "<%#{@text}%>" end end =begin PHP <h2>PHP</h2> PHPスクリプト <h3>クラスメソッド</h3> <dl compact> <dt>new(<var class="String">text</var>) <dd>糠しいオブジェクトを栏喇する。 <var class="String">text</var>はテキスト </dl> <h3>メソッド</h3> <dl compact> <dt class="String">text <dd>テキストを手す。 <dt class="String">to_s <dd>HTMLを手す。 </dl> =end class PHP attr_accessor :text def initialize(text) @text = text end def to_s "<?#{@text}?>" end end =begin HTMLSplit <h2><a name="HTMLSplit">HTMLSplit</a></h2> HTML粕み今き <h3>クラスメソッド</h3> <dl compact> <dt>new(<var class="String">html</var>) <dd>糠しいオブジェクトを栏喇する。 <var class="String">html</var>はHTML矢今 </dl> <h3>メソッド</h3> <dl compact> <dt class="Array">document <dd>ドキュメントの芹误を手す。 <dt class="String">to_s <dd>HTMLを手す。 <dt class="Iterator">each {|<var>obj</var>,<var class="Array">tag</var>| ...} <dd>ドキュメントの称オブジェクト(<var>obj</var>)に滦してブロックを删擦します。 <var class="Array">tag</var>は倡幌タグのリスト∈ [ StartTag , <var class="Integer">インデクス</var>] ∷ <dt class="Integer">index(<var class="Class">class</var>, <var class="Integer">start</var>, <var class="Integer">end</var>, <var>value</var>, <var class="Integer">count</var>) {|obj| ...} <dd><var class="Integer">start</var>から<var class="Integer">end</var>までの妥燎で<var class="Class">class</var>と霹しい<var class="Integer">count</var>戎誊の妥燎の疤弥を手します。 霹しい妥燎がひとつもなかった箕にはnilを手します。<br> <var>value</var>にnil笆嘲の猛を回年した箕には妥燎が<var>value</var>と霹しいかチェックを乖います。<var class="Class">class</var>がEmptyElementTag,StartTag,EndTagの箕はタグ叹、それ笆嘲はテキストによって孺秤します。<br> ブロックを回年して钙び叫された箕にはブロックで妥燎が霹しいか删擦する。 <dt class="Integer">end_index(<var class="Integer">start</var>) <dd><var class="Integer">start</var>に滦炳するEndTagのインデクスを手します。 滦炳する妥燎がなかった箕にはnilを手します。<br> </dl> =end class HTMLSplit EMPTY = %w(area base basefont bgsound br col frame hr img input isindex keygen link meta nextid param spacer wbr) def initialize(html) @document = [] #パ〖スしたHTMLのリスト name = '' text = '' attr = {} attrname = '' state = :TEXT # html.each_byte {|c| char = c.chr case state when :TEXT if c==60 if text.length>0 @document << CharacterData.new(text) end name = '' attr={} state = :TAGNAME else text << char end when :TAGNAME case char when '>' name.downcase! if EMPTY.include?(name) @document << EmptyElementTag.new(name,nil) else if name[0,1]=='/' @document << EndTag.new(name[1..-1]) else @document << StartTag.new(name,nil) end end text = '' state = :TEXT when '!' text = '' state = :DECLARE when '%' text = '' state = :ERUBY when '?' text = '' state = :PHP when /\s/ text='' state = :SPACE else name << char end when :SPACE #掳拉粗の鄂球 case char when '>' name.downcase! if EMPTY.include?(name) @document << EmptyElementTag.new(name,attr) else if name[0,1]=='/' @document << EndTag.new(name[1..-1]) else @document << StartTag.new(name,attr) end end text = '' state = :TEXT when /\s/ else attrname=char state = :ATTRNAME end when :ATTRNAME #掳拉叹 case char when /\s/ state = :BEFOREEQUAL when '=' state = :AFTEREQUAL when '>' attr[attrname.downcase]=true name.downcase! if EMPTY.include?(name) @document << EmptyElementTag.new(name,attr) else if name[0,1]=='/' @document << EndTag.new(name[1..-1]) else @document << StartTag.new(name,attr) end end text = '' state = :TEXT else attrname << char end when :BEFOREEQUAL #= case char when '=' state = :AFTEREQUAL when '>' attr[attrname.downcase]=true name.downcase! if EMPTY.include?(name) @document << EmptyElementTag.new(name,attr) else if name[0,1]=='/' @document << EndTag.new(name[1..-1]) else @document << StartTag.new(name,attr) end end text = '' state = :TEXT when /\s/ else attr[attrname.downcase]=true attrname = char state = :ATTRNAME end when :AFTEREQUAL #= case char when "'" text='' state = :SQVALUE when '"' text='' state = :DQVALUE when '>' attr[attrname.downcase]=true name.downcase! if EMPTY.include?(name) @document << EmptyElementTag.new(name,attr) else if name[0,1]=='/' @document << EndTag.new(name[1..-1]) else @document << StartTag.new(name,attr) end end text = '' state = :TEXT when /\s/ else text=char state = :VALUE end when :VALUE #猛 case char when /\s/ attr[attrname.downcase]=CGI::unescapeHTML(text) state = :SPACE when '>' attr[attrname.downcase]=CGI::unescapeHTML(text) name.downcase! if EMPTY.include?(name) @document << EmptyElementTag.new(name,attr) else if name[0,1]=='/' @document << EndTag.new(name[1..-1]) else @document << StartTag.new(name,attr) end end text = '' state = :TEXT else text << char end when :SQVALUE #'猛' if c==39 attr[attrname.downcase]=CGI::unescapeHTML(text) state = :SPACE else text << char end when :DQVALUE #"猛" if c==34 attr[attrname.downcase]=CGI::unescapeHTML(text) state = :SPACE else text << char end when :COMMENT case char when '>' if text[-2,2]=='--' #コメント姜位 text = text[0..-3] if text=~/^#[a-z]+/ #SSI @document << SSI.new(text) else @document << Comment.new(text) end text = '' state = :TEXT else text << char end else text << char end when :ERUBY case char when '>' if text[-1,1]=='%' #eRuby姜位 text = text[0..-2] @document << ERuby.new(text) text = '' state = :TEXT else text << char end else text << char end when :PHP case char when '>' if text[-1,1]=='?' #eRuby姜位 text = text[0..-2] @document << PHP.new(text) text = '' state = :TEXT else text << char end else text << char end when :DECLARE case char when '>' @document << Declaration.new(text) text = '' state = :TEXT else text << char if text=='--' text = '' state = :COMMENT end end end } #EOFの借妄 case state when :TEXT @document << CharacterData.new(text) if text.length>0 when :TAGNAME @document << CharacterData.new('<'+text) when :SPACE #掳拉粗の鄂球 name.downcase! if EMPTY.include?(name) @document << EmptyElementTag.new(name,attr) else if name[0,1]=='/' @document << EndTag.new(name[1..-1]) else @document << StartTag.new(name,attr) end end when :ATTRNAME #掳拉叹 attr[attrname.downcase]=true name.downcase! if EMPTY.include?(name) @document << EmptyElementTag.new(name,attr) else if name[0,1]=='/' @document << EndTag.new(name[1..-1]) else @document << StartTag.new(name,attr) end end when :BEFOREEQUAL #= attr[attrname.downcase]=true name.downcase! if EMPTY.include?(name) @document << EmptyElementTag.new(name,attr) else if name[0,1]=='/' @document << EndTag.new(name[1..-1]) else @document << StartTag.new(name,attr) end end when :AFTEREQUAL #= attr[attrname.downcase]=true name.downcase! if EMPTY.include?(name) @document << EmptyElementTag.new(name,attr) else if name[0,1]=='/' @document << EndTag.new(name[1..-1]) else @document << StartTag.new(name,attr) end end when :VALUE #猛 attr[attrname.downcase]=CGI::unescapeHTML(text) name.downcase! if EMPTY.include?(name) @document << EmptyElementTag.new(name,attr) else if name[0,1]=='/' @document << EndTag.new(name[1..-1]) else @document << StartTag.new(name,attr) end end when :SQVALUE #'猛' attr[attrname.downcase]=CGI::unescapeHTML(text) when :DQVALUE #"猛" attr[attrname.downcase]=CGI::unescapeHTML(text) when :COMMENT if text=~/^#[a-zA-Z]+/ #SSI @document << SSI.new(text) else @document << Comment.new(text) end when :ERUBY @document << ERuby.new(text) when :PHP @document << PHP.new(text) when :DECLARE @document << Declaration.new(text) end end # attr_accessor :document # def to_s s = '' @document.each {|e| s<<(e.to_s) } s end # def each tag = [] i = 0 @document.each {|e| case e when StartTag tag.push [e,i] when EndTag idx = nil (tag.size-1).downto(0) {|j| if tag[j][0].name==e.name idx = j break end } # if idx if idx==0 tag = [] else tag = tag[0..idx-1] end end else end yield e,tag i += 1 } end # def index(_class,_start=0,_end=-1,value=nil,count=1) idx=_start found=false @document[_start.._end].each {|obj| if obj.type==_class if value case obj when StartTag,EmptyElementTag,EndTag if value===obj.name if (not iterator?) or yield(obj) if (count-=1)<=0 found = true break end end end else if value===obj.text if (not iterator?) or yield(obj) if (count-=1)<=0 found = true break end end end end else if (not iterator?) or yield(obj) if (count-=1)<=0 found = true break end end end end idx+=1 } if found idx else nil end end # def end_index(start_index) tag = [] end_index = nil (start_index...@document.size).each {|idx| e= @document[idx] case e when StartTag tag.push [e,idx] when EndTag i = nil (tag.size-1).downto(0) {|j| if tag[j][0].name==e.name i = j break end } # if i if i==0 tag = [] else tag = tag[0..i-1] end end if tag.size==0 end_index = idx break end else end } end_index end end =begin End of Document </body> </html> =end