How to convert Scala Scales XML to DOM/SAX
Asked Answered
T

1

1

I am trying to transform scales-xml documents into DOM documents or SAX objects based on the example code here: http://scala-scales.googlecode.com/svn/sites/scales/scales-xml_2.9.2/0.4.4/XSLT.html

The source only and roundtrip examples work fine, but the scales=>DOM code I wrote returns an empty document, and the scales=>SAX code raises the following exception:

ERROR:  'org.xml.sax.SAXException: setResult() must be called prior to startDocument().'

Is what I am trying to do supported? If so, what did I get wrong?

My sample code and full error trace is given below.

Thanks for your help.

CODE

// scales XML parsing
import scales.xml._
import ScalesXml._

object ScalesTransformTest {

  def main(args:Array[String]) {
    val elem = Elem("trax"l)
    val doc = Doc(elem / elem)
    println( s"scales doc:\n${asString(doc)}" )

    import javax.xml.transform._
    import org.w3c.dom.Document
    val tf = TransformerFactory.newInstance
    val trax = tf.newTransformer

    val wr = new java.io.StringWriter
    val str = new stream.StreamResult(wr)
    trax.transform(doc, str)
    println( s"\nsource only:\n${wr.toString}" )

    val sr = ScalesResult()
    trax.transform(doc, sr)
    println( s"\nroundtrip:\n${asString(sr.doc)}" )

    val dr = new dom.DOMResult
    trax.transform(doc, dr)
    val ddoc = dr.getNode.asInstanceOf[Document]
    println( s"\nscales=>DOM:\n$ddoc" )

    val stf = tf.asInstanceOf[sax.SAXTransformerFactory]
    val th = stf.newTransformerHandler
    val strax = th.getTransformer

    val xr = new sax.SAXResult(th)
    strax.transform(doc, xr)
    println( s"\nscales=>SAX:\n$xr" )
  }

}

ERRORS

Picked up JAVA_TOOL_OPTIONS:  -Dfile.encoding=UTF-8 -Xmx4G -XX:MaxPermSize=1G -XX:+CMSClassUnloadingEnabled
[info] [Loading project definition from /Users/eric/git/scala/dgrep/project
[info] [Set current project to DGrep (in build file:/Users/eric/git/scala/dgrep/)
[info] Running ScalesTransformTest 
scales doc:
<?xml version="1.0" encoding="UTF-8"?><trax><trax/></trax>

source only:
<?xml version="1.0" encoding="UTF-8"?><trax><trax/></trax>

roundtrip:
<?xml version="1.0" encoding="UTF-16"?><trax><trax/></trax>

scales=>DOM:
[#document: null]
ERROR:  'org.xml.sax.SAXException: setResult() must be called prior to startDocument().'
[error] (run-main) javax.xml.transform.TransformerException: javax.xml.stream.XMLStreamException: org.xml.sax.SAXException: setResult() must be called prior to startDocument().
javax.xml.transform.TransformerException: javax.xml.stream.XMLStreamException: org.xml.sax.SAXException: setResult() must be called prior to startDocument().
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:739)
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:340)
    at ScalesTransformTest$.main(ScalesTransformTest.scala:36)
    at ScalesTransformTest.main(ScalesTransformTest.scala)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at sbt.Run.invokeMain(Run.scala:72)
    at sbt.Run.run0(Run.scala:65)
    at sbt.Run.sbt$Run$$execute$1(Run.scala:54)
    at sbt.Run$$anonfun$run$1.apply$mcV$sp(Run.scala:58)
    at sbt.TrapExit$.sbt$TrapExit$$executeMain$1(TrapExit.scala:33)
    at sbt.TrapExit$$anon$1.run(TrapExit.scala:42)
Caused by: javax.xml.stream.XMLStreamException: org.xml.sax.SAXException: setResult() must be called prior to startDocument().
    at com.sun.org.apache.xalan.internal.xsltc.trax.StAXStream2SAX.bridge(StAXStream2SAX.java:210)
    at com.sun.org.apache.xalan.internal.xsltc.trax.StAXStream2SAX.parse(StAXStream2SAX.java:118)
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transformIdentity(TransformerImpl.java:678)
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:727)
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:340)
    at ScalesTransformTest$.main(ScalesTransformTest.scala:36)
    at ScalesTransformTest.main(ScalesTransformTest.scala)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at sbt.Run.invokeMain(Run.scala:72)
    at sbt.Run.run0(Run.scala:65)
    at sbt.Run.sbt$Run$$execute$1(Run.scala:54)
    at sbt.Run$$anonfun$run$1.apply$mcV$sp(Run.scala:58)
    at sbt.TrapExit$.sbt$TrapExit$$executeMain$1(TrapExit.scala:33)
    at sbt.TrapExit$$anon$1.run(TrapExit.scala:42)
Caused by: org.xml.sax.SAXException: setResult() must be called prior to startDocument().
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerHandlerImpl.startDocument(TransformerHandlerImpl.java:183)
    at com.sun.org.apache.xml.internal.serializer.ToSAXHandler.startDocumentInternal(ToSAXHandler.java:99)
    at com.sun.org.apache.xml.internal.serializer.SerializerBase.startDocument(SerializerBase.java:1235)
    at com.sun.org.apache.xalan.internal.xsltc.trax.StAXStream2SAX.handleStartDocument(StAXStream2SAX.java:239)
    at com.sun.org.apache.xalan.internal.xsltc.trax.StAXStream2SAX.bridge(StAXStream2SAX.java:153)
    at com.sun.org.apache.xalan.internal.xsltc.trax.StAXStream2SAX.parse(StAXStream2SAX.java:118)
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transformIdentity(TransformerImpl.java:678)
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:727)
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerImpl.transform(TransformerImpl.java:340)
    at ScalesTransformTest$.main(ScalesTransformTest.scala:36)
    at ScalesTransformTest.main(ScalesTransformTest.scala)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at sbt.Run.invokeMain(Run.scala:72)
    at sbt.Run.run0(Run.scala:65)
    at sbt.Run.sbt$Run$$execute$1(Run.scala:54)
    at sbt.Run$$anonfun$run$1.apply$mcV$sp(Run.scala:58)
    at sbt.TrapExit$.sbt$TrapExit$$executeMain$1(TrapExit.scala:33)
    at sbt.TrapExit$$anon$1.run(TrapExit.scala:42)
[debug]     Thread run-main exited.
[debug] Interrupting remaining threads (should be all daemons).
[debug] Sandboxed run complete..
java.lang.RuntimeException: Nonzero exit code: 1
    at scala.sys.package$.error(package.scala:27)
    at sbt.BuildCommon$$anonfun$toError$1.apply(Defaults.scala:1628)
    at sbt.BuildCommon$$anonfun$toError$1.apply(Defaults.scala:1628)
    at scala.Option.foreach(Option.scala:236)
    at sbt.BuildCommon$class.toError(Defaults.scala:1628)
    at sbt.Defaults$.toError(Defaults.scala:34)
    at sbt.Defaults$$anonfun$runMainTask$1$$anonfun$apply$34$$anonfun$apply$35.apply(Defaults.scala:637)
    at sbt.Defaults$$anonfun$runMainTask$1$$anonfun$apply$34$$anonfun$apply$35.apply(Defaults.scala:633)
    at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
    at sbt.$tilde$greater$$anonfun$$u2219$1.apply(TypeFunctions.scala:42)
    at sbt.std.Transform$$anon$4.work(System.scala:64)
    at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
    at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
    at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:18)
    at sbt.Execute.work(Execute.scala:244)
    at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
    at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
    at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:160)
    at sbt.CompletionService$$anon$2.call(CompletionService.scala:30)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
    at java.util.concurrent.FutureTask.run(FutureTask.java:166)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
    at java.util.concurrent.FutureTask.run(FutureTask.java:166)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:722)
[error] (compile:runMain) Nonzero exit code: 1
Tamarau answered 27/9, 2013 at 6:45 Comment(0)
B
2

The problem is that you need to provide a stylesheet when doing dom and sax transformations:

// scales XML parsing
import scales.xml._
import ScalesXml._
//import scales.xml.trax._ // needed for the latest scales version

object ScalesTransformTest {

  def run() {
    val elem = Elem("trax"l)
    val doc = Doc(elem / elem)
    println( s"scales doc:\n${asString(doc)}" )

    import javax.xml.transform._
    import org.w3c.dom.Document

    val matchall = 
      """<?xml version="1.0"?>
         <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
       <xsl:output encoding="UTF-8" />
       <xsl:template match="*">
         <xsl:copy-of select="." />
       </xsl:template>
     </xsl:stylesheet>"""

val tf = TransformerFactory.newInstance
val trax = tf.newTransformer(new stream.StreamSource(new java.io.StringReader(matchall)))

val wr = new java.io.StringWriter
val str = new stream.StreamResult(wr)
trax.transform(doc, str)
println( s"\nsource only:\n${wr.toString}" )

val sr = ScalesResult()
trax.transform(doc, sr)
println( s"\nroundtrip:\n${asString(sr.doc)}" )

val dr = new dom.DOMResult 
trax.transform(doc, dr)
val ddoc = dr.getNode.asInstanceOf[Document]
println( s"\nscales=>DOM:\n$ddoc" )

val sr2 = ScalesResult()
trax.transform(new dom.DOMSource(ddoc), sr2)
println( s"\nback from dom:\n${asString(sr2.doc)}" )

val stf = tf.asInstanceOf[sax.SAXTransformerFactory]
val th = stf.newTransformerHandler(new stream.StreamSource(new java.io.StringReader(matchall)))

val wr2 = new java.io.StringWriter
val str2 = new stream.StreamResult(wr2)
th.setResult(str2)

val strax = th.getTransformer

val xr = new sax.SAXResult(th)
strax.transform(doc, xr)
println( s"\nscales=>SAX:\n${wr2.toString}" )

  }

}
Bosanquet answered 30/9, 2013 at 19:29 Comment(3)
Thanks for the answer, @Chris! For some reason, I was under the impression that trax used the identify transform by default. Now everything works fine.Tamarau
It should, indeed this works: val ddoc2 = scales.xml.impl.DefaultStaxInputFactoryPool.loan { fact => val in = new stax.StAXSource(fact.createXMLStreamReader(new java.io.StringReader(wr.toString))) val dr2 = new dom.DOMResult tf.newTransformer().transform(in, dr2) dr2.getNode.asInstanceOf[Document] } println( s"\nstr=>DOM:\n$ddoc2" ) so there is something not right here, but I've been hit by assumptions within the jaxp code before that aren't documented. Kinda interested, I'll create an issue to track it.Bosanquet
Thanks. I hadn't looked into using a StAXSource, so I didn't notice that it works without specifying a transform. Let me know if you find the cause of this bug.Tamarau

© 2022 - 2024 — McMap. All rights reserved.