package scala.xml
package include.sax
import scala.xml.include._
import collection.mutable.Stack
import org.xml.sax.{ ContentHandler, XMLReader, Locator, Attributes }
import org.xml.sax.ext.LexicalHandler
import java.io.{ File, OutputStream, OutputStreamWriter, Writer, IOException }
class XIncluder(outs: OutputStream, encoding: String) extends ContentHandler with LexicalHandler {
var out = new OutputStreamWriter(outs, encoding)
def setDocumentLocator(locator: Locator) {}
def startDocument() {
try {
out.write("<?xml version='1.0' encoding='"
+ encoding + "'?>\r\n");
}
catch {
case e:IOException =>
throw new SAXException("Write failed", e)
}
}
def endDocument() {
try {
out.flush()
}
catch {
case e:IOException =>
throw new SAXException("Flush failed", e)
}
}
def startPrefixMapping(prefix: String , uri: String) {}
def endPrefixMapping(prefix: String) {}
def startElement(namespaceURI: String, localName: String, qualifiedName: String, atts: Attributes) = {
try {
out.write("<" + qualifiedName);
var i = 0; while (i < atts.getLength()) {
out.write(" ");
out.write(atts.getQName(i));
out.write("='");
val value = atts.getValue(i);
out.write(xml.Utility.escape(value))
out.write("'");
i += 1
}
out.write(">")
}
catch {
case e:IOException =>
throw new SAXException("Write failed", e)
}
}
def endElement(namespaceURI: String, localName:String, qualifiedName: String) {
try {
out.write("</" + qualifiedName + ">")
}
catch {
case e: IOException =>
throw new SAXException("Write failed", e)
}
}
def characters(ch: Array[Char], start: Int, length: Int) {
try {
var i = 0; while (i < length) {
val c = ch(start+i);
if (c == '&') out.write("&");
else if (c == '<') out.write("<");
else if (c == '>') out.write(">");
else out.write(c);
i = i+1;
}
}
catch {
case e: IOException =>
throw new SAXException("Write failed", e);
}
}
def ignorableWhitespace(ch: Array[Char], start: Int , length: Int) {
this.characters(ch, start, length)
}
def processingInstruction(target: String, data: String) {
try {
out.write("<?" + target + " " + data + "?>")
}
catch {
case e:IOException =>
throw new SAXException("Write failed", e)
}
}
def skippedEntity(name: String) {
try {
out.write("&" + name + ";")
}
catch {
case e:IOException =>
throw new SAXException("Write failed", e)
}
}
private var inDTD: Boolean = false
private val entities = new Stack[String]()
def startDTD(name: String, publicID: String, systemID: String) {
inDTD = true
if (entities.isEmpty) {
var id = ""
if (publicID != null) id = " PUBLIC \"" + publicID + "\" \"" + systemID + '"';
else if (systemID != null) id = " SYSTEM \"" + systemID + '"';
try {
out.write("<!DOCTYPE " + name + id + ">\r\n")
}
catch {
case e:IOException =>
throw new SAXException("Error while writing DOCTYPE", e)
}
}
}
def endDTD() {}
def startEntity(name: String) {
entities push name
}
def endEntity(name: String) {
entities.pop()
}
def startCDATA() {}
def endCDATA() {}
private var filter: XIncludeFilter = null
def setFilter(filter: XIncludeFilter) {
this.filter = filter
}
def comment(ch: Array[Char], start: Int, length: Int) {
if (!inDTD && !filter.insideIncludeElement()) {
try {
out.write("<!--")
out.write(ch, start, length)
out.write("-->")
}
catch {
case e: IOException =>
throw new SAXException("Write failed", e)
}
}
}
}