More validator work
This commit is contained in:
parent
c75c37d24d
commit
d205075e35
|
@ -1,3 +1,10 @@
|
||||||
|
|
||||||
|
* XML Dsig
|
||||||
|
|
||||||
|
*
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
* Add SimpleSetters for all primitive datatypes
|
* Add SimpleSetters for all primitive datatypes
|
||||||
|
|
||||||
* Implement and add Simple Getters in a similar way to simple setters
|
* Implement and add Simple Getters in a similar way to simple setters
|
||||||
|
|
|
@ -661,6 +661,7 @@ class ParserState<T> {
|
||||||
myPreResourceState = thePreResourceState;
|
myPreResourceState = thePreResourceState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public void attributeValue(String theName, String theValue) throws DataFormatException {
|
public void attributeValue(String theName, String theValue) throws DataFormatException {
|
||||||
// ignore by default
|
// ignore by default
|
||||||
}
|
}
|
||||||
|
@ -669,6 +670,7 @@ class ParserState<T> {
|
||||||
// ignore by default
|
// ignore by default
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public void enteringNewElement(String theNamespaceURI, String theLocalPart) throws DataFormatException {
|
public void enteringNewElement(String theNamespaceURI, String theLocalPart) throws DataFormatException {
|
||||||
// ignore by default
|
// ignore by default
|
||||||
}
|
}
|
||||||
|
@ -676,6 +678,7 @@ class ParserState<T> {
|
||||||
/**
|
/**
|
||||||
* Default implementation just handles undeclared extensions
|
* Default implementation just handles undeclared extensions
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public void enteringNewElementExtension(StartElement theElement, String theUrlAttr, boolean theIsModifier) {
|
public void enteringNewElementExtension(StartElement theElement, String theUrlAttr, boolean theIsModifier) {
|
||||||
if (myPreResourceState != null && getCurrentElement() instanceof ISupportsUndeclaredExtensions) {
|
if (myPreResourceState != null && getCurrentElement() instanceof ISupportsUndeclaredExtensions) {
|
||||||
ExtensionDt newExtension = new ExtensionDt(theIsModifier, theUrlAttr);
|
ExtensionDt newExtension = new ExtensionDt(theIsModifier, theUrlAttr);
|
||||||
|
|
|
@ -37,7 +37,7 @@ public class ResponseValidatingInterceptor extends InterceptorAdapter {
|
||||||
private FhirValidator myValidator;
|
private FhirValidator myValidator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the validator used ny this interceptor
|
* Returns the validator used by this interceptor
|
||||||
*/
|
*/
|
||||||
public FhirValidator getValidator() {
|
public FhirValidator getValidator() {
|
||||||
return myValidator;
|
return myValidator;
|
||||||
|
|
|
@ -31,8 +31,8 @@ import ca.uhn.fhir.model.api.IResource;
|
||||||
import ca.uhn.fhir.model.dstu.resource.OperationOutcome;
|
import ca.uhn.fhir.model.dstu.resource.OperationOutcome;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resource validator, which checks resources for compliance against various
|
* Resource validator, which checks resources for compliance against various validation schemes (schemas, schematrons,
|
||||||
* validation schemes (schemas, schematrons, etc.)
|
* etc.)
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* To obtain a resource validator, call {@link FhirContext#newValidator()}
|
* To obtain a resource validator, call {@link FhirContext#newValidator()}
|
||||||
|
@ -51,15 +51,15 @@ public class FhirValidator {
|
||||||
*/
|
*/
|
||||||
public FhirValidator(FhirContext theFhirContext) {
|
public FhirValidator(FhirContext theFhirContext) {
|
||||||
myContext = theFhirContext;
|
myContext = theFhirContext;
|
||||||
setValidateBaseSchema(true);
|
setValidateAgainstStandardSchema(true);
|
||||||
setValidateBaseSchematron(true);
|
setValidateAgainstStandardSchematron(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should the validator validate the resource against the base schema (the schema provided with the FHIR
|
* Should the validator validate the resource against the base schema (the schema provided with the FHIR
|
||||||
* distribution itself)
|
* distribution itself)
|
||||||
*/
|
*/
|
||||||
public boolean isValidateBaseSchema() {
|
public boolean isValidateAgainstStandardSchema() {
|
||||||
return haveValidatorOfType(SchemaBaseValidator.class);
|
return haveValidatorOfType(SchemaBaseValidator.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,15 +67,15 @@ public class FhirValidator {
|
||||||
* Should the validator validate the resource against the base schema (the schema provided with the FHIR
|
* Should the validator validate the resource against the base schema (the schema provided with the FHIR
|
||||||
* distribution itself)
|
* distribution itself)
|
||||||
*/
|
*/
|
||||||
public void setValidateBaseSchema(boolean theValidateBaseSchema) {
|
public void setValidateAgainstStandardSchema(boolean theValidateAgainstStandardSchema) {
|
||||||
addOrRemoveValidator(theValidateBaseSchema, SchemaBaseValidator.class, new SchemaBaseValidator());
|
addOrRemoveValidator(theValidateAgainstStandardSchema, SchemaBaseValidator.class, new SchemaBaseValidator());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should the validator validate the resource against the base schema (the schema provided with the FHIR
|
* Should the validator validate the resource against the base schema (the schema provided with the FHIR
|
||||||
* distribution itself)
|
* distribution itself)
|
||||||
*/
|
*/
|
||||||
public boolean isValidateBaseSchematron() {
|
public boolean isValidateAgainstStandardSchematron() {
|
||||||
return haveValidatorOfType(SchematronBaseValidator.class);
|
return haveValidatorOfType(SchematronBaseValidator.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,18 +83,23 @@ public class FhirValidator {
|
||||||
* Should the validator validate the resource against the base schematron (the schematron provided with the FHIR
|
* Should the validator validate the resource against the base schematron (the schematron provided with the FHIR
|
||||||
* distribution itself)
|
* distribution itself)
|
||||||
*/
|
*/
|
||||||
public void setValidateBaseSchematron(boolean theValidateBaseSchematron) {
|
public void setValidateAgainstStandardSchematron(boolean theValidateAgainstStandardSchematron) {
|
||||||
addOrRemoveValidator(theValidateBaseSchematron, SchematronBaseValidator.class, new SchematronBaseValidator());
|
addOrRemoveValidator(theValidateAgainstStandardSchematron, SchematronBaseValidator.class, new SchematronBaseValidator());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates a resource instance, throwing a {@link ValidationFailureException} if the validation fails
|
||||||
|
*
|
||||||
|
* @param theResource The resource to validate
|
||||||
|
* @throws ValidationFailureException If the validation fails
|
||||||
|
*/
|
||||||
public void validate(IResource theResource) throws ValidationFailureException {
|
public void validate(IResource theResource) throws ValidationFailureException {
|
||||||
Validate.notNull(theResource, "theResource must not be null");
|
Validate.notNull(theResource, "theResource must not be null");
|
||||||
|
|
||||||
ValidationContext ctx = new ValidationContext(myContext, theResource);
|
ValidationContext<IResource> ctx = ValidationContext.forResource(myContext, theResource);
|
||||||
|
|
||||||
for (IValidator next : myValidators) {
|
for (IValidator next : myValidators) {
|
||||||
next.validate(ctx);
|
next.validateResource(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
OperationOutcome oo = ctx.getOperationOutcome();
|
OperationOutcome oo = ctx.getOperationOutcome();
|
||||||
|
@ -104,8 +109,8 @@ public class FhirValidator {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addOrRemoveValidator(boolean theValidateBaseSchema, Class<? extends IValidator> type, IValidator instance) {
|
private void addOrRemoveValidator(boolean theValidateAgainstStandardSchema, Class<? extends IValidator> type, IValidator instance) {
|
||||||
if (theValidateBaseSchema) {
|
if (theValidateAgainstStandardSchema) {
|
||||||
boolean found = haveValidatorOfType(type);
|
boolean found = haveValidatorOfType(type);
|
||||||
if (!found) {
|
if (!found) {
|
||||||
myValidators.add(instance);
|
myValidators.add(instance);
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package ca.uhn.fhir.validation;
|
package ca.uhn.fhir.validation;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.model.api.IResource;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* #%L
|
* #%L
|
||||||
* HAPI FHIR - Core Library
|
* HAPI FHIR - Core Library
|
||||||
|
@ -23,6 +25,6 @@ package ca.uhn.fhir.validation;
|
||||||
|
|
||||||
interface IValidator {
|
interface IValidator {
|
||||||
|
|
||||||
void validate(ValidationContext theCtx);
|
void validateResource(ValidationContext<IResource> theCtx);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,11 @@ import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.xml.XMLConstants;
|
import javax.xml.XMLConstants;
|
||||||
import javax.xml.transform.Source;
|
import javax.xml.transform.Source;
|
||||||
|
@ -43,54 +46,41 @@ import org.xml.sax.SAXException;
|
||||||
import org.xml.sax.SAXParseException;
|
import org.xml.sax.SAXParseException;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.ConfigurationException;
|
import ca.uhn.fhir.context.ConfigurationException;
|
||||||
|
import ca.uhn.fhir.model.api.Bundle;
|
||||||
import ca.uhn.fhir.model.api.IResource;
|
import ca.uhn.fhir.model.api.IResource;
|
||||||
import ca.uhn.fhir.model.dstu.resource.OperationOutcome;
|
|
||||||
import ca.uhn.fhir.model.dstu.resource.OperationOutcome.Issue;
|
import ca.uhn.fhir.model.dstu.resource.OperationOutcome.Issue;
|
||||||
import ca.uhn.fhir.model.dstu.valueset.IssueSeverityEnum;
|
import ca.uhn.fhir.model.dstu.valueset.IssueSeverityEnum;
|
||||||
|
|
||||||
class SchemaBaseValidator implements IValidator {
|
class SchemaBaseValidator implements IValidator {
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SchemaBaseValidator.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SchemaBaseValidator.class);
|
||||||
private Map<Class<? extends IResource>, Schema> myClassToSchema = new HashMap<Class<? extends IResource>, Schema>();
|
private static final Set<String> SCHEMA_NAMES;
|
||||||
|
|
||||||
private Schema loadSchema(final Class<? extends IResource> theClass, ValidationContext theValidationCtx) {
|
static {
|
||||||
synchronized (myClassToSchema) {
|
HashSet<String> sn = new HashSet<String>();
|
||||||
Schema schema = myClassToSchema.get(theClass);
|
sn.add("xml.xsd");
|
||||||
if (schema != null) {
|
sn.add("xhtml1-strict.xsd");
|
||||||
return schema;
|
sn.add("fhir-single.xsd");
|
||||||
|
sn.add("tombstone.xsd");
|
||||||
|
sn.add("opensearch.xsd");
|
||||||
|
sn.add("opensearchscore.xsd");
|
||||||
|
sn.add("xmldsig-core-schema.xsd");
|
||||||
|
SCHEMA_NAMES = Collections.unmodifiableSet(sn);
|
||||||
}
|
}
|
||||||
|
|
||||||
Source baseSource = loadXml(theValidationCtx, theClass, null, "fhir-single.xsd");
|
private Map<String, Schema> myKeyToSchema = new HashMap<String, Schema>();
|
||||||
|
|
||||||
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
|
public void validateBundle(ValidationContext<Bundle> theContext) {
|
||||||
schemaFactory.setResourceResolver(new MyResourceResolver(theClass));
|
doValidate(theContext, "fhir-atom-single.xsd");
|
||||||
|
|
||||||
try {
|
|
||||||
schema = schemaFactory.newSchema(new Source[] { baseSource });
|
|
||||||
} catch (SAXException e) {
|
|
||||||
throw new ConfigurationException("Could not load/parse schema file", e);
|
|
||||||
}
|
|
||||||
myClassToSchema.put(theClass, schema);
|
|
||||||
return schema;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Source loadXml(ValidationContext theCtx, Class<? extends IResource> theClass, String theSystemId, String theSchemaName) {
|
|
||||||
Class<? extends IResource> baseResourceClass = theCtx.getFhirContext().getResourceDefinition(theClass).getBaseDefinition().getImplementingClass();
|
|
||||||
Package pack = baseResourceClass.getPackage();
|
|
||||||
String pathToBase = pack.getName().replace('.', '/') + '/' + theSchemaName;
|
|
||||||
InputStream baseIs = FhirValidator.class.getClassLoader().getResourceAsStream(pathToBase);
|
|
||||||
if (baseIs == null) {
|
|
||||||
throw new ValidationFailureException("No FHIR-BASE schema found");
|
|
||||||
}
|
|
||||||
Source baseSource = new StreamSource(baseIs, theSystemId);
|
|
||||||
return baseSource;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validate(ValidationContext theContext) {
|
public void validateResource(ValidationContext<IResource> theContext) {
|
||||||
OperationOutcome outcome = theContext.getOperationOutcome();
|
doValidate(theContext, "fhir-single.xsd");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doValidate(ValidationContext<?> theContext, String schemaName) {
|
||||||
|
Schema schema = loadSchema("dstu", schemaName);
|
||||||
|
|
||||||
Schema schema = loadSchema(outcome.getClass(), theContext);
|
|
||||||
try {
|
try {
|
||||||
Validator validator = schema.newValidator();
|
Validator validator = schema.newValidator();
|
||||||
MyErrorHandler handler = new MyErrorHandler(theContext);
|
MyErrorHandler handler = new MyErrorHandler(theContext);
|
||||||
|
@ -104,21 +94,87 @@ class SchemaBaseValidator implements IValidator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class MyResourceResolver implements LSResourceResolver {
|
private Schema loadSchema(String theVersion, String theSchemaName) {
|
||||||
private final Class<? extends IResource> myClass;
|
String key = theVersion + "-" + theSchemaName;
|
||||||
|
|
||||||
private MyResourceResolver(Class<? extends IResource> theClass) {
|
synchronized (myKeyToSchema) {
|
||||||
myClass = theClass;
|
Schema schema = myKeyToSchema.get(key);
|
||||||
|
if (schema != null) {
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
Source baseSource = loadXml("dstu", null, theSchemaName);
|
||||||
|
|
||||||
|
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
|
||||||
|
schemaFactory.setResourceResolver(new MyResourceResolver("dstu"));
|
||||||
|
|
||||||
|
try {
|
||||||
|
schema = schemaFactory.newSchema(new Source[] { baseSource });
|
||||||
|
} catch (SAXException e) {
|
||||||
|
throw new ConfigurationException("Could not load/parse schema file", e);
|
||||||
|
}
|
||||||
|
myKeyToSchema.put(key, schema);
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Source loadXml(String theVersion, String theSystemId, String theSchemaName) {
|
||||||
|
String pathToBase = "ca/uhn/fhir/model/" + theVersion + "/schema/" + theSchemaName;
|
||||||
|
InputStream baseIs = FhirValidator.class.getClassLoader().getResourceAsStream(pathToBase);
|
||||||
|
if (baseIs == null) {
|
||||||
|
throw new ValidationFailureException("No FHIR-BASE schema found");
|
||||||
|
}
|
||||||
|
Source baseSource = new StreamSource(baseIs, theSystemId);
|
||||||
|
return baseSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class MyErrorHandler implements org.xml.sax.ErrorHandler {
|
||||||
|
|
||||||
|
private ValidationContext<?> myContext;
|
||||||
|
|
||||||
|
public MyErrorHandler(ValidationContext<?> theContext) {
|
||||||
|
myContext = theContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(SAXParseException theException) throws SAXException {
|
||||||
|
addIssue(theException, IssueSeverityEnum.ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fatalError(SAXParseException theException) throws SAXException {
|
||||||
|
addIssue(theException, IssueSeverityEnum.FATAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void warning(SAXParseException theException) throws SAXException {
|
||||||
|
addIssue(theException, IssueSeverityEnum.WARNING);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addIssue(SAXParseException theException, IssueSeverityEnum severity) {
|
||||||
|
Issue issue = myContext.getOperationOutcome().addIssue();
|
||||||
|
issue.setSeverity(severity);
|
||||||
|
issue.setDetails(theException.getLocalizedMessage());
|
||||||
|
issue.addLocation().setValue("Line[" + theException.getLineNumber() + "] Col[" + theException.getColumnNumber() + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class MyResourceResolver implements LSResourceResolver {
|
||||||
|
private String myVersion;
|
||||||
|
|
||||||
|
private MyResourceResolver(String theVersion) {
|
||||||
|
myVersion = theVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LSInput resolveResource(String theType, String theNamespaceURI, String thePublicId, String theSystemId, String theBaseURI) {
|
public LSInput resolveResource(String theType, String theNamespaceURI, String thePublicId, String theSystemId, String theBaseURI) {
|
||||||
if ("xml.xsd".equals(theSystemId) || "xhtml1-strict.xsd".equals(theSystemId)) {
|
if (theSystemId != null && SCHEMA_NAMES.contains(theSystemId)) {
|
||||||
LSInputImpl input = new LSInputImpl();
|
LSInputImpl input = new LSInputImpl();
|
||||||
input.setPublicId(thePublicId);
|
input.setPublicId(thePublicId);
|
||||||
input.setSystemId(theSystemId);
|
input.setSystemId(theSystemId);
|
||||||
input.setBaseURI(theBaseURI);
|
input.setBaseURI(theBaseURI);
|
||||||
String pathToBase = myClass.getPackage().getName().replace('.', '/') + '/' + theSystemId;
|
String pathToBase = "ca/uhn/fhir/model/" + myVersion + "/schema/" + theSystemId;
|
||||||
InputStream baseIs = FhirValidator.class.getClassLoader().getResourceAsStream(pathToBase);
|
InputStream baseIs = FhirValidator.class.getClassLoader().getResourceAsStream(pathToBase);
|
||||||
if (baseIs == null) {
|
if (baseIs == null) {
|
||||||
throw new ValidationFailureException("No FHIR-BASE schema found");
|
throw new ValidationFailureException("No FHIR-BASE schema found");
|
||||||
|
@ -152,36 +208,4 @@ class SchemaBaseValidator implements IValidator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class MyErrorHandler implements org.xml.sax.ErrorHandler {
|
|
||||||
|
|
||||||
private ValidationContext myContext;
|
|
||||||
|
|
||||||
public MyErrorHandler(ValidationContext theContext) {
|
|
||||||
myContext = theContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void error(SAXParseException theException) throws SAXException {
|
|
||||||
addIssue(theException, IssueSeverityEnum.ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void fatalError(SAXParseException theException) throws SAXException {
|
|
||||||
addIssue(theException, IssueSeverityEnum.FATAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void warning(SAXParseException theException) throws SAXException {
|
|
||||||
addIssue(theException, IssueSeverityEnum.WARNING);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addIssue(SAXParseException theException, IssueSeverityEnum severity) {
|
|
||||||
Issue issue = myContext.getOperationOutcome().addIssue();
|
|
||||||
issue.setSeverity(severity);
|
|
||||||
issue.setDetails(theException.getLocalizedMessage());
|
|
||||||
issue.addLocation().setValue("Line[" + theException.getLineNumber() + "] Col[" + theException.getColumnNumber() + "]");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,7 @@ public class SchematronBaseValidator implements IValidator {
|
||||||
private Map<Class<? extends IResource>, ISchematronResource> myClassToSchematron = new HashMap<Class<? extends IResource>, ISchematronResource>();
|
private Map<Class<? extends IResource>, ISchematronResource> myClassToSchematron = new HashMap<Class<? extends IResource>, ISchematronResource>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validate(ValidationContext theCtx) {
|
public void validateResource(ValidationContext<IResource> theCtx) {
|
||||||
|
|
||||||
ISchematronResource sch = getSchematron(theCtx);
|
ISchematronResource sch = getSchematron(theCtx);
|
||||||
StreamSource source = new StreamSource(new StringReader(theCtx.getXmlEncodedResource()));
|
StreamSource source = new StreamSource(new StringReader(theCtx.getXmlEncodedResource()));
|
||||||
|
@ -83,22 +83,21 @@ public class SchematronBaseValidator implements IValidator {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ISchematronResource getSchematron(ValidationContext theCtx) {
|
private ISchematronResource getSchematron(ValidationContext<IResource> theCtx) {
|
||||||
Class<? extends IResource> resource = theCtx.getResource().getClass();
|
Class<? extends IResource> resource = theCtx.getResource().getClass();
|
||||||
Class<? extends IResource> baseResourceClass = theCtx.getFhirContext().getResourceDefinition(resource).getBaseDefinition().getImplementingClass();
|
Class<? extends IResource> baseResourceClass = theCtx.getFhirContext().getResourceDefinition(resource).getBaseDefinition().getImplementingClass();
|
||||||
|
|
||||||
return getSchematronAndCache(theCtx, baseResourceClass);
|
return getSchematronAndCache(theCtx, "dstu",baseResourceClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ISchematronResource getSchematronAndCache(ValidationContext theCtx, Class<? extends IResource> theClass) {
|
private ISchematronResource getSchematronAndCache(ValidationContext<IResource> theCtx, String theVersion , Class<? extends IResource> theClass) {
|
||||||
synchronized (myClassToSchematron) {
|
synchronized (myClassToSchematron) {
|
||||||
ISchematronResource retVal = myClassToSchematron.get(theClass);
|
ISchematronResource retVal = myClassToSchematron.get(theClass);
|
||||||
if (retVal != null) {
|
if (retVal != null) {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
Package pack = theClass.getPackage();
|
|
||||||
|
|
||||||
String pathToBase = pack.getName().replace('.', '/') + '/' + theCtx.getFhirContext().getResourceDefinition(theCtx.getResource()).getBaseDefinition().getName().toLowerCase() + ".sch";
|
String pathToBase = "ca/uhn/fhir/model/"+theVersion+"/schema/" + theCtx.getFhirContext().getResourceDefinition(theCtx.getResource()).getBaseDefinition().getName().toLowerCase() + ".sch";
|
||||||
InputStream baseIs = FhirValidator.class.getClassLoader().getResourceAsStream(pathToBase);
|
InputStream baseIs = FhirValidator.class.getClassLoader().getResourceAsStream(pathToBase);
|
||||||
if (baseIs == null) {
|
if (baseIs == null) {
|
||||||
throw new ValidationFailureException("No schematron found for resource type: " + theCtx.getFhirContext().getResourceDefinition(theCtx.getResource()).getBaseDefinition().getImplementingClass().getCanonicalName());
|
throw new ValidationFailureException("No schematron found for resource type: " + theCtx.getFhirContext().getResourceDefinition(theCtx.getResource()).getBaseDefinition().getImplementingClass().getCanonicalName());
|
||||||
|
|
|
@ -21,26 +21,26 @@ package ca.uhn.fhir.validation;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.model.api.Bundle;
|
||||||
import ca.uhn.fhir.model.api.IResource;
|
import ca.uhn.fhir.model.api.IResource;
|
||||||
import ca.uhn.fhir.model.dstu.resource.OperationOutcome;
|
import ca.uhn.fhir.model.dstu.resource.OperationOutcome;
|
||||||
|
|
||||||
class ValidationContext {
|
class ValidationContext<T> {
|
||||||
|
|
||||||
private FhirContext myFhirContext;
|
private final IEncoder myEncoder;
|
||||||
|
private final FhirContext myFhirContext;
|
||||||
private OperationOutcome myOperationOutcome;
|
private OperationOutcome myOperationOutcome;
|
||||||
private IResource myResource;
|
private final T myResource;
|
||||||
private String myXmlEncodedResource;
|
private String myXmlEncodedResource;
|
||||||
|
|
||||||
public ValidationContext(FhirContext theContext, IResource theResource) {
|
private ValidationContext(FhirContext theContext, T theResource, IEncoder theEncoder) {
|
||||||
myFhirContext = theContext;
|
myFhirContext = theContext;
|
||||||
myResource = theResource;
|
myResource = theResource;
|
||||||
|
myEncoder = theEncoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getXmlEncodedResource() {
|
public FhirContext getFhirContext() {
|
||||||
if (myXmlEncodedResource == null) {
|
return myFhirContext;
|
||||||
myXmlEncodedResource = myFhirContext.newXmlParser().encodeResourceToString(myResource);
|
|
||||||
}
|
|
||||||
return myXmlEncodedResource;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public OperationOutcome getOperationOutcome() {
|
public OperationOutcome getOperationOutcome() {
|
||||||
|
@ -50,12 +50,37 @@ class ValidationContext {
|
||||||
return myOperationOutcome;
|
return myOperationOutcome;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FhirContext getFhirContext() {
|
public T getResource() {
|
||||||
return myFhirContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IResource getResource() {
|
|
||||||
return myResource;
|
return myResource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getXmlEncodedResource() {
|
||||||
|
if (myXmlEncodedResource == null) {
|
||||||
|
myXmlEncodedResource = myEncoder.encode();
|
||||||
|
}
|
||||||
|
return myXmlEncodedResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ValidationContext<Bundle> forBundle(final FhirContext theContext, final Bundle theBundle) {
|
||||||
|
return new ValidationContext<Bundle>(theContext, theBundle, new IEncoder() {
|
||||||
|
@Override
|
||||||
|
public String encode() {
|
||||||
|
return theContext.newXmlParser().encodeBundleToString(theBundle);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ValidationContext<IResource> forResource(final FhirContext theContext, final IResource theResource) {
|
||||||
|
return new ValidationContext<IResource>(theContext, theResource, new IEncoder() {
|
||||||
|
@Override
|
||||||
|
public String encode() {
|
||||||
|
return theContext.newXmlParser().encodeResourceToString(theResource);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private interface IEncoder {
|
||||||
|
String encode();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,201 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright (c) 2011-2012, HL7, Inc
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
* Neither the name of HL7 nor the names of its contributors may be used to
|
||||||
|
endorse or promote products derived from this software without specific
|
||||||
|
prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||||
|
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
Generated on Mon, Feb 3, 2014 23:47+1100 for FHIR v0.80
|
||||||
|
-->
|
||||||
|
<xs:schema xmlns:atom="http://www.w3.org/2005/Atom" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:os="http://a9.com/-/spec/opensearch/1.1/" xmlns:osr="http://a9.com/-/opensearch/extensions/relevance/1.0/"
|
||||||
|
xmlns:fhir="http://hl7.org/fhir" xmlns:at="http://purl.org/atompub/tombstones/1.0" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" targetNamespace="http://www.w3.org/2005/Atom" elementFormDefault="qualified" attributeFormDefault="unqualified">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
This is a reduced form of the atom schema, that only supports the features profiled in the FHIR specification
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
<xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="xml.xsd"/>
|
||||||
|
<xs:import namespace="http://hl7.org/fhir" schemaLocation="fhir-single.xsd"/>
|
||||||
|
<xs:import namespace="http://purl.org/atompub/tombstones/1.0" schemaLocation="tombstone.xsd"/>
|
||||||
|
<xs:import namespace="http://a9.com/-/spec/opensearch/1.1/" schemaLocation="opensearch.xsd"/>
|
||||||
|
<xs:import namespace="http://a9.com/-/opensearch/extensions/relevance/1.0/" schemaLocation="opensearchscore.xsd"/>
|
||||||
|
<xs:import namespace="http://www.w3.org/2000/09/xmldsig#" schemaLocation="xmldsig-core-schema.xsd"/>
|
||||||
|
<xs:element name="feed" type="atom:FeedType"/>
|
||||||
|
<xs:complexType name="TextType" mixed="true">
|
||||||
|
<xs:annotation>
|
||||||
|
<xs:documentation>
|
||||||
|
The Atom text construct is defined in section 3.1 of the format spec.
|
||||||
|
</xs:documentation>
|
||||||
|
</xs:annotation>
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:any namespace="http://www.w3.org/1999/xhtml" minOccurs="0"/>
|
||||||
|
</xs:sequence>
|
||||||
|
<xs:attribute name="type">
|
||||||
|
<xs:simpleType>
|
||||||
|
<xs:restriction base="xs:token">
|
||||||
|
<xs:enumeration value="text"/>
|
||||||
|
<xs:enumeration value="html"/>
|
||||||
|
<xs:enumeration value="xhtml"/>
|
||||||
|
</xs:restriction>
|
||||||
|
</xs:simpleType>
|
||||||
|
</xs:attribute>
|
||||||
|
<xs:attributeGroup ref="atom:CommonAttributes"/>
|
||||||
|
</xs:complexType>
|
||||||
|
<xs:complexType name="PersonType">
|
||||||
|
<xs:choice maxOccurs="unbounded">
|
||||||
|
<xs:element name="name" type="xs:string"/>
|
||||||
|
<xs:element name="uri" type="atom:UriType" minOccurs="0"/>
|
||||||
|
</xs:choice>
|
||||||
|
<xs:attributeGroup ref="atom:CommonAttributes"/>
|
||||||
|
</xs:complexType>
|
||||||
|
<xs:complexType name="FeedType">
|
||||||
|
<xs:sequence>
|
||||||
|
<xs:choice minOccurs="3" maxOccurs="unbounded">
|
||||||
|
<xs:element name="title" type="atom:TextType"/>
|
||||||
|
<xs:element name="updated" type="atom:DateTimeType"/>
|
||||||
|
<xs:element name="id" type="atom:IdType"/>
|
||||||
|
<xs:element name="link" type="atom:LinkType"/>
|
||||||
|
<xs:element name="author" type="atom:PersonType" maxOccurs="unbounded"/>
|
||||||
|
<xs:element name="category" type="atom:CategoryType" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
<xs:element name="entry" type="atom:EntryType"/>
|
||||||
|
<xs:element ref="at:deleted-entry"/>
|
||||||
|
<xs:element ref="os:totalResults"/>
|
||||||
|
<xs:element ref="osr:score"/>
|
||||||
|
</xs:choice>
|
||||||
|
<xs:element ref="ds:Signature" minOccurs="0" maxOccurs="1"/>
|
||||||
|
</xs:sequence>
|
||||||
|
<xs:attributeGroup ref="atom:CommonAttributes"/>
|
||||||
|
</xs:complexType>
|
||||||
|
<xs:complexType name="EntryType">
|
||||||
|
<xs:choice maxOccurs="unbounded">
|
||||||
|
<xs:element name="title" type="atom:TextType"/>
|
||||||
|
<xs:element name="link" type="atom:LinkType"/>
|
||||||
|
<xs:element name="id" type="atom:IdType"/>
|
||||||
|
<xs:element name="updated" type="atom:DateTimeType"/>
|
||||||
|
<xs:element name="published" type="atom:DateTimeType" minOccurs="0"/>
|
||||||
|
<xs:element name="author" type="atom:PersonType" maxOccurs="unbounded"/>
|
||||||
|
<xs:element name="category" type="atom:CategoryType" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
|
<xs:element name="content" type="atom:ContentType" minOccurs="0"/>
|
||||||
|
<xs:element name="summary" type="atom:TextType"/>
|
||||||
|
</xs:choice>
|
||||||
|
<xs:attributeGroup ref="atom:CommonAttributes"/>
|
||||||
|
</xs:complexType>
|
||||||
|
<xs:complexType name="CategoryType">
|
||||||
|
<xs:attribute name="term" type="xs:anyURI" use="required"/>
|
||||||
|
<xs:attribute name="scheme" type="xs:anyURI" use="required"/>
|
||||||
|
<xs:attribute name="label" type="xs:string" use="optional"/>
|
||||||
|
<xs:attributeGroup ref="atom:CommonAttributes"/>
|
||||||
|
</xs:complexType>
|
||||||
|
<xs:complexType name="ContentType" mixed="true">
|
||||||
|
<xs:choice>
|
||||||
|
<xs:element ref="fhir:Binary"/>
|
||||||
|
<xs:element ref="atom:feed" />
|
||||||
|
<xs:element ref="fhir:AdverseReaction"/>
|
||||||
|
<xs:element ref="fhir:Alert"/>
|
||||||
|
<xs:element ref="fhir:AllergyIntolerance"/>
|
||||||
|
<xs:element ref="fhir:CarePlan"/>
|
||||||
|
<xs:element ref="fhir:Composition"/>
|
||||||
|
<xs:element ref="fhir:ConceptMap"/>
|
||||||
|
<xs:element ref="fhir:Condition"/>
|
||||||
|
<xs:element ref="fhir:Conformance"/>
|
||||||
|
<xs:element ref="fhir:Device"/>
|
||||||
|
<xs:element ref="fhir:DeviceObservationReport"/>
|
||||||
|
<xs:element ref="fhir:DiagnosticOrder"/>
|
||||||
|
<xs:element ref="fhir:DiagnosticReport"/>
|
||||||
|
<xs:element ref="fhir:DocumentManifest"/>
|
||||||
|
<xs:element ref="fhir:DocumentReference"/>
|
||||||
|
<xs:element ref="fhir:Encounter"/>
|
||||||
|
<xs:element ref="fhir:FamilyHistory"/>
|
||||||
|
<xs:element ref="fhir:Group"/>
|
||||||
|
<xs:element ref="fhir:ImagingStudy"/>
|
||||||
|
<xs:element ref="fhir:Immunization"/>
|
||||||
|
<xs:element ref="fhir:ImmunizationRecommendation"/>
|
||||||
|
<xs:element ref="fhir:List"/>
|
||||||
|
<xs:element ref="fhir:Location"/>
|
||||||
|
<xs:element ref="fhir:Media"/>
|
||||||
|
<xs:element ref="fhir:Medication"/>
|
||||||
|
<xs:element ref="fhir:MedicationAdministration"/>
|
||||||
|
<xs:element ref="fhir:MedicationDispense"/>
|
||||||
|
<xs:element ref="fhir:MedicationPrescription"/>
|
||||||
|
<xs:element ref="fhir:MedicationStatement"/>
|
||||||
|
<xs:element ref="fhir:MessageHeader"/>
|
||||||
|
<xs:element ref="fhir:Observation"/>
|
||||||
|
<xs:element ref="fhir:OperationOutcome"/>
|
||||||
|
<xs:element ref="fhir:Order"/>
|
||||||
|
<xs:element ref="fhir:OrderResponse"/>
|
||||||
|
<xs:element ref="fhir:Organization"/>
|
||||||
|
<xs:element ref="fhir:Other"/>
|
||||||
|
<xs:element ref="fhir:Patient"/>
|
||||||
|
<xs:element ref="fhir:Practitioner"/>
|
||||||
|
<xs:element ref="fhir:Procedure"/>
|
||||||
|
<xs:element ref="fhir:Profile"/>
|
||||||
|
<xs:element ref="fhir:Provenance"/>
|
||||||
|
<xs:element ref="fhir:Query"/>
|
||||||
|
<xs:element ref="fhir:Questionnaire"/>
|
||||||
|
<xs:element ref="fhir:RelatedPerson"/>
|
||||||
|
<xs:element ref="fhir:SecurityEvent"/>
|
||||||
|
<xs:element ref="fhir:Specimen"/>
|
||||||
|
<xs:element ref="fhir:Substance"/>
|
||||||
|
<xs:element ref="fhir:Supply"/>
|
||||||
|
<xs:element ref="fhir:ValueSet"/>
|
||||||
|
|
||||||
|
</xs:choice>
|
||||||
|
<xs:attribute name="type" type="xs:string"/>
|
||||||
|
<xs:attributeGroup ref="atom:CommonAttributes"/>
|
||||||
|
</xs:complexType>
|
||||||
|
<xs:complexType name="UriType">
|
||||||
|
<xs:simpleContent>
|
||||||
|
<xs:extension base="xs:anyURI">
|
||||||
|
<xs:attributeGroup ref="atom:CommonAttributes"/>
|
||||||
|
</xs:extension>
|
||||||
|
</xs:simpleContent>
|
||||||
|
</xs:complexType>
|
||||||
|
<xs:complexType name="LinkType" mixed="true">
|
||||||
|
<xs:attribute name="href" type="xs:anyURI" use="required"/>
|
||||||
|
<xs:attribute name="rel" type="xs:string" use="optional"/>
|
||||||
|
<xs:attribute name="type" type="xs:string" use="optional"/>
|
||||||
|
<xs:attribute name="hreflang" type="xs:NMTOKEN" use="optional"/>
|
||||||
|
<xs:attribute name="title" type="xs:string" use="optional"/>
|
||||||
|
<xs:attribute name="length" type="xs:positiveInteger" use="optional"/>
|
||||||
|
<xs:attributeGroup ref="atom:CommonAttributes"/>
|
||||||
|
</xs:complexType>
|
||||||
|
<xs:complexType name="IdType">
|
||||||
|
<xs:simpleContent>
|
||||||
|
<xs:extension base="xs:anyURI">
|
||||||
|
<xs:attributeGroup ref="atom:CommonAttributes"/>
|
||||||
|
</xs:extension>
|
||||||
|
</xs:simpleContent>
|
||||||
|
</xs:complexType>
|
||||||
|
<xs:complexType name="DateTimeType">
|
||||||
|
<xs:simpleContent>
|
||||||
|
<xs:extension base="xs:dateTime">
|
||||||
|
<xs:attributeGroup ref="atom:CommonAttributes"/>
|
||||||
|
</xs:extension>
|
||||||
|
</xs:simpleContent>
|
||||||
|
</xs:complexType>
|
||||||
|
<xs:attributeGroup name="CommonAttributes">
|
||||||
|
<xs:attribute ref="xml:base"/>
|
||||||
|
<xs:attribute ref="xml:lang"/>
|
||||||
|
</xs:attributeGroup>
|
||||||
|
</xs:schema>
|
|
@ -23,8 +23,8 @@ public class ResourceValidatorTest {
|
||||||
Patient p = ourCtx.newXmlParser().parseResource(Patient.class, res);
|
Patient p = ourCtx.newXmlParser().parseResource(Patient.class, res);
|
||||||
|
|
||||||
FhirValidator val = ourCtx.newValidator();
|
FhirValidator val = ourCtx.newValidator();
|
||||||
val.setValidateBaseSchema(true);
|
val.setValidateAgainstStandardSchema(true);
|
||||||
val.setValidateBaseSchematron(false);
|
val.setValidateAgainstStandardSchematron(false);
|
||||||
|
|
||||||
val.validate(p);
|
val.validate(p);
|
||||||
|
|
||||||
|
@ -49,8 +49,8 @@ public class ResourceValidatorTest {
|
||||||
Patient p = ourCtx.newXmlParser().parseResource(Patient.class, res);
|
Patient p = ourCtx.newXmlParser().parseResource(Patient.class, res);
|
||||||
|
|
||||||
FhirValidator val = ourCtx.newValidator();
|
FhirValidator val = ourCtx.newValidator();
|
||||||
val.setValidateBaseSchema(false);
|
val.setValidateAgainstStandardSchema(false);
|
||||||
val.setValidateBaseSchematron(true);
|
val.setValidateAgainstStandardSchematron(true);
|
||||||
|
|
||||||
val.validate(p);
|
val.validate(p);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue