12

so right now when I validate the XML file using an XML schema, I am only able to know whether it fail or pass, and if I want to know why it fail, I need to look at the error message like

[org.xml.sax.SAXParseException: cvc-complex-type.2.4.a: Invalid content was found starting with element 'City'. One of '{Address1}' is expected.]

In the above example, it fail because I am missing tag Address1. My question is When the validation fail, can I know which tag causing the failure? This is because I need to handle these failure differently for each important missing-tag. Right now my thought is

FileInputStream inputStream = null;
try{
    SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
    Schema schema = sf.newSchema(new File(config.getXmlSchema()));
    JAXBContext context = JAXBContext.newInstance(PackageLabel.class);
    Unmarshaller unmarshaller = context.createUnmarshaller();
    unmarshaller.setSchema(schema);
    inputStream = new FileInputStream(xmlFile);
    pl = (PackageLabel) unmarshaller.unmarshal(inputStream);
} catch (JAXBException e) {
    if(pl.getAddress1() == null){
         System.out.println("Invalid Mailing Address");
    }
    //EDIT: CANNOT DO THIS, SINCE pl  IS NULL AT THIS POINT
    //Some more logics on how to handle important missing-tags
    ...
}finally{
    if(inputStream != null) inputStream.close();
}  

However, I do not think writing logic inside catch clause is correct. Any advice?

EDIT

I followed Balaise idea, and below is the event I received when the XML missing an Address1

EVENT
SEVERITY:  2
MESSAGE:  cvc-complex-type.2.4.a: Invalid content was found starting with element 'City'. One of '{Address1}' is expected.
LINKED EXCEPTION:  org.xml.sax.SAXParseException: cvc-complex-type.2.4.a: Invalid content was found starting with element 'City'. One of '{Address1}' is expected.
LOCATOR
 LINE NUMBER:  4
 COLUMN NUMBER:  11
 OFFSET:  -1
 OBJECT:  null
 NODE:  null
 URL:  null

However, both NODE and OBJECT are null, I cannot further investigate on what causing the exception unless I parse the exception which is what I asked originally.

Thang Pham
  • 38,125
  • 75
  • 201
  • 285
  • @CodeBrickie: Thank you for your input. That was my original thought as well, however, i just want to make sure. I just want to make sure if JAXB have a different way to handle this or not – Thang Pham Dec 12 '11 at 15:14
  • 1
    You say that *I need to handle these failure differently for each important missing-tag*. So basically, your XML is invalid, because there are *expected* tags missing? Don't you have a separate schema for each scenario? In that case you could validate the input against all of them: if one passes, you're OK. This solution is rubbish: just as rubbish as *validating* an XML against a schema, when you *expect* the XML to be invalid. Sorry. It's just pointless. If the XML only missing some tags, but it's valid otherwise: don't validate it against a schema and *search* for particular defects. – Kohányi Róbert Dec 21 '11 at 20:29

3 Answers3

7

You can leverage JAXB's ValidationEventHandler for this. An implementation can then be set on instances of Marshaller and Unmarshaller:

package blog.jaxb.validation;

import javax.xml.bind.ValidationEvent;
import javax.xml.bind.ValidationEventHandler;

public class MyValidationEventHandler implements ValidationEventHandler {

    public boolean handleEvent(ValidationEvent event) {
        System.out.println("\nEVENT");
        System.out.println("SEVERITY:  " + event.getSeverity());
        System.out.println("MESSAGE:  " + event.getMessage());
        System.out.println("LINKED EXCEPTION:  " + event.getLinkedException());
        System.out.println("LOCATOR");
        System.out.println("    LINE NUMBER:  " + event.getLocator().getLineNumber());
        System.out.println("    COLUMN NUMBER:  " + event.getLocator().getColumnNumber());
        System.out.println("    OFFSET:  " + event.getLocator().getOffset());
        System.out.println("    OBJECT:  " + event.getLocator().getObject());
        System.out.println("    NODE:  " + event.getLocator().getNode());
        System.out.println("    URL:  " + event.getLocator().getURL());
        return true;
    }

}

For More Information

bdoughan
  • 147,609
  • 23
  • 300
  • 400
  • Hi Blaise, I am very sorry for taking so long to reply you back, I was swarm with other issues. I tried what you showed on your first link, however, I do see how I can investigate further. I only see the exception message back, but that still mean that I have to parse the the exception message to further investigate, which is what I tried to avoid. What I want is if the XML validation fail, then check if no address 1 then generate "invalid mailing address", and if something else, generate some other error code. Please see my original post for more updated information. Thank you so much – Thang Pham Dec 21 '11 at 16:21
2

The following may work (I haven't coded it yet). You could create a StAX XMLStreamReader on you XML input. Then unmarshal from that using an Unmarshaller with a Schema set on it to enable validation. If an error occurs the unmarshalling will stop. Then you can check what event the XMLStreamReader is currently at to see where the error occurred.

bdoughan
  • 147,609
  • 23
  • 300
  • 400
2

There is no well formed solution to what you are asking through JAXB. JAXB provides support to validate the source xml against the schema which reults in - true or false. The concept is that if the xml is invalid you should not proceed further.

Acn
  • 1,010
  • 2
  • 11
  • 22