0

I am new to Scala coding. I have below code snippet which builds document using documentBuilder. My input is XML. Whenever I input an malformed XML below code is failing to parse and raising SAXException.

def parse_xml(xmlString: String)(implicit invocationTs: Date) : Either [None, Document] = {
 try {
   println(s"Parse xmlString invoked")
   val document = documentBuilder(false).parse(new InputSource(new StringReader(xmlString)))
   document.getDocumentElement.normalize()
   //Right(document)
   document
 } catch {
   case e: Exception => None

SAXException is raised because of the inbuilt implementation of parse function. Please see below code where SAXException is being handled:

public abstract Document parse(InputSource is)
    throws SAXException, IOException;

Now I am trying to bypass this SAXException as I don't want my job to failed just because of one malformed XML. So I have put try catch block handling below exception :

case e: Exception => None

But it's showing error here as "Expression of Type None. Type doesn't confirm to expect type Document" as my return type is document.

How can I get rid of this issue?

halfer
  • 19,824
  • 17
  • 99
  • 186
user2531569
  • 609
  • 4
  • 18
  • 36
  • 1
    Note that `Either[None, ...]` seems quite un-idiomatic. Why not just use `Option`? – Andrey Tyukin Apr 03 '19 at 17:22
  • 2
    A good solution is to return `Option[Document]` rather than `Either[None, Document]` and return `Some(document)` rather than just `document`. There are lots of good answers on this site that explain how to use `Option` effectively. If you want to preserve the exception you could return `Try[Document]`, replace the `try {` with `Try{` and remove the `catch` clause. – Tim Apr 03 '19 at 17:29
  • Thanks a lot. My issue solved now. – user2531569 Apr 03 '19 at 17:30

1 Answers1

3

If you want to use wrappers, like Either or Option you always have to wrap returned value.

In case you want to pass exception further, better choice than Either might be Try:

def parse_xml(xmlString: String)(implicit invocationTs: Date) : Try[Document] = {
    try {
      println(s"Parse xmlString invoked")
      val document = documentBuilder(false).parse(new InputSource(new StringReader(xmlString)))
      document.getDocumentElement.normalize()
      Success(document)
    } catch {
      case e: Exception => Failure(e)
    }
}

You could even simplify it by wrapping block inside Try.apply:

Try{
   println(s"Parse xmlString invoked")
   val document = documentBuilder(false).parse(new InputSource(new StringReader(xmlString)))
   document.getDocumentElement.normalize()
   document
}

If you don't care about exception, just about result, use Option:

def parse_xml(xmlString: String)(implicit invocationTs: Date) : Option[Document] = {
     try {
       println(s"Parse xmlString invoked")
       val document = documentBuilder(false).parse(new InputSource(new StringReader(xmlString)))
       document.getDocumentElement.normalize()
       Some(document)
     } catch {
       case e: Exception => None
     }
}
Krzysztof Atłasik
  • 21,985
  • 6
  • 54
  • 76