7

I'm attempting to parse load a rather complicated XML schema into a Schema object in Java so I can do some validation on XML messages.

My code looks similar to this:

SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = factory.newSchema(new StreamSource(new File("schema/schema.xsd")));

My schema has quite a few imports:

<?xml version="1.0" encoding="UTF-8"?>
  <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="base_1">
  <xs:import namespace="base_1" schemaLocation="common/MessageBase.xsd"/>
</xs:schema>

...etc. When I attempt to load the schema, I get lots of errors. Based on one other question related to this, it looks like I need to specify a resource resolver, but isn't this something that should be handled by default?

If so, is there a specific directory I need to put the schema in relative to where I run the application I'm writing or relative to the base schema file?

Finally, when I load the schema with XMLSpy or similar, it works fine and I can validate XML instances with no problem.

quaylar
  • 2,617
  • 1
  • 17
  • 31
magneticMonster
  • 2,373
  • 6
  • 30
  • 46

3 Answers3

15

There is no need for a resource resolver if you use an URL instead of a StreamSource.

URL schemaURL = Thread.currentThread().getContextClassLoader().getResource(schemaFileName);
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema = schemaFactory.newSchema(schemaURL);
Peter
  • 163
  • 1
  • 4
  • 2
    I already did it using an URL, but still did't resolve the resources correctly for me when it had to deal with imports. I used a ResourceResolver, and it was fixed though. Why it does work for you, and not for me remains the question. maybe it has to do with project structure. The paths in my xsd files are relative to my java classpath, my best guess, is that yours may be relative to your working folder. – bvdb Oct 26 '16 at 13:21
  • I had a root XSD including several other XSDs and importing another XSD. Loading them as array of Sources did not work, however specifying only the root XSD as URL as stated in this response worked for me. Thanks! – times29 Aug 03 '22 at 07:42
10

I think that the use of StreamSource, without specifying the base location, is the source of your problem.

The parser has no way of knowing where the main schema is, so it can't resolve common/MessageBase.xml.

Use the two-argument constructor and pass in a SystemID that is the pathname where you're starting from.

See the javadoc for StreamSource.

bmargulies
  • 97,814
  • 39
  • 186
  • 310
  • Tried this and still get the following error: src-resolve: Cannot resolve the name 'base:StatusWithError_optional' to a(n) 'attribute group' component. – magneticMonster Nov 14 '09 at 00:50
  • That's a different issue. It suggests that your schema is not complete and self-contained. Do you have an attribute group named StatusWithError_optional? Is it in the right namespace? – bmargulies Nov 14 '09 at 02:01
  • Yep, it's defined in a separate file at the same level as the base schema file. Same namespace. Should the systemID be the path to the root .xsd file or to the root directory for the schema? How about the other argument of the 2-arg constructor? – magneticMonster Nov 14 '09 at 02:14
  • the system ID should be the path to the entire schema. Again, the error you are getting indicates that finding the imported schema is working, but now there's an actual problem with the content of the schema. The first arg is just the stream or the reader, after all. – bmargulies Nov 14 '09 at 02:37
  • Is there a way to get more information about how the schema is being parsed? What order the files are being loaded, where in the file it's running into these errors, etc.? (Thanks for your help, by the way) – magneticMonster Nov 14 '09 at 02:54
  • You need to read it all into a text editor and poke around. You could also try reading it with Apache XmlSchema, it might or might not be more informative. – bmargulies Nov 14 '09 at 12:22
  • 3
    @bmargulies: After spending 4h to find out that this is the reason why the include-tags in my xml-schema are not resolving, i would gladly give you +10 for this answer :) In addition to your info: In fact the StreamSource(File) constructor does set the systemId itself by querying the URL from File. The problem here seems that he passed a relative path. I encountered the very same prob because i used StreamSource(InputStream) which of course does also not provide any information about the path - unless you set it explicitely. For future reference for myself and others :D – quaylar Oct 10 '12 at 12:57
2

In order to resolve the imported XSDs you have to associate the schema factory with a resource resolver:

SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
factory.setResourceResolver(new MyResourceResolver());
Schema schema = factory.newSchema(new StreamSource(new File("schema/schema.xsd")));

For further details you can look at this answer.

Community
  • 1
  • 1
greenluka
  • 21
  • 2