You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Projects requiring external multiple XSDs with the same schemaLocation in the import, require a means to resolve the local XSD within the applications file jar or file structure. This becomes an issue when multiple versions of the same XSD is maintained and the XSD filename or path is changed to reflect the version, ie. custom_v1.xsd, custom_v2.xsd or schema/v1/custom.xsd, schema/v2/custom.xsd-> [ <xsd:import namespace="com.org/custom_feature" schemaLocation="custom.xsd"/> ]
Example JUnit code snippet:
@Test
public void test() throws XMLStreamException, SAXException, IOException
{
File basePath = new File(System.getProperty("user.dir") + "/schema");
// Source xml file
File xmlFile = new File(basePath, "refxml/mydata.xml");
// XSD fies
File xsdMyFile = new File(basePath, "schema/example.xsd");
File xsdCustomFileV1 = new File(basePath, "schema/custom_v1.xsd");
// Validation first
Map<String, Source> schemas = new HashMap<>();
schemas.put("com.myorg/main", new StreamSource(xsdMyFile));
schemas.put("com.org/custom_feature", new StreamSource(xsdCustomFileV1));
try
{
W3CMultiSchemaFactory sf = new W3CMultiSchemaFactory();
sf.setEntityResolver(new EntityResolver() {
@Override
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException
{
System.out.println("ResolveEntity() - Before->Public id: [" + publicId + "], System id: [" + systemId + "]");
InputSource is = null;
File tmp = new File(URI.create(systemId).getPath());
String fileName = tmp.getName();
if ("custom.xsd".equals(fileName))
{
tmp = xsdCustomFileV1;
}
try
{
is = new InputSource(new FileReader(tmp));
is.setSystemId(tmp.toURI().toString());
}
catch (IOException ex)
{
ex.printStackTrace();
}
if (is != null)
{
System.out.println("ResolveEntity() - Before->Public id: [" + is.getPublicId() + "], System id: [" + is.getSystemId() + "]");
}
return is;
}
});
schema = sf.createSchema(basePath.toURI().toString(), schemas);
// Parse
final WstxInputFactory xf = new WstxInputFactory();
xf.setProperty(XMLInputFactory2.P_PRESERVE_LOCATION, Boolean.TRUE );
xf.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, true);
xf.setProperty(XMLInputFactory.IS_COALESCING, true);
XMLStreamReader2 reader = (XMLStreamReader2) xf.createXMLStreamReader(new BufferedInputStream(new FileInputStream(xmlFile)));
reader.setValidationProblemHandler( new ValidationProblemHandler() {
@Override
public void reportProblem(XMLValidationProblem arg0) throws XMLValidationException
{
if (arg0.getSeverity() == XMLValidationProblem.SEVERITY_WARNING )
{
System.out.println("Validation Warning: " + arg0.getMessage());
}
else
{
System.out.println("Validation Error: " + arg0.getMessage());
throw arg0.toException();
}
}
});
reader.validateAgainst(schema);
while (reader.hasNext())
{
int code = reader.next();
}
Suggested changes:
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;
import org.codehaus.stax2.validation.XMLValidationSchema;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import com.ctc.wstx.msv.W3CSchema;
import com.ctc.wstx.shaded.msv_core.grammar.ExpressionPool;
import com.ctc.wstx.shaded.msv_core.grammar.xmlschema.XMLSchemaGrammar;
import com.ctc.wstx.shaded.msv_core.grammar.xmlschema.XMLSchemaSchema;
import com.ctc.wstx.shaded.msv_core.reader.GrammarReaderController;
import com.ctc.wstx.shaded.msv_core.reader.GrammarReaderController2;
import com.ctc.wstx.shaded.msv_core.reader.State;
import com.ctc.wstx.shaded.msv_core.reader.xmlschema.EmbeddedSchema;
import com.ctc.wstx.shaded.msv_core.reader.xmlschema.MultiSchemaReader;
import com.ctc.wstx.shaded.msv_core.reader.xmlschema.SchemaState;
import com.ctc.wstx.shaded.msv_core.reader.xmlschema.WSDLGrammarReaderController;
import com.ctc.wstx.shaded.msv_core.reader.xmlschema.XMLSchemaReader;
public class W3CMultiSchemaFactory
{
private final SAXParserFactory parserFactory;
private EntityResolver entityResolver;
public W3CMultiSchemaFactory() {
parserFactory = SAXParserFactory.newInstance();
parserFactory.setNamespaceAware(true);
}
static class RecursiveAllowedXMLSchemaReader extends XMLSchemaReader
{
Set<String> sysIds = new TreeSet<String>();
public RecursiveAllowedXMLSchemaReader(GrammarReaderController controller, SAXParserFactory parserFactory)
{
super(controller, parserFactory, new StateFactory() {
@Override
public State schemaHead(String expectedNamespace) {
return new SchemaState(expectedNamespace) {
private XMLSchemaSchema old;
@Override
protected void endSelf() {
super.endSelf();
RecursiveAllowedXMLSchemaReader r = (RecursiveAllowedXMLSchemaReader)reader;
r.currentSchema = old;
}
@Override
protected void onTargetNamespaceResolved(String targetNs, boolean ignoreContents)
{
RecursiveAllowedXMLSchemaReader r = (RecursiveAllowedXMLSchemaReader)reader;
// sets new XMLSchemaGrammar object.
old = r.currentSchema;
r.currentSchema = r.getOrCreateSchema(targetNs);
if (ignoreContents) {
return;
}
if (!r.isSchemaDefined(r.currentSchema)) {
r.markSchemaAsDefined(r.currentSchema);
}
}
};
}
}, new ExpressionPool());
}
@Override
public void setLocator(Locator locator) {
if (locator == null && getLocator() != null && getLocator().getSystemId() != null)
{
sysIds.add(getLocator().getSystemId());
}
super.setLocator(locator);
}
@Override
public void switchSource(Source source, State newState)
{
String url = source.getSystemId();
if (url != null && sysIds.contains(url)) {
return;
}
super.switchSource(source, newState);
}
}
static class FixedWSDLGrammarReaderController extends WSDLGrammarReaderController
{
private EntityResolver entityResolver;
public FixedWSDLGrammarReaderController(GrammarReaderController2 nextController,
String baseURI, Map<String, EmbeddedSchema> sources)
{
super(nextController, baseURI, sources);
}
public void setEntityResolver(EntityResolver entityResolver)
{
this.entityResolver = entityResolver;
}
@Override
public InputSource resolveEntity(String publicId, String systemId)
{
InputSource is = null;
if (entityResolver != null)
{
try
{
is = entityResolver.resolveEntity(publicId, systemId);
}
catch (SAXException | IOException ex)
{
ex.printStackTrace();
}
}
else {
is = super.resolveEntity(publicId, systemId);
}
return is;
}
}
/**
* Creates an XMLValidateSchema that can be used to validate XML instances against
* any of the schemas defined in the Map of schemaSources.
*
* @param baseURI Base URI for resolving dependant schemas
* @param schemaSources Map of schemas, namespace to Source
*/
public XMLValidationSchema createSchema(String baseURI,
Map<String, Source> schemaSources) throws XMLStreamException
{
Map<String, EmbeddedSchema> embeddedSources = new HashMap<String, EmbeddedSchema>();
for (Map.Entry<String, Source> source : schemaSources.entrySet()) {
if (source.getValue() instanceof DOMSource) {
Node nd = ((DOMSource)source.getValue()).getNode();
Element el = null;
if (nd instanceof Element) {
el = (Element)nd;
} else if (nd instanceof Document) {
el = ((Document)nd).getDocumentElement();
}
embeddedSources.put(source.getKey(), new EmbeddedSchema(source.getValue().getSystemId(), el));
}
}
final FixedWSDLGrammarReaderController ctrl = new FixedWSDLGrammarReaderController(null, baseURI, embeddedSources);
ctrl.setEntityResolver(entityResolver);
final RecursiveAllowedXMLSchemaReader xmlSchemaReader = new RecursiveAllowedXMLSchemaReader(ctrl, parserFactory);
final MultiSchemaReader multiSchemaReader = new MultiSchemaReader(xmlSchemaReader);
for (Source source : schemaSources.values()) {
multiSchemaReader.parse(source);
}
XMLSchemaGrammar grammar = multiSchemaReader.getResult();
if (grammar == null) {
throw new XMLStreamException("Failed to load schemas");
}
return new W3CSchema(grammar);
}
public W3CMultiSchemaFactory setEntityResolver(EntityResolver entityResolver)
{
this.entityResolver = entityResolver;
return this;
}
}
The text was updated successfully, but these errors were encountered:
Projects requiring external multiple XSDs with the same schemaLocation in the import, require a means to resolve the local XSD within the applications file jar or file structure. This becomes an issue when multiple versions of the same XSD is maintained and the XSD filename or path is changed to reflect the version, ie. custom_v1.xsd, custom_v2.xsd or schema/v1/custom.xsd, schema/v2/custom.xsd-> [ <xsd:import namespace="com.org/custom_feature" schemaLocation="custom.xsd"/> ]
Example JUnit code snippet:
Suggested changes:
The text was updated successfully, but these errors were encountered: