Scala+DBMS+Web スカラ座の夜

2011年8月31日

Web フレームワークを作る!! HTML Parserの差し替え

Filed under: Framework,Scala — admin @ 9:39 PM

HTMLパーサの差し替え

org.htmlparser.saxのバージョンは2.0をタグ拡張したバージョンにするため
以下のハンドラコードにを切り替える。

class Htmlparse5Spは、class Htmlparse4Spのハンドラを
生成しているところを、

val cb = new ParserCallback4 から val cb = new ParserCallback5 に書き換えればよい。

これで、オリジナルのHTMLファイルのScriptタグのなかにあるJavascriptのコードがなくならない。

このコードについて、このページを掲載してからいろいろとテストしたところ、
タグの再現性がないことを確認しました。

再現しない理由は、

  • HTML parserが解析しないタグが他にもあること。
  • タグの開始と終了が完全でないとエラーとなる。これは、ソースコードにあるstackでタグ関係をチェックしているために対が崩れるとエラーとしていることです。この場合このコードは不要です。

対応は、
HTML parserのオリジナルのコードにさらに定義されていないタグのクラス定義を追加し、
stackのタグ対チェックを外すことです。

これ以外にも、処理ロッジを変更しているので、新しいコードが完成次第リリースしますので、お試しください。

以下のコードはさらに差し替えになります。

package ews.servlet.sp
import java.util.HashMap
import org.xml.sax._
import org.xml.sax.helpers.DefaultHandler
import scala.collection.JavaConversions._
import scala.collection.mutable.Stack
import seedo._

class ParserCallback5(pMap:HashMap[String,Array[String]]) extends DefaultHandler {
	var buf = new StringBuffer
	val stack = new Stack[String]			// For indent inspection of tag
	val stackChange = new Stack[ExecTag]	// For substitution
	var locator:Locator = null

	override def toString :String = buf.toString
	override def setDocumentLocator (locator:Locator) :Unit=  {	this.locator = locator }
	override def startDocument ():Unit= {	System.out.println("Start document");}
	override def endDocument():Unit= {	System.out.println("End document");}
	override def startElement ( uri:String,  name:String, qualifiedName:String , attrs:Attributes ):Unit={
		var buflocal = new StringBuffer
		stack.push(name)
		buflocal.append("<"+name)
		var fullFag = false	//
		for (idx <- 0 to attrs.getLength - 1){
			val attributeType = attrs.getType(idx)
			val attrLocalName = attrs.getLocalName(idx)
		  	val attrName = attrs.getQName(idx)
			val attrValue = attrs.getValue(idx)
			if(attrLocalName.length > 0 && !"#text".equals(attrLocalName)){
				buflocal.append(" " + attrLocalName + "=\"" + attrValue + "\"")
				if("class".equals(attrName) && attrValue.startsWith("seedo:")){
					val execCommand = attrValue.split(":")	// Each element is separated.
					if(execCommand.length >= 3) {	// It doesn't substitute it if there are neither a class name nor a function name.
						stackChange.push(new ExecTag(
						stack.length
						,name
						,execCommand
						,new StringBuffer	// The tag to be substituted is maintained.
						))
						fullFag = true
					} else {
						println("$$$$$$$$$$ execClass Warning " + attrName + "='" + attrValue + "'")
					}
				}
			}
		}
		buflocal.append(">")
		if(!stackChange.isEmpty){
			stackChange.top.getBufChange.append(buflocal)
		} else {
			buf.append(buflocal)
		}
		if(fullFag == true){
			stackChange.top.setStartTagFull(buflocal.toString)
		}
	}
	override def endElement (uri:String ,  name:String, qualifiedName:String):Unit={
		val endTag = "</"+name+">"
		if(stack.top.equals(name)){	// It is the same as the tag that became a substitution beginning.
			if(!stackChange.isEmpty) {	// Tag to be substituted inside
			  if(stackChange.top.getStartTagDepth == stack.length && name.equals(stackChange.top.getStartTag) && !stackChange.isEmpty) {
				// Depth of the same stack as tag that became substitution beginning -> tag end
				stackChange.top.getBufChange.append(endTag)
				var changeTag:String = ""
				try{
					val execCommand = stackChange.top.getExecCommand
					var ec:ExecClass = new ExecClass(execCommand(1))		// Object is generated.
					if(ec != null){
						ec.exec("setTag",stackChange.top.getBufChange.toString)	// TAG before it substitutes it is set.
						ec.exec("setParameterMap",pMap)	// GetParameterMap method of ServletRequest to acquire parameter
						if(execCommand.length == 3){	// Argument none
							changeTag = ec.exec(execCommand(2)).toString
						}else if(execCommand.length == 4){	// There is one argument.
							val value = execCommand(3)
							changeTag = ec.execStr(execCommand(2),execCommand(3)).toString
						}
					}
				} catch {
					case e:NoSuchMethodException => {
						println("Exception "+e.getMessage + " NoSuchMethodException!")
					}
					case e:Exception => {
						println("Exception "+e.getMessage + " class or Method not find!")
					}
				}
				var str:String = null
				if(!stackChange.isEmpty){// Tag inside class="seedo"
					str = stackChange.top.getStartTagFull + changeTag + endTag
				}
				stackChange.pop	// The stack for substitution is liberated.
				if(!stackChange.isEmpty){// class="seedo"
					stackChange.top.getBufChange.append(str)
				} else {
					buf.append(str)	//
				}
			  } else {
				stackChange.top.getBufChange.append(endTag)
			  }
			} else {
				buf.append(endTag)
			}
			stack.pop
	//		println("-------------stack.length="+stack.length)
		} else {
			println("$$$$$$$$$$ The correspondence of tag is not taken. startTag(stack.top)=" + stack.top + " endTag=" + qualifiedName)
		}
	}
	override def characters(ch:Array[Char],start:Int,length:Int) : Unit = {
		var str:String = ""
		for(i <- start to length+start-1){
			str += ch(i)
		}
		if(!stackChange.isEmpty){// inside tag class="seedo"
			stackChange.top.getBufChange.append(str)
		} else {
			buf.append(str)
		}
	}
}

package がすべてewsだったので、機能ごとに階層を分ける。
servletから呼び出されるクラスは、package ews.servlet.spに置く。

class htmlSrvは、package ews.servletに置く。

packageの変更により、web.xmlの定義は以下のように修正。

HTMLファイルを置く場所も、テスト用にC:\test_site\htmlに変更する。
この設定を変更すればいろいろなサイトのコンテンツを評価することができます。

またews.servlet.htmlSrvを拡張してファイル転送できるようにしたので、イメージファイルやCSSファイル、JSファイルもこのディレクトリに置くことができます。

web.xml

	<servlet>
		<servlet-name>html</servlet-name>
		<servlet-class>ews.servlet.htmlSrv</servlet-class>
		<init-param>
			<param-name>html</param-name>
			<param-value>C:\test_site\html</param-value>
		</init-param>

		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>html</servlet-name>
		<url-pattern>/html/*</url-pattern>
	</servlet-mapping>

コードが落ち着いてきたらソースコード一式をダウンロードできるようにします。

Comments

comments

Powered by Facebook Comments

コメントはまだありません »

No comments yet.

RSS feed for comments on this post. TrackBack URL

Leave a comment

コメントを投稿するにはログインしてください。

Powered by WordPress