1

I am trying to validate XML against a XSD file in Java.

This is my code:

public static InputStream inputStreamFromClasspath(String path) {
    return Utils.class.getClassLoader().getResourceAsStream(path);
}   

public static boolean validateXMLSchema() throws SAXException, IOException {

    InputStream xsd = inputStreamFromClasspath("/xml/students_xsd.xml");
    InputStream xml = inputStreamFromClasspath("/xml/students.xml");
    SchemaFactory factory =
                SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
    Schema schema = factory.newSchema(new StreamSource(xsd));
    Validator validator = schema.newValidator();
    validator.validate(new StreamSource(xml));
    return true;
}

But I am getting an error:

org.xml.sax.SAXParseException; schema_reference.4: Failed to read schema document 'null', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.

Code reference: Validating XML against XSD

My Students xml file is:

<?xml version = "1.0"?>

<class>
    <student rollno = "393">
        <firstname>Dinkar</firstname>
        <lastname>Kad</lastname>
        <nickname>Dinkar</nickname>
        <marks>85</marks>
    </student>

    <student rollno = "493">
        <firstname>Vaneet</firstname>
        <lastname>Gupta</lastname>
        <nickname>Vinni</nickname>
        <marks>95</marks>
    </student>

    <student rollno = "593">
        <firstname>Jasvir</firstname>
        <lastname>Singh</lastname>
        <nickname>Jazz</nickname>
        <marks>90</marks>
    </student>
</class>

And the xsd file is:

<?xml version = "1.0"?>

<xs:schema xmlns:xs = "http://www.w3.org/2001/XMLSchema">
    <xs:element name = 'class'>
        <xs:complexType>
            <xs:sequence>
                <xs:element name = 'student' type = 'StudentType' minOccurs = '0'
                            maxOccurs = 'unbounded' />
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:complexType name = "StudentType">
        <xs:sequence>
            <xs:element name = "firstname" type = "xs:string"/>
            <xs:element name = "lastname" type = "xs:string"/>
            <xs:element name = "nickname" type = "xs:string"/>
            <xs:element name = "marks" type = "xs:positiveInteger"/>
        </xs:sequence>
        <xs:attribute name = 'rollno' type = 'xs:positiveInteger'/>
    </xs:complexType>
</xs:schema>

Not sure where I am getting wrong, any suggestions will be helpful. Thank you.

Mads Hansen
  • 63,927
  • 12
  • 112
  • 147
Rumi
  • 61
  • 1
  • 9

1 Answers1

3

One other thing:

    InputStream xsd = inputStreamFromClasspath("/xml/students_xsd.xml");
    return Utils.class.getClassLoader().getResourceAsStream(path);
  • A ClassLoader uses an absolute path without preceding /.
  • A class uses a possibly relative path (relative to its package), and for absolute paths need a preceding /.

Either (my preference, better with modular java)

    InputStream xsd = inputStreamFromClasspath("/xml/students_xsd.xml");
    return Utils.class.getResourceAsStream(path);

or (needing correction of all calls)

    InputStream xsd = inputStreamFromClasspath("xml/students_xsd.xml");
    return Utils.class.getClassLoader().getResourceAsStream(path);

You got a null resource because of that slash.

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
  • Thank you, the problem was in the schema it was xs, should be xsd. But this was a problem too. – Rumi Feb 03 '22 at 21:23
  • @Rumi: Hmm, are you sure about that? Your XSD defines and uses an `xs:schema` root element with `xmlns:xs = "http://www.w3.org/2001/XMLSchema"`, which is fine instead of defining `xsd` as the namespace prefix. It would seem more likely to me that you're messing up with specifying the XSD due to one or more issues that Joop has indicated. – kjhughes Feb 03 '22 at 21:27
  • 1
    You are right, I was messing up the file path, Thank you. – Rumi Feb 03 '22 at 21:31
  • 2
    It’s better to use Class.getResource(AsStream) than the ClassLoader methods. In modular applications, they have slightly different behavior. See https://stackoverflow.com/questions/68314700/why-java-cannot-read-same-resource-file-when-module-info-is-added/68321325#68321325. – VGR Feb 03 '22 at 23:56