use of org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent in project kindling by HL7.
the class ResourceValidator method check.
// private List<ValidationMessage> check(String n, BindingSpecification cd) throws Exception {
// List<ValidationMessage> errors = new ArrayList<ValidationMessage>();
// check(errors, n, cd);
// return errors;
// }
private void check(List<ValidationMessage> errors, String path, BindingSpecification cd, String sd, ElementDefn e) throws Exception {
// basic integrity checks
List<DefinedCode> ac = cd.getAllCodes(definitions.getCodeSystems(), definitions.getValuesets(), false);
for (DefinedCode c : ac) {
String d = c.getCode();
if (Utilities.noString(d))
d = c.getId();
if (Utilities.noString(d))
d = c.getDisplay();
if (Utilities.noString(d))
d = c.getDisplay();
if (Utilities.noString(c.getSystem()))
warning(errors, IssueType.STRUCTURE, "Binding @ " + path, !Utilities.noString(c.getDefinition()), "Code " + d + " must have a definition");
rule(errors, IssueType.STRUCTURE, "Binding @ " + path, !(Utilities.noString(c.getId()) && Utilities.noString(c.getSystem())), "Code " + d + " must have a id or a system");
}
// trigger processing into a Heirachical set if necessary
// rule(errors, IssueType.STRUCTURE, "Binding @ "+path, !cd.isHeirachical() || (cd.getChildCodes().size() < cd.getCodes().size()), "Logic error processing Hirachical code set");
// now, rules for the source
hint(errors, IssueType.STRUCTURE, "Binding @ " + path, cd.getBinding() != BindingMethod.Unbound, "Need to provide a binding");
rule(errors, IssueType.STRUCTURE, "Binding @ " + path, Utilities.noString(cd.getDefinition()) || (cd.getDefinition().charAt(0) == cd.getDefinition().toUpperCase().charAt(0)), "Definition cannot start with a lowercase letter");
if (cd.getBinding() == BindingMethod.CodeList || (cd.getBinding() == BindingMethod.ValueSet && cd.getStrength() == BindingStrength.REQUIRED && ac.size() > 0 && "code".equals(e.typeCode()))) {
if (path.toLowerCase().endsWith("status")) {
if (rule(errors, IssueType.STRUCTURE, path, definitions.getStatusCodes().containsKey(path), "Status element not registered in status-codes.xml")) {
// rule(errors, IssueType.STRUCTURE, path, e.isModifier(), "Status elements that map to status-codes should be labelled as a modifier");
ArrayList<String> list = definitions.getStatusCodes().get(path);
for (DefinedCode c : ac) {
boolean ok = false;
for (String s : list) {
String[] parts = s.split("\\,");
for (String p : parts) if (p.trim().equals(c.getCode()))
ok = true;
}
rule(errors, IssueType.STRUCTURE, path, ok, "Status element code \"" + c.getCode() + "\" not found in status-codes.xml");
}
for (String s : list) {
String[] parts = s.split("\\,");
for (String p : parts) {
List<String> cl = new ArrayList<>();
if (!Utilities.noString(p)) {
boolean ok = false;
for (DefinedCode c : ac) {
cl.add(c.getCode());
if (p.trim().equals(c.getCode()))
ok = true;
}
if (!ok)
rule(errors, IssueType.STRUCTURE, path, ok, "Status element code \"" + p + "\" found for " + path + " in status-codes.xml but has no matching code in the resource (codes = " + cl + ")");
}
}
}
}
}
StringBuilder b = new StringBuilder();
for (DefinedCode c : ac) {
if (!c.getAbstract())
b.append(" | ").append(c.getCode());
}
if (sd.equals("*")) {
e.setShortDefn(b.toString().substring(3));
sd = b.toString().substring(3);
}
if (sd.contains("|")) {
if (b.length() < 3)
throw new Error("surprise");
String esd = b.substring(3);
rule(errors, IssueType.STRUCTURE, path, sd.startsWith(esd) || (sd.endsWith("+") && b.substring(3).startsWith(sd.substring(0, sd.length() - 1))), "The short description \"" + sd + "\" does not match the expected (\"" + b.substring(3) + "\")");
} else {
rule(errors, IssueType.STRUCTURE, path, cd.getStrength() != BindingStrength.REQUIRED || ac.size() > 12 || ac.size() <= 1 || !hasGoodCode(ac) || isExemptFromCodeList(path), "The short description of an element with a code list should have the format code | code | etc (is " + sd.toString() + ") (" + ac.size() + " codes = \"" + b.toString() + "\")");
}
}
boolean isComplex = !e.typeCode().equals("code");
if (isComplex && cd.getValueSet() != null && hasInternalReference(cd.getValueSet()) && cd.getStrength() != BindingStrength.EXAMPLE) {
hint(errors, IssueType.BUSINESSRULE, path, false, "The value " + cd.getValueSet().getUrl() + " defines codes, but is used by a Coding/CodeableConcept @ " + path + ", so it should not use FHIR defined codes");
cd.getValueSet().setUserData("vs-val-warned", true);
}
if (cd.getElementType() == ElementType.Unknown) {
if (isComplex)
cd.setElementType(ElementType.Complex);
else
cd.setElementType(ElementType.Simple);
} else if (isComplex && !cd.hasMax())
rule(errors, IssueType.STRUCTURE, path, cd.getElementType() == ElementType.Complex, "Cannot use a binding from both code and Coding/CodeableConcept elements");
else
rule(errors, IssueType.STRUCTURE, path, cd.getElementType() == ElementType.Simple, "Cannot use a binding from both code and Coding/CodeableConcept elements");
if (isComplex && cd.getValueSet() != null) {
for (ConceptSetComponent inc : cd.getValueSet().getCompose().getInclude()) if (inc.hasSystem())
txurls.add(inc.getSystem());
}
rule(errors, IssueType.STRUCTURE, "Binding @ " + path, (cd.getElementType() != ElementType.Simple || cd.getStrength() == BindingStrength.REQUIRED || cd.hasMax()) || isExemptFromProperBindingRules(path), "Must be a required binding if bound to a code instead of a Coding/CodeableConcept");
rule(errors, IssueType.STRUCTURE, "Binding @ " + path, cd.getElementType() != ElementType.Simple || cd.getBinding() != BindingMethod.Unbound, "Need to provide a binding for code elements");
if (!isComplex && !externalException(path)) {
ValueSet vs = cd.getValueSet();
if (warning(errors, IssueType.REQUIRED, path, vs != null || cd.hasReference(), "Unable to resolve value set on 'code' Binding")) {
hint(errors, IssueType.REQUIRED, path, noExternals(vs), "Bindings for code data types should only use internally defined codes (" + vs.getUrl() + ")");
// don't disable this without discussion on Zulip
}
}
}
use of org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent in project kindling by HL7.
the class ValueSetValidator method validate.
public void validate(List<ValidationMessage> errors, String nameForErrors, ValueSet vs, boolean internal, boolean exemptFromCopyrightRule) throws FHIRException {
int o_warnings = 0;
for (ValidationMessage em : errors) {
if (em.getLevel() == IssueSeverity.WARNING)
o_warnings++;
}
if (!handled.contains(vs.getId())) {
handled.add(vs.getId());
duplicateList.add(new VSDuplicateList(vs));
}
String oid = getOid(vs);
if (oid != null) {
if (!oids.containsKey(oid)) {
oids.put(oid, vs);
} else
rule(errors, IssueType.DUPLICATE, getWg(vs) + ":ValueSet[" + vs.getId() + "]", oid.endsWith(".0") || oids.get(oid).getUrl().equals(vs.getUrl()), "Duplicate OID for " + oid + " on " + oids.get(oid).getUrl() + " and " + vs.getUrl());
}
rule(errors, IssueType.BUSINESSRULE, getWg(vs) + ":ValueSet[" + vs.getId() + "]", vs.hasDescription(), "Value Sets in the build must have a description");
if (Utilities.noString(vs.getCopyright()) && !exemptFromCopyrightRule) {
Set<String> sources = getListOfSources(vs);
for (String s : sources) {
ruleHtml(errors, IssueType.BUSINESSRULE, getWg(vs) + ":ValueSet[" + vs.getId() + "].copyright", !s.equals("http://snomed.info/sct") && !s.equals("http://loinc.org"), "Value set " + nameForErrors + " (" + vs.getName() + "): A copyright statement is required for any value set that includes Snomed or Loinc codes", "<a href=\"" + vs.getUserString("path") + "\">Value set " + nameForErrors + " (" + vs.getName() + ")</a>: A copyright statement is required for any value set that includes Snomed or Loinc codes");
warning(errors, IssueType.BUSINESSRULE, getWg(vs) + ":ValueSet[" + vs.getId() + "].copyright", s.startsWith("http://hl7.org") || s.startsWith("http://terminology.hl7.org") || s.startsWith("urn:iso") || s.startsWith("urn:ietf") || s.startsWith("http://need.a.uri.org") || s.contains("cdc.gov") || s.startsWith("urn:oid:"), "Value set " + nameForErrors + " (" + vs.getName() + "): A copyright statement should be present for any value set that includes non-HL7 sourced codes (" + s + ")", "<a href=\"" + vs.getUserString("path") + "\">Value set " + nameForErrors + " (" + vs.getName() + ")</a>: A copyright statement should be present for any value set that includes non-HL7 sourced codes (" + s + ")");
}
}
if (vs.hasCompose()) {
if (!context.hasResource(CodeSystem.class, "http://terminology.hl7.org/CodeSystem/data-absent-reason") && !vs.getUrl().contains("v3") && !vs.getUrl().contains("v2"))
throw new Error("d-a-r not found");
int i = 0;
for (ConceptSetComponent inc : vs.getCompose().getInclude()) {
i++;
checkValueSetCode(errors, nameForErrors, vs, i, inc);
}
}
int warnings = 0;
for (ValidationMessage em : errors) {
if (em.getLevel() == IssueSeverity.WARNING)
warnings++;
}
vs.setUserData("warnings", o_warnings - warnings);
}
use of org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent in project kindling by HL7.
the class PageProcessor method sourceSummary.
private String sourceSummary(ValueSet vs) {
StringBuilder b = new StringBuilder();
List<String> done = new ArrayList<String>();
if (vs.hasCompose())
for (ConceptSetComponent c : vs.getCompose().getInclude()) {
String uri = c.getSystem();
String n = "Other";
if (uri != null) {
if ("http://snomed.info/sct".equals(uri))
n = "SNOMED CT";
if ("http://loinc.org".equals(uri))
n = "LOINC";
if ("http://dicom.nema.org/resources/ontology/DCM".equals(uri))
n = "DICOM";
if ("http://hl7.org/fhir/resource-types".equals(uri))
n = "FHIR";
if ("http://hl7.org/fhir/restful-interaction".equals(uri))
n = "FHIR";
if ("http://unitsofmeasure.org".equals(uri))
n = "FHIR";
if (uri.startsWith("http://terminology.hl7.org/CodeSystem/v3-"))
n = "V3";
else if (uri.startsWith("http://terminology.hl7.org/CodeSystem/v2-"))
n = "V2";
else if (uri.startsWith("http://hl7.org/fhir"))
n = "Internal";
}
if (!done.contains(n))
b.append(", ").append(n);
done.add(n);
}
return b.length() == 0 ? "" : b.substring(2);
}
use of org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent in project kindling by HL7.
the class PageProcessor method genScList.
private String genScList(String path) throws Exception {
ResourceDefn r = definitions.getResourceByName(path.substring(0, path.indexOf(".")));
if (r == null)
throw new Exception("Unable to process sclist (1): " + path);
ElementDefn e = r.getRoot().getElementByName(definitions, path.substring(path.indexOf(".") + 1), true, false);
if (e == null)
throw new Exception("Unable to process sclist (2): " + path);
if (e.typeCode().equals("boolean"))
return "true | false";
else {
StringBuilder b = new StringBuilder();
boolean first = true;
for (ConceptSetComponent inc : e.getBinding().getValueSet().getCompose().getInclude()) {
CodeSystem cs = definitions.getCodeSystems().get(inc.getSystem());
if (cs != null) {
for (ConceptDefinitionComponent cc : cs.getConcept()) {
if (first)
first = false;
else
b.append(" | ");
b.append("<span title=\"" + cc.getDisplay() + ": " + Utilities.escapeXml(cc.getDefinition()) + "\">" + cc.getCode() + "</span>");
}
}
}
return b.toString();
}
}
use of org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent in project kindling by HL7.
the class PageProcessor method generateCSUsage.
private String generateCSUsage(CodeSystem cs, String prefix) throws Exception {
StringBuilder b = new StringBuilder();
for (ValueSet vs : definitions.getValuesets().getList()) {
boolean uses = false;
for (ConceptSetComponent inc : vs.getCompose().getInclude()) {
if (inc.hasSystem() && inc.getSystem().equals(cs.getUrl()))
uses = true;
}
for (ConceptSetComponent inc : vs.getCompose().getExclude()) {
if (inc.hasSystem() && inc.getSystem().equals(cs.getUrl()))
uses = true;
}
if (uses) {
if (vs.hasUserData("external.url"))
b.append(" <li>ValueSet: <a href=\"").append(vs.getUserString("external.url")).append("\">").append(vs.present()).append("</a> (").append(Utilities.escapeXml(vs.getDescription())).append(")</li>\r\n");
else if (!vs.hasUserData("path"))
b.append(" <li>ValueSet: <a href=\"").append(prefix + "valueset-" + vs.getId()).append("\">").append(vs.present()).append("</a> (").append(Utilities.escapeXml(vs.getDescription())).append(")</li>\r\n");
else
b.append(" <li>ValueSet: <a href=\"").append(prefix + vs.getUserString("path")).append("\">").append(vs.present()).append("</a> (").append(Utilities.escapeXml(vs.getDescription())).append(")</li>\r\n");
}
}
if (b.length() == 0)
return "<p>\r\nThis Code system is not currently used\r\n</p>\r\n";
else
return "<p>\r\nThis Code system is used in the following value sets:\r\n</p>\r\n<ul>\r\n" + b.toString() + "</ul>\r\n";
}
Aggregations