All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scala.xml.include.sax.XIncluder.scala Maven / Gradle / Ivy

The newest version!
/*
 * Scala (https://www.scala-lang.org)
 *
 * Copyright EPFL and Lightbend, Inc.
 *
 * Licensed under Apache License 2.0
 * (http://www.apache.org/licenses/LICENSE-2.0).
 *
 * See the NOTICE file distributed with this work for
 * additional information regarding copyright ownership.
 */

package scala
package xml
package include.sax

import org.xml.sax.{ ContentHandler, Locator, Attributes }
import org.xml.sax.ext.LexicalHandler
import java.io.{ OutputStream, OutputStreamWriter, IOException }

/**
 * XIncluder is a SAX `ContentHandler` that writes its XML document onto
 * an output stream after resolving all `xinclude:include` elements.
 *
 * Based on Eliotte Rusty Harold's SAXXIncluder.
 */
class XIncluder(outs: OutputStream, encoding: String) extends ContentHandler with LexicalHandler {

  var out: OutputStreamWriter = new OutputStreamWriter(outs, encoding)

  override def setDocumentLocator(locator: Locator): Unit = ()

  override def startDocument(): Unit = {
    try {
      out.write(s"\r\n")
    } catch {
      case e: IOException =>
        throw new SAXException("Write failed", e)
    }
  }

  override def endDocument(): Unit = {
    try {
      out.flush()
    } catch {
      case e: IOException =>
        throw new SAXException("Flush failed", e)
    }
  }

  override def startPrefixMapping(prefix: String, uri: String): Unit = ()

  override def endPrefixMapping(prefix: String): Unit = ()

  override def startElement(namespaceURI: String, localName: String, qualifiedName: String, atts: Attributes): Unit = {
    try {
      out.write(s"<$qualifiedName")
      var i: Int = 0
      while (i < atts.getLength) {
        val value: String = atts.getValue(i)
        // @todo Need to use character references if the encoding
        // can't support the character
        val valueStr: String = scala.xml.Utility.escape(value)
        out.write(s" ${atts.getQName(i)}='$valueStr'")
        i += 1
      }
      out.write(">")
    } catch {
      case e: IOException =>
        throw new SAXException("Write failed", e)
    }
  }

  override def endElement(namespaceURI: String, localName: String, qualifiedName: String): Unit = {
    try {
      out.write(s"")
    } catch {
      case e: IOException =>
        throw new SAXException("Write failed", e)
    }
  }

  // need to escape characters that are not in the given
  // encoding using character references????
  override def characters(ch: Array[Char], start: Int, length: Int): Unit = {
    try {
      var i: Int = 0
      while (i < length) {
        val c: Char = ch(start + i)
        if (c == '&') out.write("&")
        else if (c == '<') out.write("<")
        // This next fix is normally not necessary.
        // However, it is required if text contains ]]>
        // (The end CDATA section delimiter)
        else if (c == '>') out.write(">")
        else out.write(c.toInt)
        i += 1
      }
    } catch {
      case e: IOException =>
        throw new SAXException("Write failed", e)
    }
  }

  override def ignorableWhitespace(ch: Array[Char], start: Int, length: Int): Unit = {
    this.characters(ch, start, length)
  }

  // do I need to escape text in PI????
  override def processingInstruction(target: String, data: String): Unit = {
    try {
      out.write(s"")
    } catch {
      case e: IOException =>
        throw new SAXException("Write failed", e)
    }
  }

  override def skippedEntity(name: String): Unit = {
    try {
      out.write(s"&$name;")
    } catch {
      case e: IOException =>
        throw new SAXException("Write failed", e)
    }
  }

  // LexicalHandler methods
  private var inDTD: Boolean = false
  private var entities = List.empty[String]

  override def startDTD(name: String, publicID: String, systemID: String): Unit = {
    inDTD = true
    // if this is the source document, output a DOCTYPE declaration
    if (entities.isEmpty) {
      var id: String = ""
      if (publicID != null) id = s""" PUBLIC "$publicID" "$systemID""""
      else if (systemID != null) id = s""" SYSTEM "$systemID""""
      try {
        out.write(s"\r\n")
      } catch {
        case e: IOException =>
          throw new SAXException("Error while writing DOCTYPE", e)
      }
    }
  }
  override def endDTD(): Unit = ()

  override def startEntity(name: String): Unit = {
    entities = name :: entities
  }

  override def endEntity(name: String): Unit = {
    entities = entities.tail
  }

  override def startCDATA(): Unit = ()
  override def endCDATA(): Unit = ()

  // Just need this reference so we can ask if a comment is
  // inside an include element or not
  private var filter: XIncludeFilter = _

  def setFilter(filter: XIncludeFilter): Unit = {
    this.filter = filter
  }

  override def comment(ch: Array[Char], start: Int, length: Int): Unit = {
    if (!inDTD && !filter.insideIncludeElement) {
      try {
        out.write("")
      } catch {
        case e: IOException =>
          throw new SAXException("Write failed", e)
      }
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy