2014-11-05 77 views
1

我需要通过xsd验证xml文件,并在可能的情况下解析xml。我有下面的例子:Scala XML验证XSD和解析

import java.io.FileInputStream 
import javax.xml.XMLConstants 
import javax.xml.parsers.SAXParserFactory 
import javax.xml.transform.stream.StreamSource 
import javax.xml.validation.SchemaFactory 

import org.xml.sax.SAXParseException 
import org.xml.sax.helpers.DefaultHandler 

import scala.util.Try 
import scala.xml.XML 

object XMLTup extends App { 
    val schema = { 
    val factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI) 
    val xsdStream = new FileInputStream("xsd.xsd") 
    val schema = factory.newSchema(new StreamSource(xsdStream)) 
    xsdStream.close() 
    schema 
    } 

    val saxParser = { 
    val f = SAXParserFactory.newInstance() 
    f.setNamespaceAware(true) 
    f.setSchema(schema) 
    f.newSAXParser() 
    } 

    //DOESN'T WORK 
    val xml1 = new FileInputStream("xml.xml") 
    println { 
    Try{XML.withSAXParser(saxParser).load(xml1)} 
    } 
    xml1.close() 

    //WORKS 
    val xml2 = new FileInputStream("xml.xml") 
    val handler = new DefaultHandler() { 
    override def error(ex: SAXParseException) { 
     println("Validation Error!") 
    } 
    } 
    saxParser.parse(xml2, handler) 
    xml2.close() 
} 

当我使用XML阶(不工作),我得到了成功,并没有验证错误,但接下来的代码(工程)我得到了“验证错误”信息。为什么会发生?我如何使用Scala XML类通过XSD验证XML?

回答

1

令人惊讶的是,它发现scala XML使用NoBindingFactoryAdapter,它继承了FactoryAdapter继承了DefaultHandler。 DefaultHandler有下一个方法:

public void error (SAXParseException e) 
    throws SAXException 
{ 
    // no op 
} 

您需要重写此方法来处理xml验证的错误消息。一种方法是创建自己的Scala特性XMLLoader对象,并根据需要重写适配器和解析器:

//NOW, IT WORKS 
    val xml1 = new FileInputStream("xml.xml") 
    println { 
    Try{ 
     val loader = new XMLLoader[Elem] { 
     override def adapter: FactoryAdapter = new NoBindingFactoryAdapter() { 
      override def error(e: SAXParseException) = { 
      throw e 
      } 
     } 

     override def parser: SAXParser = saxParser 
     } 
     loader.load(xml1) 
    } 
    } 
    xml1.close() 
2

我用sbt使用scalaxb(我的xsd文件位于子项目genscalaxb)。

添加到项目/ plugin.sbt:

resolvers += Resolver.sonatypeRepo("public") 

addSbtPlugin("org.scalaxb" % "sbt-scalaxb" % "1.2.1") 

添加到您的build.sbt(地图是可选的 - 定制包):

lazy val `genscalaxb` = Project("genscalaxb", file("genscalaxb")).settings(scalaxbSettings: _*).settings(
    packageNames in scalaxb in Compile := Map(new URI("https://github.com/ajozwik/mvn2sbt") -> "pl.jozwik.gen", 
    new URI("http://maven.apache.org/POM/4.0.0") -> "org.maven"), 
    sourceGenerators in Compile <+= scalaxb in Compile 
) 

把你的XSD文件:genscalaxb/src/main/xsd

我用在功能,see in github

private def handlePomFile(pomXml: File, parent: Option[MavenDependency]) = { 
    val xmlFromFile = Try(xml.XML.loadFile(pomXml)) match { 
     case Success(pom) => pom 
     case Failure(th) => 
     logger.error(s"${pomXml.getAbsolutePath} failed to be parse") 
     throw th 
    } 
    val pomModel = scalaxb.fromXML[org.maven.Model](xmlFromFile) 
    createProjectMap(pomXml.getParentFile, pomModel, parent) 
    } 

xsd文件是maven-4.0.0.xsd

xml文件 - 是poms。