I've written a trivial scala program to open an XML file.
Is there a way to get scala to validate the XML file against the schema file that it references? Currently my XML file doesn't follow the schema, so I'd expect to get errors on validation.
The XML file references the schema like this in the root element:
<items xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="items.xsd">
The scala code:
import scala.xml._
object HelloWorld {
def main(args: Array[Stri开发者_如何转开发ng]) {
println("Hello, world! " + args.toList)
val start = System.currentTimeMillis
val data = XML.loadFile(args(0))
val stop = System.currentTimeMillis
Console.println("Took " + (stop-start)/1000.0 + "s to load " + args(0))
}
}
HelloWorld.main(args)
Here is a blog post describing how to use the Java libraries for schema validation in Scala:
http://sean8223.blogspot.com/2009/09/xsd-validation-in-scala.html
It boils down to a basic re-implementation of XML.load
:
import javax.xml.parsers.SAXParser
import javax.xml.parsers.SAXParserFactory
import javax.xml.validation.Schema
import javax.xml.validation.ValidatorHandler
import org.xml.sax.XMLReader
class SchemaAwareFactoryAdapter(schema:Schema) extends NoBindingFactoryAdapter {
override def loadXML(source: InputSource): Elem = {
// create parser
val parser: SAXParser = try {
val f = SAXParserFactory.newInstance()
f.setNamespaceAware(true)
f.setFeature("http://xml.org/sax/features/namespace-prefixes", true)
f.newSAXParser()
} catch {
case e: Exception =>
Console.err.println("error: Unable to instantiate parser")
throw e
}
val xr = parser.getXMLReader()
val vh = schema.newValidatorHandler()
vh.setContentHandler(this)
xr.setContentHandler(vh)
// parse file
scopeStack.push(TopScope)
xr.parse(source)
scopeStack.pop
return rootElem.asInstanceOf[Elem]
}
}
I don't think you can do it yet with Scala libraries. But you can definitely use Java libraries. Just google "java schema validation" and you'll find a lot of options
Here is an adaptation to minor API changes in 2.8.0 (or 2.8.1):
import org.xml.sax.InputSource
import scala.xml.parsing.NoBindingFactoryAdapter
import scala.xml.{TopScope, Elem}
import javax.xml.parsers.{SAXParserFactory, SAXParser}
import javax.xml.validation.Schema
class SchemaAwareFactoryAdapter(schema: Schema) extends NoBindingFactoryAdapter {
override def loadXML(source: InputSource, parser: SAXParser) = {
val reader = parser.getXMLReader()
val handler = schema.newValidatorHandler()
handler.setContentHandler(this)
reader.setContentHandler(handler)
scopeStack.push(TopScope)
reader.parse(source)
scopeStack.pop
rootElem.asInstanceOf[Elem]
}
override def parser: SAXParser = {
val factory = SAXParserFactory.newInstance()
factory.setNamespaceAware(true)
factory.setFeature("http://xml.org/sax/features/namespace-prefixes", true)
factory.newSAXParser()
}
}
The application is also slightly different:
val factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI)
val xsdStream = getClass.getResourceAsStream("/foo.xsd")
val schema = factory.newSchema(new StreamSource(stream))
val source = getClass.getResourceAsStream("baz.xml")
val xml = new SchemaAwareFactoryAdapter(schema).load(source)
精彩评论