StAX(Streaming API for XML)
「Scala には XML に対するファーストクラスのサポートが最初から組み込まれているため、XML ストリングの作成や、プログラムによる DOM ツリーの作成が必要ありません。」
と説明されているのですが、XhtmlParserだとDOMよりもメモリーを使っているのではないと思う次第です。いまどきメモリーを気にすることもないかもしれませんが、でも気になります。
データ交換にXMLを使うことが多いのでDOMよりもSAXが好みです。
Javaのときに使いなれたStAXコードをScalaに移植してみました。
このコードは、XMLを調べて構文をイベントで処理します。
scala.xml.pull.XMLEventReader を使った処理も書いてみました。
StAXコードと同じプル型。コードはすっきりしています。
package Hello import java.io.{BufferedInputStream,BufferedReader,ByteArrayInputStream,FileInputStream,IOException} import java.io.InputStreamReader import java.util.{Iterator,Stack} import org.xml.sax.InputSource import org.xml.sax.helpers.DefaultHandler import org.xml.sax.Attributes import javax.xml.parsers.SAXParser import javax.xml.parsers.SAXParserFactory import javax.xml.namespace.QName import javax.xml.stream.{XMLEventReader,XMLInputFactory,XMLStreamException,XMLStreamReader,XMLStreamConstants} import javax.xml.stream.events.{Attribute,Characters,EndElement,StartElement,XMLEvent} import scala.collection.mutable.ArrayBuffer import scala.collection.JavaConversions._ import scala.xml._ import scala.xml.pull._ import scala.io.Source import scala.collection.mutable.Stack object Xmlcheck { def XmlCheck(xml:NodeSeq) :Boolean = { XmlStringCheck(xml.toString) } def XmlStringCheck(xmlString:String) :Boolean = { if(xmlString == null) return false var bt:Array[Byte] = xmlString.getBytes("UTF-8") val in = new ByteArrayInputStream(bt) val factory:XMLInputFactory = XMLInputFactory.newInstance val reader:XMLStreamReader = factory.createXMLStreamReader(in, "UTF-8") while(true) { var eventType = reader.getEventType if(eventType == XMLStreamConstants.ATTRIBUTE){ println("eventType: ATTRIBUTE") }else if(eventType == XMLStreamConstants.CDATA){ println("eventType: CDATA") }else if(eventType == XMLStreamConstants.CHARACTERS){ println("eventType: CHARACTERS: "+reader.getText.trim) }else if (eventType == XMLStreamConstants.COMMENT){ println("eventType: COMMENT") }else if (eventType == XMLStreamConstants.DTD){ println("eventType: DTD") }else if (eventType == XMLStreamConstants.END_DOCUMENT){ println("eventType: END_DOCUMENT") }else if (eventType == XMLStreamConstants.END_ELEMENT){ println("eventType: END_ELEMENT: "+reader.getName) }else if(eventType == XMLStreamConstants.ENTITY_DECLARATION){ println("eventType: END_ELEMENT") }else if(eventType == XMLStreamConstants.ENTITY_REFERENCE){ println("eventType: ENTITY_REFERENCE") }else if(eventType == XMLStreamConstants.NAMESPACE){ println("eventType: NAMESPACE") }else if(eventType == XMLStreamConstants.NOTATION_DECLARATION){ println("eventType: NOTATION_DECLARATION") }else if(eventType == XMLStreamConstants.PROCESSING_INSTRUCTION){ println("eventType: PROCESSING_INSTRUCTION") }else if(eventType == XMLStreamConstants.SPACE){ println("eventType: SPACE") }else if(eventType == XMLStreamConstants.START_DOCUMENT){ println("eventType: START_DOCUMENT") }else if(eventType == XMLStreamConstants.START_ELEMENT){ println("eventType: START_ELEMENT: "+reader.getName) }else { println("eventType: Other: "+eventType) } if(reader.hasNext) { reader.next } else { reader.close in.close return true } } false } def XmlStringCheck2(xml:String) :Boolean = { val src = Source.fromString(xml) val er = new scala.xml.pull.XMLEventReader(src) val stack = scala.collection.mutable.Stack[scala.xml.pull.XMLEvent]() def iprintln(s:String) = println((" " * stack.size) + s.trim) while (er.hasNext) { er.next match { case x @ EvElemStart(_, label, _, _) => stack push x iprintln("EvElemStart <" + label + " ...>") case EvElemEnd(_, label) => iprintln("EvElemEnd </" + label + ">") stack pop; case EvText(text) => iprintln(text) case EvEntityRef(entity) => iprintln(entity) case _ => // ignore everything else } } true } def main(args : Array[String]) : Unit = { println("result=" + XmlCheck(<HTML><BODY>abcd12345</BODY></HTML>)) println("result=" + XmlStringCheck("<H><B>abcd12345</B></H>")) println("result=" + XmlStringCheck2("<HX><BC>abcd12345</BC></HX>")) } }
実行した結果です。
eventType: START_DOCUMENT eventType: START_ELEMENT: HTML eventType: START_ELEMENT: BODY eventType: CHARACTERS: abcd12345 eventType: END_ELEMENT: BODY eventType: END_ELEMENT: HTML eventType: END_DOCUMENT result=true eventType: START_DOCUMENT eventType: START_ELEMENT: H eventType: START_ELEMENT: B eventType: CHARACTERS: abcd12345 eventType: END_ELEMENT: B eventType: END_ELEMENT: H eventType: END_DOCUMENT result=true EvElemStart <HX ...> EvElemStart <BC ...> abcd12345 EvElemEnd </BC> EvElemEnd </HX> result=true
コメントを残す
コメントを投稿するにはログインしてください。