Richard Searle's Blog

Thoughts about software

Converting Scala XML into SAX events

Posted by eggsearle on September 2, 2010

This object generates SAX events from Scala XML to the provided ContentHandler.
If the target also implements LexicalHandler then comments are included.

import scala.xml._
import org.xml.sax.ext.LexicalHandler
import org.xml.sax._
import org.xml.sax.helpers._

import scala.xml.Utility._

object XMLDumper{

   def toXML(
    x: Node,
    target: ContentHandler,
    pscope: NamespaceBinding = TopScope)
    val lexical = if(target.isInstanceOf[LexicalHandler]) target.asInstanceOf[LexicalHandler] else null


    x match {
      case c: Comment => if (lexical != null) lexical.comment(c.commentText.toCharArray,0,c.commentText.length)
      case a: Atom[_] =>  { val s = a text; target.characters(s.toCharArray,0,s.length) } 
      case e: EntityRef =>  { val s = e text; target.characters(s.toCharArray,0,s.length) } 
      case  p:ProcInstr => target.processingInstruction(,p.proctext)
      case g: Group =>
        g.nodes foreach {toXML(_, target, x.scope)}
      case _  =>
        val uri = x.namespace
        val localName = x.label
        val qName = if(x.prefix == null) localName else x.prefix + ":" + localName

        val atts = new AttributesImpl() 
        if(x.attributes != null) toXML(x.attributes,atts)
          x.child foreach {toXML(_, target, x.scope)}

  private def startPrefix(ns:NamespaceBinding,stop:NamespaceBinding,target:ContentHandler){
     if(ns ne stop){
        target.startPrefixMapping(if(ns.prefix==null) "" else ns.prefix,ns.uri);
         startPrefix(ns.parent, stop,target)

  private def endPrefix(ns:NamespaceBinding,stop:NamespaceBinding,target:ContentHandler){
     if(ns ne stop){
       target.endPrefixMapping(if(ns.prefix==null) "" else ns.prefix);
       endPrefix(ns.parent, stop,target)

  private def toXML(att:MetaData,atts:AttributesImpl){
     att match  {
        case pa:PrefixedAttribute =>  atts.addAttribute(null,pa.key,pa.pre+":"+pa.key,"CDATA",toString(pa.value))
        case ua:UnprefixedAttribute =>  atts.addAttribute(null,ua.key,ua.key,"CDATA",toString(ua.value))
        case Null =>  //ignored
     if(att hasNext)

  private def toString(ns:Seq[Node]) = {
     val sb = new StringBuilder
     ns foreach {_ match { 
          case a: Atom[_] => sb.append(a.text)
          case e:EntityRef => sb.append(e.text)


With example usage

import javax.xml.parsers._
import javax.xml.transform._
import javax.xml.transform.sax._

object XMLDumperDriver extends Application{

val transformerFactory = (TransformerFactory.newInstance).asInstanceOf[SAXTransformerFactory]
val xformer = transformerFactory.newTransformerHandler
xformer.setResult(new StreamResult(System.out))

  val xml = <Outside> <Y xmlns="http://y"/> <X a="12" c="21" xmlns:h="" xmlns:q="http://q"  >xxx &lt; <y xmlns:g=""  h:b="13"/> </X> </Outside>


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s

%d bloggers like this: