From bfac7f06deb2bd2c5a1412e93631635704fa74b3 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Sat, 2 Sep 2023 23:21:32 +0700 Subject: [PATCH 1/8] Add SHLinks validation --- org.hl7.fhir.r5/pom.xml | 8 + .../hl7/fhir/r5/elementmodel/FmlParser.java | 15 +- .../hl7/fhir/r5/elementmodel/JsonParser.java | 230 ++++----- .../org/hl7/fhir/r5/elementmodel/Manager.java | 12 +- .../hl7/fhir/r5/elementmodel/ParserBase.java | 74 ++- .../hl7/fhir/r5/elementmodel/SHCParser.java | 68 +-- .../hl7/fhir/r5/elementmodel/SHLParser.java | 465 ++++++++++++++++++ .../fhir/r5/elementmodel/TurtleParser.java | 82 +-- .../r5/elementmodel/VerticalBarParser.java | 8 +- .../hl7/fhir/r5/elementmodel/XmlParser.java | 98 ++-- .../CommaSeparatedStringBuilder.java | 8 + .../hl7/fhir/utilities/SimpleHTTPClient.java | 8 +- .../hl7/fhir/validation/ResourceChecker.java | 11 +- .../hl7/fhir/validation/ValidationEngine.java | 2 +- .../instance/InstanceValidator.java | 30 +- .../validation/special/R4R5MapTester.java | 2 +- .../org/hl7/fhir/r5/test/GeneralTests.java | 4 +- .../validation/tests/ValidationTests.java | 10 +- .../org.hl7.fhir.validation/4.0.1/cvx.cache | 223 ++++++++- .../4.0.1/http___standardterms.edqm.eu.cache | 22 + .../4.0.1/iso3166.cache | 24 +- .../org.hl7.fhir.validation/4.0.1/loinc.cache | 312 ++++++------ .../4.0.1/rxnorm.cache | 25 +- .../4.0.1/snomed.cache | 184 +++---- pom.xml | 9 +- 25 files changed, 1361 insertions(+), 573 deletions(-) create mode 100644 org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHLParser.java diff --git a/org.hl7.fhir.r5/pom.xml b/org.hl7.fhir.r5/pom.xml index 445335aa9..fd68ac629 100644 --- a/org.hl7.fhir.r5/pom.xml +++ b/org.hl7.fhir.r5/pom.xml @@ -172,12 +172,20 @@ 4.12 test + + + com.nimbusds + nimbus-jose-jwt + 9.30.2 + + net.sourceforge.plantuml plantuml-mit 1.2023.9 compile + diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/FmlParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/FmlParser.java index 972840a08..87bbf5f0d 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/FmlParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/FmlParser.java @@ -1,5 +1,6 @@ package org.hl7.fhir.r5.elementmodel; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -44,10 +45,14 @@ public class FmlParser extends ParserBase { } @Override - public List parse(InputStream stream) throws IOException, FHIRFormatError, DefinitionException, FHIRException { + public List parse(InputStream inStream) throws IOException, FHIRFormatError, DefinitionException, FHIRException { + byte[] content = TextFile.streamToBytes(inStream); + ByteArrayInputStream stream = new ByteArrayInputStream(content); String text = TextFile.streamToString(stream); List result = new ArrayList<>(); - result.add(new NamedElement(null, parse(text))); + NamedElement ctxt = new NamedElement("fml", content); + ctxt.setElement(parse(ctxt.getErrors(), text)); + result.add(ctxt); return result; } @@ -57,7 +62,7 @@ public class FmlParser extends ParserBase { throw new Error("Not done yet"); } - public Element parse(String text) throws FHIRException { + public Element parse(List errors, String text) throws FHIRException { FHIRLexer lexer = new FHIRLexer(text, "source", true, true); if (lexer.done()) throw lexer.error("Map Input cannot be empty"); @@ -112,13 +117,13 @@ public class FmlParser extends ParserBase { if (policy == ValidationPolicy.NONE) { throw e; } else { - logError("2023-02-24", e.getLocation().getLine(), e.getLocation().getColumn(), "??", IssueType.INVALID, e.getMessage(), IssueSeverity.FATAL); + logError(errors, "2023-02-24", e.getLocation().getLine(), e.getLocation().getColumn(), "??", IssueType.INVALID, e.getMessage(), IssueSeverity.FATAL); } } catch (Exception e) { if (policy == ValidationPolicy.NONE) { throw e; } else { - logError("2023-02-24", -1, -1, "?", IssueType.INVALID, e.getMessage(), IssueSeverity.FATAL); + logError(errors, "2023-02-24", -1, -1, "?", IssueType.INVALID, e.getMessage(), IssueSeverity.FATAL); } } result.setIgnorePropertyOrder(true); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java index ad0752524..770dd311d 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java @@ -1,5 +1,7 @@ package org.hl7.fhir.r5.elementmodel; +import java.io.ByteArrayInputStream; + /* Copyright (c) 2011+, HL7, Inc. All rights reserved. @@ -50,6 +52,7 @@ import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; import org.hl7.fhir.r5.context.ContextUtilities; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.elementmodel.Element.SpecialElement; +import org.hl7.fhir.r5.elementmodel.ParserBase.NamedElement; import org.hl7.fhir.r5.formats.IParser.OutputStyle; import org.hl7.fhir.r5.formats.JsonCreator; import org.hl7.fhir.r5.formats.JsonCreatorCanonical; @@ -95,63 +98,66 @@ public class JsonParser extends ParserBase { this.profileUtilities = new ProfileUtilities(this.context, null, null, new FHIRPathEngine(context)); } - - public Element parse(String source, String type) throws Exception { - JsonObject obj = org.hl7.fhir.utilities.json.parser.JsonParser.parseObject(source, true, true); - String path = "/"+type; - StructureDefinition sd = getDefinition(-1, -1, type); - if (sd == null) - return null; - - Element result = new Element(type, new Property(context, sd.getSnapshot().getElement().get(0), sd, this.profileUtilities)); - result.setPath(type); - checkObject(obj, result, path); - result.setType(type); - parseChildren(path, obj, result, true); - result.numberChildren(); - return result; - } +// +// public Element parse(String source, String type) throws Exception { +// JsonObject obj = org.hl7.fhir.utilities.json.parser.JsonParser.parseObject(source, true, true); +// String path = "/"+type; +// StructureDefinition sd = getDefinition(-1, -1, type); +// if (sd == null) +// return null; +// +// Element result = new Element(type, new Property(context, sd.getSnapshot().getElement().get(0), sd, this.profileUtilities)); +// result.setPath(type); +// checkObject(obj, result, path); +// result.setType(type); +// parseChildren(path, obj, result, true); +// result.numberChildren(); +// return result; +// } @Override - public List parse(InputStream stream) throws IOException, FHIRException { + public List parse(InputStream inStream) throws IOException, FHIRException { + byte[] content = TextFile.streamToBytes(inStream); + NamedElement ctxt = new NamedElement("json", content); + + ByteArrayInputStream stream = new ByteArrayInputStream(content); + // if we're parsing at this point, then we're going to use the custom parser - List res = new ArrayList<>(); String source = TextFile.streamToString(stream); JsonObject obj = null; if (policy == ValidationPolicy.EVERYTHING) { try { obj = org.hl7.fhir.utilities.json.parser.JsonParser.parseObject(source, true, true); } catch (Exception e) { - logError(ValidationMessage.NO_RULE_DATE, -1, -1,context.formatMessage(I18nConstants.DOCUMENT), IssueType.INVALID, context.formatMessage(I18nConstants.ERROR_PARSING_JSON_, e.getMessage()), IssueSeverity.FATAL); - return null; + logError(ctxt.getErrors(), ValidationMessage.NO_RULE_DATE, -1, -1,context.formatMessage(I18nConstants.DOCUMENT), IssueType.INVALID, context.formatMessage(I18nConstants.ERROR_PARSING_JSON_, e.getMessage()), IssueSeverity.FATAL); } } else { obj = org.hl7.fhir.utilities.json.parser.JsonParser.parseObject(source, true, true); } - Element e = parse(obj); - if (e != null) { - res.add(new NamedElement(null, e)); - } + ctxt.setElement(parse(ctxt.getErrors(), obj)); + + List res = new ArrayList<>(); + res.add(ctxt); return res; } - public Element parse(JsonObject object) throws FHIRException { + public Element parse(List errors, JsonObject object) throws FHIRException { StructureDefinition sd = getLogical(); String name; String path; if (sd == null) { JsonElement rt = object.get("resourceType"); if (rt == null) { - logError(ValidationMessage.NO_RULE_DATE, line(object), col(object), "$", IssueType.INVALID, context.formatMessage(I18nConstants.UNABLE_TO_FIND_RESOURCETYPE_PROPERTY), IssueSeverity.FATAL); + logError(errors, ValidationMessage.NO_RULE_DATE, line(object), col(object), "$", IssueType.INVALID, context.formatMessage(I18nConstants.UNABLE_TO_FIND_RESOURCETYPE_PROPERTY), IssueSeverity.FATAL); return null; } else if (!rt.isJsonString()) { - logError("2022-11-26", line(object), col(object), "$", IssueType.INVALID, context.formatMessage(I18nConstants.RESOURCETYPE_PROPERTY_WRONG_TYPE, rt.type().toName()), IssueSeverity.FATAL); + logError(errors, "2022-11-26", line(object), col(object), "$", IssueType.INVALID, context.formatMessage(I18nConstants.RESOURCETYPE_PROPERTY_WRONG_TYPE, rt.type().toName()), IssueSeverity.FATAL); return null; } else { name = rt.asString(); - sd = getDefinition(line(object), col(object), name); + sd = getDefinition(errors, line(object), col(object), name); if (sd == null) { return null; } @@ -162,25 +168,25 @@ public class JsonParser extends ParserBase { path = sd.getTypeTail(); } baseElement = new Element(name, new Property(context, sd.getSnapshot().getElement().get(0), sd, this.profileUtilities)); - checkObject(object, baseElement, path); + checkObject(errors, object, baseElement, path); baseElement.markLocation(line(object), col(object)); baseElement.setType(name); baseElement.setPath(baseElement.fhirTypeRoot()); - parseChildren(path, object, baseElement, true); + parseChildren(errors, path, object, baseElement, true); baseElement.numberChildren(); return baseElement; } - private void checkObject(JsonObject object, Element b, String path) { - checkComments(object, b, path); + private void checkObject(List errors, JsonObject object, Element b, String path) { + checkComments(errors, object, b, path); if (policy == ValidationPolicy.EVERYTHING) { if (object.getProperties().size() == 0) { - logError(ValidationMessage.NO_RULE_DATE, line(object), col(object), path, IssueType.INVALID, context.formatMessage(I18nConstants.OBJECT_MUST_HAVE_SOME_CONTENT), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(object), col(object), path, IssueType.INVALID, context.formatMessage(I18nConstants.OBJECT_MUST_HAVE_SOME_CONTENT), IssueSeverity.ERROR); } } } - private void checkComments(JsonElement element, Element b, String path) throws FHIRFormatError { + private void checkComments(List errors, JsonElement element, Element b, String path) throws FHIRFormatError { if (element != null && element.hasComments()) { if (allowComments) { for (JsonComment c : element.getComments()) { @@ -188,13 +194,13 @@ public class JsonParser extends ParserBase { } } else { for (JsonComment c : element.getComments()) { - logError("2022-11-26", c.getStart().getLine(), c.getStart().getCol(), path, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_COMMENTS_NOT_ALLOWED), IssueSeverity.ERROR); + logError(errors, "2022-11-26", c.getStart().getLine(), c.getStart().getCol(), path, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_COMMENTS_NOT_ALLOWED), IssueSeverity.ERROR); } } } } - private void parseChildren(String path, JsonObject object, Element element, boolean hasResourceType) throws FHIRException { + private void parseChildren(List errors, String path, JsonObject object, Element element, boolean hasResourceType) throws FHIRException { reapComments(object, element); List properties = element.getProperty().getChildProperties(element.getName(), null); Set processed = new HashSet(); @@ -205,13 +211,13 @@ public class JsonParser extends ParserBase { Set unique = new HashSet<>(); for (JsonProperty p : object.getProperties()) { if (p.isUnquotedName()) { - logError("2022-11-26", line(p.getValue()), col(p.getValue()), path, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_PROPERTY_NO_QUOTES, p.getName()), IssueSeverity.ERROR); + logError(errors, "2022-11-26", line(p.getValue()), col(p.getValue()), path, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_PROPERTY_NO_QUOTES, p.getName()), IssueSeverity.ERROR); } if (p.isNoComma()) { - logError("2022-11-26", line(p.getValue()), col(p.getValue()), path, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_COMMA_MISSING), IssueSeverity.ERROR); + logError(errors, "2022-11-26", line(p.getValue()), col(p.getValue()), path, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_COMMA_MISSING), IssueSeverity.ERROR); } if (unique.contains(p.getName())) { - logError("2022-11-26", line(p.getValue()), col(p.getValue()), path, IssueType.INVALID, context.formatMessage(I18nConstants.DUPLICATE_JSON_PROPERTY, p.getName()), IssueSeverity.ERROR); + logError(errors, "2022-11-26", line(p.getValue()), col(p.getValue()), path, IssueType.INVALID, context.formatMessage(I18nConstants.DUPLICATE_JSON_PROPERTY, p.getName()), IssueSeverity.ERROR); } else { unique.add(p.getName()); recognisedChildren.put(p.getName(), p); @@ -221,7 +227,7 @@ public class JsonParser extends ParserBase { // note that we do not trouble ourselves to maintain the wire format order here - we don't even know what it was anyway // first pass: process the properties for (Property property : properties) { - parseChildItem(path, recognisedChildren, element, processed, property); + parseChildItem(errors, path, recognisedChildren, element, processed, property); } // second pass: check for things not processed @@ -231,32 +237,32 @@ public class JsonParser extends ParserBase { StructureDefinition sd = element.getProperty().isLogical() ? new ContextUtilities(context).fetchByJsonName(e.getKey()) : null; if (sd != null) { Property property = new Property(context, sd.getSnapshot().getElementFirstRep(), sd, element.getProperty().getUtils()); - parseChildItem(path, recognisedChildren, element, null, property); + parseChildItem(errors, path, recognisedChildren, element, null, property); } else if ("fhir_comments".equals(e.getKey()) && (VersionUtilities.isR2BVer(context.getVersion()) || VersionUtilities.isR2Ver(context.getVersion()))) { if (!e.getValue().getValue().isJsonArray()) { - logError("2022-12-17", line(e.getValue().getValue()), col(e.getValue().getValue()), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.ILLEGAL_COMMENT_TYPE, e.getValue().getValue().type().toName()), IssueSeverity.ERROR); + logError(errors, "2022-12-17", line(e.getValue().getValue()), col(e.getValue().getValue()), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.ILLEGAL_COMMENT_TYPE, e.getValue().getValue().type().toName()), IssueSeverity.ERROR); } else { for (JsonElement c : e.getValue().getValue().asJsonArray()) { if (!c.isJsonString()) { - logError("2022-12-17", line(e.getValue().getValue()), col(e.getValue().getValue()), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.ILLEGAL_COMMENT_TYPE, c.type().toName()), IssueSeverity.ERROR); + logError(errors, "2022-12-17", line(e.getValue().getValue()), col(e.getValue().getValue()), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.ILLEGAL_COMMENT_TYPE, c.type().toName()), IssueSeverity.ERROR); } else { element.getComments().add(c.asString()); } } } } else { - logError(ValidationMessage.NO_RULE_DATE, line(e.getValue().getValue()), col(e.getValue().getValue()), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.UNRECOGNISED_PROPERTY_, e.getKey()), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(e.getValue().getValue()), col(e.getValue().getValue()), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.UNRECOGNISED_PROPERTY_, e.getKey()), IssueSeverity.ERROR); } } } } if (object.isExtraComma()) { - logError("2022-11-26", object.getEnd().getLine(), object.getEnd().getCol(), path, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_COMMA_EXTRA, "Object"), IssueSeverity.ERROR); + logError(errors, "2022-11-26", object.getEnd().getLine(), object.getEnd().getCol(), path, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_COMMA_EXTRA, "Object"), IssueSeverity.ERROR); } } - public void parseChildItem(String path, Map children, Element context, Set processed, Property property) { + public void parseChildItem(List errors, String path, Map children, Element context, Set processed, Property property) { if (property.isChoice() || property.getDefinition().getPath().endsWith("data[x]")) { if (property.isJsonPrimitiveChoice()) { if (children.containsKey(property.getJsonName())) { @@ -264,30 +270,30 @@ public class JsonParser extends ParserBase { if (processed != null) processed.add(property.getJsonName()); String type = getTypeFromJsonType(je); if (type == null) { - logError(ValidationMessage.NO_RULE_DATE, line(je), col(je), path, IssueType.STRUCTURE, this.context.formatMessage(I18nConstants.UNRECOGNISED_PROPERTY_TYPE, describeType(je), property.getName(), property.typeSummary()), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(je), col(je), path, IssueType.STRUCTURE, this.context.formatMessage(I18nConstants.UNRECOGNISED_PROPERTY_TYPE, describeType(je), property.getName(), property.typeSummary()), IssueSeverity.ERROR); } else if (property.hasType(type)) { Property np = new Property(property.getContext(), property.getDefinition(), property.getStructure(), property.getUtils(), type); - parseChildPrimitive(children, context, processed, np, path, property.getName(), false); + parseChildPrimitive(errors, children, context, processed, np, path, property.getName(), false); } else { - logError(ValidationMessage.NO_RULE_DATE, line(je), col(je), path, IssueType.STRUCTURE, this.context.formatMessage(I18nConstants.UNRECOGNISED_PROPERTY_TYPE_WRONG, describeType(je), property.getName(), type, property.typeSummary()), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(je), col(je), path, IssueType.STRUCTURE, this.context.formatMessage(I18nConstants.UNRECOGNISED_PROPERTY_TYPE_WRONG, describeType(je), property.getName(), type, property.typeSummary()), IssueSeverity.ERROR); } } } else { for (TypeRefComponent type : property.getDefinition().getType()) { String eName = property.getJsonName().substring(0, property.getName().length()-3) + Utilities.capitalize(type.getWorkingCode()); if (!isPrimitive(type.getWorkingCode()) && children.containsKey(eName)) { - parseChildComplex(path, children, context, processed, property, eName, false); + parseChildComplex(errors, path, children, context, processed, property, eName, false); break; } else if (isPrimitive(type.getWorkingCode()) && (children.containsKey(eName) || children.containsKey("_"+eName))) { - parseChildPrimitive(children, context, processed, property, path, eName, false); + parseChildPrimitive(errors, children, context, processed, property, path, eName, false); break; } } } } else if (property.isPrimitive(property.getType(null))) { - parseChildPrimitive(children, context, processed, property, path, property.getJsonName(), property.hasJsonName()); + parseChildPrimitive(errors, children, context, processed, property, path, property.getJsonName(), property.hasJsonName()); } else if (children.containsKey(property.getJsonName())) { - parseChildComplex(path, children, context, processed, property, property.getJsonName(), property.hasJsonName()); + parseChildComplex(errors, path, children, context, processed, property, property.getJsonName(), property.hasJsonName()); } } @@ -311,7 +317,7 @@ public class JsonParser extends ParserBase { } } - private void parseChildComplex(String path, Map children, Element element, Set processed, Property property, String name, boolean isJsonName) throws FHIRException { + private void parseChildComplex(List errors, String path, Map children, Element element, Set processed, Property property, String name, boolean isJsonName) throws FHIRException { if (processed != null) { processed.add(name); } @@ -322,49 +328,49 @@ public class JsonParser extends ParserBase { if (property.isList() && !property.isJsonKeyArray() && (e instanceof JsonArray)) { JsonArray arr = (JsonArray) e; if (arr.isExtraComma()) { - logError("2022-11-26", arr.getEnd().getLine(), arr.getEnd().getCol(), npath, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_COMMA_EXTRA, "Array"), IssueSeverity.ERROR); + logError(errors, "2022-11-26", arr.getEnd().getLine(), arr.getEnd().getCol(), npath, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_COMMA_EXTRA, "Array"), IssueSeverity.ERROR); } if (arr.size() == 0) { if (property.canBeEmpty()) { // nothing } else { - logError(ValidationMessage.NO_RULE_DATE, line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.ARRAY_CANNOT_BE_EMPTY), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.ARRAY_CANNOT_BE_EMPTY), IssueSeverity.ERROR); } } int c = 0; for (JsonElement am : arr) { - parseChildComplexInstance(npath+"["+c+"]", fpath+"["+c+"]", element, property, name, am, c == 0 ? arr : null, path); + parseChildComplexInstance(errors, npath+"["+c+"]", fpath+"["+c+"]", element, property, name, am, c == 0 ? arr : null, path); c++; } } else if (property.isJsonKeyArray()) { String code = property.getJsonKeyProperty(); List properties = property.getChildProperties(element.getName(), null); if (properties.size() != 2) { - logError(ValidationMessage.NO_RULE_DATE, line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.OBJECT_CANNOT_BE_KEYED_ARRAY_CHILD_COUNT, propNames(properties)), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.OBJECT_CANNOT_BE_KEYED_ARRAY_CHILD_COUNT, propNames(properties)), IssueSeverity.ERROR); } else { Property propK = properties.get(0); Property propV = properties.get(1); if (!propK.getName().equals(code)) { - logError(ValidationMessage.NO_RULE_DATE, line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.OBJECT_CANNOT_BE_KEYED_ARRAY_PROP_NAME, propNames(properties)), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.OBJECT_CANNOT_BE_KEYED_ARRAY_PROP_NAME, propNames(properties)), IssueSeverity.ERROR); } else if (!propK.isPrimitive()) { - logError(ValidationMessage.NO_RULE_DATE, line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.OBJECT_CANNOT_BE_KEYED_ARRAY_PROP_TYPE, propNames(properties), propK.typeSummary()), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.OBJECT_CANNOT_BE_KEYED_ARRAY_PROP_TYPE, propNames(properties), propK.typeSummary()), IssueSeverity.ERROR); } else if (propV.isList()) { - logError(ValidationMessage.NO_RULE_DATE, line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.OBJECT_CANNOT_BE_KEYED_ARRAY_NO_LIST, propV.getName()), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.OBJECT_CANNOT_BE_KEYED_ARRAY_NO_LIST, propV.getName()), IssueSeverity.ERROR); } else if (propV.isChoice() && propV.getName().endsWith("[x]")) { - logError(ValidationMessage.NO_RULE_DATE, line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.OBJECT_CANNOT_BE_KEYED_ARRAY_NO_CHOICE, propV.getName()), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.OBJECT_CANNOT_BE_KEYED_ARRAY_NO_CHOICE, propV.getName()), IssueSeverity.ERROR); } else if (!(e instanceof JsonObject)) { - logError(ValidationMessage.NO_RULE_DATE, line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_PROPERTY_MUST_BE_AN_OBJECT_NOT_, describe(e)), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_PROPERTY_MUST_BE_AN_OBJECT_NOT_, describe(e)), IssueSeverity.ERROR); } else { JsonObject o = (JsonObject) e; if (o.isExtraComma()) { - logError("2022-11-26", o.getEnd().getLine(), o.getEnd().getCol(), npath, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_COMMA_EXTRA, "Object"), IssueSeverity.ERROR); + logError(errors, "2022-11-26", o.getEnd().getLine(), o.getEnd().getCol(), npath, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_COMMA_EXTRA, "Object"), IssueSeverity.ERROR); } int i = 0; Set names = new HashSet<>(); for (JsonProperty pv : o.getProperties()) { if (names.contains(pv.getName())) { - logError("2022-11-26", line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.DUPLICATE_JSON_PROPERTY_KEY, pv.getName()), IssueSeverity.ERROR); + logError(errors, "2022-11-26", line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.DUPLICATE_JSON_PROPERTY_KEY, pv.getName()), IssueSeverity.ERROR); } else { names.add(pv.getName()); } @@ -378,7 +384,7 @@ public class JsonParser extends ParserBase { // handle the key String fpathKey = fpathArr+"."+propK.getName(); Element nKey = new Element(code, propK).markLocation(line(pv.getValue()), col(pv.getValue())); - checkComments(pv.getValue(), n, fpathArr); + checkComments(errors, pv.getValue(), n, fpathArr); nKey.setPath(fpathKey); n.getChildren().add(nKey); nKey.setValue(pv.getName()); @@ -390,12 +396,12 @@ public class JsonParser extends ParserBase { ok = false; String type = getTypeFromJsonType(pv.getValue()); if (type == null) { - logError(ValidationMessage.NO_RULE_DATE, line(pv.getValue()), col(pv.getValue()), path, IssueType.STRUCTURE, this.context.formatMessage(I18nConstants.UNRECOGNISED_PROPERTY_TYPE, describeType(pv.getValue()), propV.getName(), propV.typeSummary()), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(pv.getValue()), col(pv.getValue()), path, IssueType.STRUCTURE, this.context.formatMessage(I18nConstants.UNRECOGNISED_PROPERTY_TYPE, describeType(pv.getValue()), propV.getName(), propV.typeSummary()), IssueSeverity.ERROR); } else if (propV.hasType(type)) { pvl = new Property(propV.getContext(), propV.getDefinition(), propV.getStructure(), propV.getUtils(), type); ok = true; } else { - logError(ValidationMessage.NO_RULE_DATE, line(pv.getValue()), col(pv.getValue()), path, IssueType.STRUCTURE, this.context.formatMessage(I18nConstants.UNRECOGNISED_PROPERTY_TYPE_WRONG, describeType(pv.getValue()), propV.getName(), type, propV.typeSummary()), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(pv.getValue()), col(pv.getValue()), path, IssueType.STRUCTURE, this.context.formatMessage(I18nConstants.UNRECOGNISED_PROPERTY_TYPE_WRONG, describeType(pv.getValue()), propV.getName(), type, propV.typeSummary()), IssueSeverity.ERROR); } } if (ok) { @@ -403,11 +409,11 @@ public class JsonParser extends ParserBase { String npathV = npathArr+"."+pvl.getName(); String fpathV = fpathArr+"."+pvl.getName(); if (propV.isPrimitive(pvl.getType(null))) { - parseChildPrimitiveInstance(n, pvl, pvl.getName(), false, npathV, fpathV, pv.getValue(), null); + parseChildPrimitiveInstance(errors, n, pvl, pvl.getName(), false, npathV, fpathV, pv.getValue(), null); } else if (pv.getValue() instanceof JsonObject || pv.getValue() instanceof JsonNull) { - parseChildComplexInstance(npathV, fpathV, n, pvl, pvl.getName(), pv.getValue(), null, null); + parseChildComplexInstance(errors, npathV, fpathV, n, pvl, pvl.getName(), pv.getValue(), null, null); } else { - logError(ValidationMessage.NO_RULE_DATE, line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_PROPERTY_MUST_BE_AN_OBJECT_NOT_, describe(pv.getValue())), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_PROPERTY_MUST_BE_AN_OBJECT_NOT_, describe(pv.getValue())), IssueSeverity.ERROR); } } i++; @@ -416,9 +422,9 @@ public class JsonParser extends ParserBase { } } else { if (property.isList()) { - logError(ValidationMessage.NO_RULE_DATE, line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_PROPERTY_MUST_BE_AN_ARRAY_NOT_, describe(e), name, path), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_PROPERTY_MUST_BE_AN_ARRAY_NOT_, describe(e), name, path), IssueSeverity.ERROR); } - parseChildComplexInstance(npath, fpath, element, property, name, e, null, null); + parseChildComplexInstance(errors, npath, fpath, element, property, name, e, null, null); } } @@ -430,7 +436,7 @@ public class JsonParser extends ParserBase { return b.toString(); } - private void parseChildComplexInstance(String npath, String fpath, Element element, Property property, String name, JsonElement e, JsonElement commentContext, String commentPath) throws FHIRException { + private void parseChildComplexInstance(List errors, String npath, String fpath, Element element, Property property, String name, JsonElement e, JsonElement commentContext, String commentPath) throws FHIRException { if (property.hasTypeSpecifier()) { FHIRPathEngine fpe = new FHIRPathEngine(context); String type = null; @@ -445,19 +451,19 @@ public class JsonParser extends ParserBase { if (type != null) { StructureDefinition sd = context.fetchResource(StructureDefinition.class, type); if (sd == null) { - logError(ValidationMessage.NO_RULE_DATE, line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.TYPE_SPECIFIER_ILLEGAL_TYPE, type, cond), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.TYPE_SPECIFIER_ILLEGAL_TYPE, type, cond), IssueSeverity.ERROR); } else { if (sd.getAbstract()) { - logError(ValidationMessage.NO_RULE_DATE, line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.TYPE_SPECIFIER_ABSTRACT_TYPE, type, cond), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.TYPE_SPECIFIER_ABSTRACT_TYPE, type, cond), IssueSeverity.ERROR); } property = property.cloneToType(sd); } } else { StructureDefinition sd = context.fetchTypeDefinition(property.getType()); if (sd == null) { - logError(ValidationMessage.NO_RULE_DATE, line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.TYPE_SPECIFIER_NM_ILLEGAL_TYPE, property.getType()), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.TYPE_SPECIFIER_NM_ILLEGAL_TYPE, property.getType()), IssueSeverity.ERROR); } else if (sd.getAbstract()) { - logError(ValidationMessage.NO_RULE_DATE, line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.TYPE_SPECIFIER_NM_ABSTRACT_TYPE, property.getType()), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.TYPE_SPECIFIER_NM_ABSTRACT_TYPE, property.getType()), IssueSeverity.ERROR); } } } @@ -465,26 +471,26 @@ public class JsonParser extends ParserBase { JsonObject child = (JsonObject) e; Element n = new Element(name, property).markLocation(line(child), col(child)); n.setPath(fpath); - checkComments(commentContext, n, commentPath); - checkObject(child, n, npath); + checkComments(errors, commentContext, n, commentPath); + checkObject(errors, child, n, npath); element.getChildren().add(n); if (property.isResource()) { - parseResource(npath, child, n, property); + parseResource(errors, npath, child, n, property); } else { - parseChildren(npath, child, n, false); + parseChildren(errors, npath, child, n, false); } } else if (property.isNullable() && e instanceof JsonNull) { // we create an element marked as a null element so we know something was present JsonNull child = (JsonNull) e; Element n = new Element(name, property).markLocation(line(child), col(child)); - checkComments(commentContext, n, commentPath); - checkComments(child, n, fpath); + checkComments(errors, commentContext, n, commentPath); + checkComments(errors, child, n, fpath); n.setPath(fpath); element.getChildren().add(n); n.setNull(true); // nothing to do, it's ok, but we treat it like it doesn't exist } else { - logError(ValidationMessage.NO_RULE_DATE, line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_PROPERTY_MUST_BE__NOT_, (property.isList() ? "an Array" : "an Object"), describe(e), name, npath), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(e), col(e), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_PROPERTY_MUST_BE__NOT_, (property.isList() ? "an Array" : "an Object"), describe(e), name, npath), IssueSeverity.ERROR); } } @@ -508,7 +514,7 @@ public class JsonParser extends ParserBase { return e.type().toName(); } - private void parseChildPrimitive(Map children, Element element, Set processed, Property property, String path, String name, boolean isJsonName) throws FHIRException { + private void parseChildPrimitive(List errors, Map children, Element element, Set processed, Property property, String path, String name, boolean isJsonName) throws FHIRException { String npath = path+"."+property.getName(); String fpath = element.getPath()+"."+property.getName(); processed.add(name); @@ -516,40 +522,40 @@ public class JsonParser extends ParserBase { JsonProperty main = children.containsKey(name) ? children.get(name) : null; JsonProperty fork = children.containsKey("_"+name) ? children.get("_"+name) : null; if (main != null && main.getValue().isJsonString() && main.isUnquotedValue()) { - logError("2022-11-26", line(main.getValue()), col(main.getValue()), path, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_PROPERTY_VALUE_NO_QUOTES, main.getName(), main.getValue().asString()), IssueSeverity.ERROR); + logError(errors, "2022-11-26", line(main.getValue()), col(main.getValue()), path, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_PROPERTY_VALUE_NO_QUOTES, main.getName(), main.getValue().asString()), IssueSeverity.ERROR); } if (main != null || fork != null) { if (property.isList()) { boolean ok = true; if (!(main == null || main.getValue() instanceof JsonArray)) { - logError(ValidationMessage.NO_RULE_DATE, line(main.getValue()), col(main.getValue()), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_PROPERTY_MUST_BE_AN_ARRAY_NOT_, describe(main.getValue()), name, path), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(main.getValue()), col(main.getValue()), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_PROPERTY_MUST_BE_AN_ARRAY_NOT_, describe(main.getValue()), name, path), IssueSeverity.ERROR); ok = false; } if (!(fork == null || fork.getValue() instanceof JsonArray)) { - logError(ValidationMessage.NO_RULE_DATE, line(fork.getValue()), col(fork.getValue()), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_BASE_PROPERTY_MUST_BE_AN_ARRAY_NOT_, describe(main.getValue()), name, path), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(fork.getValue()), col(fork.getValue()), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_BASE_PROPERTY_MUST_BE_AN_ARRAY_NOT_, describe(main.getValue()), name, path), IssueSeverity.ERROR); ok = false; } if (ok) { JsonArray arr1 = (JsonArray) (main == null ? null : main.getValue()); JsonArray arr2 = (JsonArray) (fork == null ? null : fork.getValue()); if (arr1 != null && arr1.isExtraComma()) { - logError("2022-11-26", arr1.getEnd().getLine(), arr1.getEnd().getCol(), npath, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_COMMA_EXTRA, "Array"), IssueSeverity.ERROR); + logError(errors, "2022-11-26", arr1.getEnd().getLine(), arr1.getEnd().getCol(), npath, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_COMMA_EXTRA, "Array"), IssueSeverity.ERROR); } if (arr2 != null && arr2.isExtraComma()) { - logError("2022-11-26", arr2.getEnd().getLine(), arr2.getEnd().getCol(), npath, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_COMMA_EXTRA, "Array"), IssueSeverity.ERROR); + logError(errors, "2022-11-26", arr2.getEnd().getLine(), arr2.getEnd().getCol(), npath, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_COMMA_EXTRA, "Array"), IssueSeverity.ERROR); } for (int i = 0; i < Math.max(arrC(arr1), arrC(arr2)); i++) { JsonElement m = arrI(arr1, i); JsonElement f = arrI(arr2, i); if (m != null && m.isJsonString() && arr1.isUnquoted(i)) { - logError("2022-11-26", line(m), col(m), path+"."+name+"["+i+"]", IssueType.INVALID, context.formatMessage(I18nConstants.JSON_PROPERTY_VALUE_NO_QUOTES, "item", m.asString()), IssueSeverity.ERROR); + logError(errors, "2022-11-26", line(m), col(m), path+"."+name+"["+i+"]", IssueType.INVALID, context.formatMessage(I18nConstants.JSON_PROPERTY_VALUE_NO_QUOTES, "item", m.asString()), IssueSeverity.ERROR); } - parseChildPrimitiveInstance(element, property, name, isJsonName, npath, fpath, m, f); + parseChildPrimitiveInstance(errors, element, property, name, isJsonName, npath, fpath, m, f); } } } else { - parseChildPrimitiveInstance(element, property, name, isJsonName, npath, fpath, main == null ? null : main.getValue(), fork == null ? null : fork.getValue()); + parseChildPrimitiveInstance(errors, element, property, name, isJsonName, npath, fpath, main == null ? null : main.getValue(), fork == null ? null : fork.getValue()); } } } @@ -562,19 +568,19 @@ public class JsonParser extends ParserBase { return arr == null ? 0 : arr.size(); } - private void parseChildPrimitiveInstance(Element element, Property property, String name, boolean isJsonName, String npath, String fpath, JsonElement main, JsonElement fork) throws FHIRException { + private void parseChildPrimitiveInstance(List errors, Element element, Property property, String name, boolean isJsonName, String npath, String fpath, JsonElement main, JsonElement fork) throws FHIRException { if (main != null && !(main.isJsonBoolean() || main.isJsonNumber() || main.isJsonString())) { - logError(ValidationMessage.NO_RULE_DATE, line(main), col(main), npath, IssueType.INVALID, context.formatMessage( + logError(errors, ValidationMessage.NO_RULE_DATE, line(main), col(main), npath, IssueType.INVALID, context.formatMessage( I18nConstants.THIS_PROPERTY_MUST_BE_AN_SIMPLE_VALUE_NOT_, describe(main), name, npath), IssueSeverity.ERROR); } else if (fork != null && !(fork instanceof JsonObject)) { - logError(ValidationMessage.NO_RULE_DATE, line(fork), col(fork), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_PROPERTY_MUST_BE_AN_OBJECT_NOT_, describe(fork), name, npath), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(fork), col(fork), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_PROPERTY_MUST_BE_AN_OBJECT_NOT_, describe(fork), name, npath), IssueSeverity.ERROR); } else { Element n = new Element(isJsonName ? property.getName() : name, property).markLocation(line(main != null ? main : fork), col(main != null ? main : fork)); if (main != null) { - checkComments(main, n, npath); + checkComments(errors, main, n, npath); } if (fork != null) { - checkComments(fork, n, npath); + checkComments(errors, fork, n, npath); } n.setPath(fpath); element.getChildren().add(n); @@ -587,55 +593,55 @@ public class JsonParser extends ParserBase { n.setXhtml(xhtml.setXmlMode(true).parse(n.getValue(), null).getDocumentElement()); if (policy == ValidationPolicy.EVERYTHING) { for (StringPair s : xhtml.getValidationIssues()) { - logError("2022-11-17", line(main), col(main), npath, IssueType.INVALID, context.formatMessage(s.getName(), s.getValue()), IssueSeverity.ERROR); + logError(errors, "2022-11-17", line(main), col(main), npath, IssueType.INVALID, context.formatMessage(s.getName(), s.getValue()), IssueSeverity.ERROR); } } } catch (Exception e) { - logError(ValidationMessage.NO_RULE_DATE, line(main), col(main), npath, IssueType.INVALID, context.formatMessage(I18nConstants.ERROR_PARSING_XHTML_, e.getMessage()), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(main), col(main), npath, IssueType.INVALID, context.formatMessage(I18nConstants.ERROR_PARSING_XHTML_, e.getMessage()), IssueSeverity.ERROR); } } if (policy == ValidationPolicy.EVERYTHING) { // now we cross-check the primitive format against the stated type if (Utilities.existsInList(n.getType(), "boolean")) { if (!p.isJsonBoolean()) { - logError(ValidationMessage.NO_RULE_DATE, line(main), col(main), npath, IssueType.INVALID, context.formatMessage(I18nConstants.ERROR_PARSING_JSON_THE_PRIMITIVE_VALUE_MUST_BE_A_BOOLEAN), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(main), col(main), npath, IssueType.INVALID, context.formatMessage(I18nConstants.ERROR_PARSING_JSON_THE_PRIMITIVE_VALUE_MUST_BE_A_BOOLEAN), IssueSeverity.ERROR); } } else if (Utilities.existsInList(n.getType(), "integer", "unsignedInt", "positiveInt", "decimal")) { if (!p.isJsonNumber()) - logError(ValidationMessage.NO_RULE_DATE, line(main), col(main), npath, IssueType.INVALID, context.formatMessage(I18nConstants.ERROR_PARSING_JSON_THE_PRIMITIVE_VALUE_MUST_BE_A_NUMBER), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(main), col(main), npath, IssueType.INVALID, context.formatMessage(I18nConstants.ERROR_PARSING_JSON_THE_PRIMITIVE_VALUE_MUST_BE_A_NUMBER), IssueSeverity.ERROR); } else if (!p.isJsonString()) { - logError(ValidationMessage.NO_RULE_DATE, line(main), col(main), npath, IssueType.INVALID, context.formatMessage(I18nConstants.ERROR_PARSING_JSON_THE_PRIMITIVE_VALUE_MUST_BE_A_STRING), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(main), col(main), npath, IssueType.INVALID, context.formatMessage(I18nConstants.ERROR_PARSING_JSON_THE_PRIMITIVE_VALUE_MUST_BE_A_STRING), IssueSeverity.ERROR); } } } if (fork != null) { JsonObject child = (JsonObject) fork; - checkObject(child, n, npath); - parseChildren(npath, child, n, false); + checkObject(errors, child, n, npath); + parseChildren(errors, npath, child, n, false); } } } - private void parseResource(String npath, JsonObject res, Element parent, Property elementProperty) throws FHIRException { + private void parseResource(List errors, String npath, JsonObject res, Element parent, Property elementProperty) throws FHIRException { JsonElement rt = res.get("resourceType"); if (rt == null) { - logError(ValidationMessage.NO_RULE_DATE, line(res), col(res), npath, IssueType.INVALID, context.formatMessage(I18nConstants.UNABLE_TO_FIND_RESOURCETYPE_PROPERTY), IssueSeverity.FATAL); + logError(errors, ValidationMessage.NO_RULE_DATE, line(res), col(res), npath, IssueType.INVALID, context.formatMessage(I18nConstants.UNABLE_TO_FIND_RESOURCETYPE_PROPERTY), IssueSeverity.FATAL); } else if (!rt.isJsonString()) { - logError("2022-11-26", line(res), col(res), npath, IssueType.INVALID, context.formatMessage(I18nConstants.RESOURCETYPE_PROPERTY_WRONG_TYPE, rt.type().toName()), IssueSeverity.FATAL); + logError(errors, "2022-11-26", line(res), col(res), npath, IssueType.INVALID, context.formatMessage(I18nConstants.RESOURCETYPE_PROPERTY_WRONG_TYPE, rt.type().toName()), IssueSeverity.FATAL); } else { String name = rt.asString(); StructureDefinition sd = context.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(name, null)); if (sd == null) { - logError(ValidationMessage.NO_RULE_DATE, line(res), col(res), npath, IssueType.INVALID, context.formatMessage(I18nConstants.CONTAINED_RESOURCE_DOES_NOT_APPEAR_TO_BE_A_FHIR_RESOURCE_UNKNOWN_NAME_, name), IssueSeverity.FATAL); + logError(errors, ValidationMessage.NO_RULE_DATE, line(res), col(res), npath, IssueType.INVALID, context.formatMessage(I18nConstants.CONTAINED_RESOURCE_DOES_NOT_APPEAR_TO_BE_A_FHIR_RESOURCE_UNKNOWN_NAME_, name), IssueSeverity.FATAL); } else { parent.updateProperty(new Property(context, sd.getSnapshot().getElement().get(0), sd, this.profileUtilities), SpecialElement.fromProperty(parent.getProperty()), elementProperty); parent.setType(name); - parseChildren(npath, res, parent, true); + parseChildren(errors, npath, res, parent, true); } } if (res.isExtraComma()) { - logError("2022-11-26", res.getEnd().getLine(), res.getEnd().getCol(), npath, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_COMMA_EXTRA, "Object"), IssueSeverity.ERROR); + logError(errors, "2022-11-26", res.getEnd().getLine(), res.getEnd().getCol(), npath, IssueType.INVALID, context.formatMessage(I18nConstants.JSON_COMMA_EXTRA, "Object"), IssueSeverity.ERROR); } } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Manager.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Manager.java index f4b2c53fc..275eeb86d 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Manager.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/Manager.java @@ -48,9 +48,10 @@ import org.hl7.fhir.r5.model.StructureDefinition; public class Manager { //TODO use EnumMap - public enum FhirFormat { XML, JSON, TURTLE, TEXT, VBAR, SHC, FML; + public enum FhirFormat { XML, JSON, TURTLE, TEXT, VBAR, SHC, SHL, FML; // SHC = smart health cards, including as text versions of QR codes - + // SHL = smart health links, also a text version of the QR code + public String getExtension() { switch (this) { case JSON: @@ -65,6 +66,8 @@ public class Manager { return "hl7"; case SHC: return "shc"; + case SHL: + return "shl"; case FML: return "fml"; } @@ -85,6 +88,8 @@ public class Manager { return VBAR; case "shc": return SHC; + case "shl": + return SHL; case "fml": return FML; } @@ -106,7 +111,7 @@ public class Manager { } public static Element parseSingle(IWorkerContext context, InputStream source, FhirFormat inputFormat) throws FHIRFormatError, DefinitionException, IOException, FHIRException { - return makeParser(context, inputFormat).parseSingle(source); + return makeParser(context, inputFormat).parseSingle(source, null); } @@ -124,6 +129,7 @@ public class Manager { case TURTLE : return new TurtleParser(context); case VBAR : return new VerticalBarParser(context); case SHC : return new SHCParser(context); + case SHL : return new SHLParser(context); case FML : return new FmlParser(context); case TEXT : throw new Error("Programming logic error: do not call makeParser for a text resource"); } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/ParserBase.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/ParserBase.java index 1efa0984c..572d5ebea 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/ParserBase.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/ParserBase.java @@ -72,17 +72,42 @@ public abstract class ParserBase { public class NamedElement { private String name; private Element element; - public NamedElement(String name, Element element) { + private byte[] content; + private List errors = new ArrayList<>(); + + public NamedElement(String name, Element element, byte[] content) { super(); this.name = name; - this.element = element; + this.element = element; + this.content = content; } + + public NamedElement(String name, byte[] content) { + super(); + this.name = name; + this.content = content; + } + public String getName() { return name; } + public Element getElement() { return element; } + + public byte[] getContent() { + return content; + } + + public List getErrors() { + return errors; + } + + public void setElement(Element element) { + this.element = element; + + } } @@ -106,7 +131,6 @@ public abstract class ParserBase { protected IWorkerContext context; protected ValidationPolicy policy; - protected List errors; protected ILinkResolver linkResolver; protected boolean showDecorations; protected IdRenderingPolicy idPolicy = IdRenderingPolicy.All; @@ -118,30 +142,32 @@ public abstract class ParserBase { policy = ValidationPolicy.NONE; } - public void setupValidation(ValidationPolicy policy, List errors) { + public void setupValidation(ValidationPolicy policy) { this.policy = policy; - this.errors = errors; } public abstract List parse(InputStream stream) throws IOException, FHIRFormatError, DefinitionException, FHIRException; - public Element parseSingle(InputStream stream) throws IOException, FHIRFormatError, DefinitionException, FHIRException { - if (errors == null) { - errors = new ArrayList<>(); - } + public Element parseSingle(InputStream stream, List errors) throws IOException, FHIRFormatError, DefinitionException, FHIRException { + List res = parse(stream); - if (res == null) { - throw new FHIRException("Parsing FHIR content failed: "+errorSummary()); - } else if (res.size() == 0) { - throw new FHIRException("Parsing FHIR content returned no elements in a context where one element is required because: "+errorSummary()); - } + if (res.size() != 1) { throw new FHIRException("Parsing FHIR content returned multiple elements in a context where only one element is allowed"); } - return res.get(0).getElement(); + var resE = res.get(0); + if (resE.getElement() == null) { + throw new FHIRException("Parsing FHIR content failed: "+errorSummary(resE.errors)); + } else if (res.size() == 0) { + throw new FHIRException("Parsing FHIR content returned no elements in a context where one element is required because: "+errorSummary(resE.errors)); + } + if (errors != null) { + errors.addAll(resE.getErrors()); + } + return resE.getElement(); } - private String errorSummary() { + private String errorSummary(List errors) { if (errors == null || errors.size() == 0) { return "(no error description)"; } else { @@ -152,7 +178,7 @@ public abstract class ParserBase { public abstract void compose(Element e, OutputStream destination, OutputStyle style, String base) throws FHIRException, IOException; //FIXME: i18n should be done here - public void logError(String ruleDate, int line, int col, String path, IssueType type, String message, IssueSeverity level) throws FHIRFormatError { + public void logError(List errors, String ruleDate, int line, int col, String path, IssueType type, String message, IssueSeverity level) throws FHIRFormatError { if (errors != null) { if (policy == ValidationPolicy.EVERYTHING) { ValidationMessage msg = new ValidationMessage(Source.InstanceValidator, type, line, col, path, message, level); @@ -164,13 +190,13 @@ public abstract class ParserBase { } - protected StructureDefinition getDefinition(int line, int col, String ns, String name) throws FHIRFormatError { + protected StructureDefinition getDefinition(List errors, int line, int col, String ns, String name) throws FHIRFormatError { if (ns == null) { - logError(ValidationMessage.NO_RULE_DATE, line, col, name, IssueType.STRUCTURE, context.formatMessage(I18nConstants.THIS__CANNOT_BE_PARSED_AS_A_FHIR_OBJECT_NO_NAMESPACE, name), IssueSeverity.FATAL); + logError(errors, ValidationMessage.NO_RULE_DATE, line, col, name, IssueType.STRUCTURE, context.formatMessage(I18nConstants.THIS__CANNOT_BE_PARSED_AS_A_FHIR_OBJECT_NO_NAMESPACE, name), IssueSeverity.FATAL); return null; } if (name == null) { - logError(ValidationMessage.NO_RULE_DATE, line, col, name, IssueType.STRUCTURE, context.formatMessage(I18nConstants.THIS_CANNOT_BE_PARSED_AS_A_FHIR_OBJECT_NO_NAME), IssueSeverity.FATAL); + logError(errors, ValidationMessage.NO_RULE_DATE, line, col, name, IssueType.STRUCTURE, context.formatMessage(I18nConstants.THIS_CANNOT_BE_PARSED_AS_A_FHIR_OBJECT_NO_NAME), IssueSeverity.FATAL); return null; } for (StructureDefinition sd : context.fetchResourcesByType(StructureDefinition.class)) { @@ -183,7 +209,7 @@ public abstract class ParserBase { return sd; } } - logError(ValidationMessage.NO_RULE_DATE, line, col, name, IssueType.STRUCTURE, context.formatMessage(I18nConstants.THIS_DOES_NOT_APPEAR_TO_BE_A_FHIR_RESOURCE_UNKNOWN_NAMESPACENAME_, ns, name), IssueSeverity.FATAL); + logError(errors, ValidationMessage.NO_RULE_DATE, line, col, name, IssueType.STRUCTURE, context.formatMessage(I18nConstants.THIS_DOES_NOT_APPEAR_TO_BE_A_FHIR_RESOURCE_UNKNOWN_NAMESPACENAME_, ns, name), IssueSeverity.FATAL); return null; } @@ -191,9 +217,9 @@ public abstract class ParserBase { return type == null || !type.contains("/") ? type : type.substring(type.lastIndexOf("/")+1); } - protected StructureDefinition getDefinition(int line, int col, String name) throws FHIRFormatError { + protected StructureDefinition getDefinition(List errors, int line, int col, String name) throws FHIRFormatError { if (name == null) { - logError(ValidationMessage.NO_RULE_DATE, line, col, name, IssueType.STRUCTURE, context.formatMessage(I18nConstants.THIS_CANNOT_BE_PARSED_AS_A_FHIR_OBJECT_NO_NAME), IssueSeverity.FATAL); + logError(errors, ValidationMessage.NO_RULE_DATE, line, col, name, IssueType.STRUCTURE, context.formatMessage(I18nConstants.THIS_CANNOT_BE_PARSED_AS_A_FHIR_OBJECT_NO_NAME), IssueSeverity.FATAL); return null; } // first pass: only look at base definitions @@ -209,7 +235,7 @@ public abstract class ParserBase { return sd; } } - logError(ValidationMessage.NO_RULE_DATE, line, col, name, IssueType.STRUCTURE, context.formatMessage(I18nConstants.THIS_DOES_NOT_APPEAR_TO_BE_A_FHIR_RESOURCE_UNKNOWN_NAME_, name), IssueSeverity.FATAL); + logError(errors, ValidationMessage.NO_RULE_DATE, line, col, name, IssueType.STRUCTURE, context.formatMessage(I18nConstants.THIS_DOES_NOT_APPEAR_TO_BE_A_FHIR_RESOURCE_UNKNOWN_NAME_, name), IssueSeverity.FATAL); return null; } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHCParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHCParser.java index ed0edbf54..5193c4a1c 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHCParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHCParser.java @@ -1,5 +1,6 @@ package org.hl7.fhir.r5.elementmodel; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -17,6 +18,7 @@ import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRFormatError; import org.hl7.fhir.r5.context.IWorkerContext; +import org.hl7.fhir.r5.elementmodel.ParserBase.NamedElement; import org.hl7.fhir.r5.formats.IParser.OutputStyle; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; @@ -56,20 +58,25 @@ public class SHCParser extends ParserBase { jsonParser = new JsonParser(context); } - public List parse(InputStream stream) throws IOException, FHIRFormatError, DefinitionException, FHIRException { + public List parse(InputStream inStream) throws IOException, FHIRFormatError, DefinitionException, FHIRException { + byte[] content = TextFile.streamToBytes(inStream); + ByteArrayInputStream stream = new ByteArrayInputStream(content); List res = new ArrayList<>(); + NamedElement shc = new NamedElement("shc", content); + res.add(shc); + String src = TextFile.streamToString(stream).trim(); List list = new ArrayList<>(); String pfx = null; if (src.startsWith("{")) { JsonObject json = org.hl7.fhir.utilities.json.parser.JsonParser.parseObject(src); - if (checkProperty(json, "$", "verifiableCredential", true, "Array")) { + if (checkProperty(shc.getErrors(), json, "$", "verifiableCredential", true, "Array")) { pfx = "verifiableCredential"; JsonArray arr = json.getJsonArray("verifiableCredential"); int i = 0; for (JsonElement e : arr) { if (!(e instanceof JsonPrimitive)) { - logError(ValidationMessage.NO_RULE_DATE, line(e), col(e), "$.verifiableCredential["+i+"]", IssueType.STRUCTURE, "Wrong Property verifiableCredential in JSON Payload. Expected : String but found "+e.type().toName(), IssueSeverity.ERROR); + logError(shc.getErrors(), ValidationMessage.NO_RULE_DATE, line(e), col(e), "$.verifiableCredential["+i+"]", IssueType.STRUCTURE, "Wrong Property verifiableCredential in JSON Payload. Expected : String but found "+e.type().toName(), IssueSeverity.ERROR); } else { list.add(e.asString()); } @@ -87,66 +94,65 @@ public class SHCParser extends ParserBase { c++; JWT jwt = null; try { - jwt = decodeJWT(ssrc); + jwt = decodeJWT(shc.getErrors(), ssrc); } catch (Exception e) { - logError(ValidationMessage.NO_RULE_DATE, 1, 1, prefix+"JWT", IssueType.INVALID, "Unable to decode JWT token", IssueSeverity.ERROR); + logError(shc.getErrors(), ValidationMessage.NO_RULE_DATE, 1, 1, prefix+"JWT", IssueType.INVALID, "Unable to decode JWT token", IssueSeverity.ERROR); return res; } - checkNamedProperties(jwt.getPayload(), prefix+"payload", "iss", "nbf", "vc"); - checkProperty(jwt.getPayload(), prefix+"payload", "iss", true, "String"); - logError(ValidationMessage.NO_RULE_DATE, 1, 1, prefix+"JWT", IssueType.INFORMATIONAL, "The FHIR Validator does not check the JWT signature "+ + checkNamedProperties(shc.getErrors(), jwt.getPayload(), prefix+"payload", "iss", "nbf", "vc"); + checkProperty(shc.getErrors(), jwt.getPayload(), prefix+"payload", "iss", true, "String"); + logError(shc.getErrors(), ValidationMessage.NO_RULE_DATE, 1, 1, prefix+"JWT", IssueType.INFORMATIONAL, "The FHIR Validator does not check the JWT signature "+ "(see https://demo-portals.smarthealth.cards/VerifierPortal.html or https://github.com/smart-on-fhir/health-cards-dev-tools) (Issuer = '"+jwt.getPayload().asString("iss")+"')", IssueSeverity.INFORMATION); - checkProperty(jwt.getPayload(), prefix+"payload", "nbf", true, "Number"); + checkProperty(shc.getErrors(), jwt.getPayload(), prefix+"payload", "nbf", true, "Number"); JsonObject vc = jwt.getPayload().getJsonObject("vc"); if (vc == null) { - logError(ValidationMessage.NO_RULE_DATE, 1, 1, "JWT", IssueType.STRUCTURE, "Unable to find property 'vc' in the payload", IssueSeverity.ERROR); + logError(shc.getErrors(), ValidationMessage.NO_RULE_DATE, 1, 1, "JWT", IssueType.STRUCTURE, "Unable to find property 'vc' in the payload", IssueSeverity.ERROR); return res; } String path = prefix+"payload.vc"; - checkNamedProperties(vc, path, "type", "credentialSubject"); - if (!checkProperty(vc, path, "type", true, "Array")) { + checkNamedProperties(shc.getErrors(), vc, path, "type", "credentialSubject"); + if (!checkProperty(shc.getErrors(), vc, path, "type", true, "Array")) { return res; } JsonArray type = vc.getJsonArray("type"); int i = 0; for (JsonElement e : type) { if (e.type() != JsonElementType.STRING) { - logError(ValidationMessage.NO_RULE_DATE, line(e), col(e), path+".type["+i+"]", IssueType.STRUCTURE, "Wrong Property Type in JSON Payload. Expected : String but found "+e.type().toName(), IssueSeverity.ERROR); + logError(shc.getErrors(), ValidationMessage.NO_RULE_DATE, line(e), col(e), path+".type["+i+"]", IssueType.STRUCTURE, "Wrong Property Type in JSON Payload. Expected : String but found "+e.type().toName(), IssueSeverity.ERROR); } else { types.add(e.asString()); } i++; } if (!types.contains("https://smarthealth.cards#health-card")) { - logError(ValidationMessage.NO_RULE_DATE, line(vc), col(vc), path, IssueType.STRUCTURE, "Card does not claim to be of type https://smarthealth.cards#health-card, cannot validate", IssueSeverity.ERROR); + logError(shc.getErrors(), ValidationMessage.NO_RULE_DATE, line(vc), col(vc), path, IssueType.STRUCTURE, "Card does not claim to be of type https://smarthealth.cards#health-card, cannot validate", IssueSeverity.ERROR); return res; } - if (!checkProperty(vc, path, "credentialSubject", true, "Object")) { + if (!checkProperty(shc.getErrors(), vc, path, "credentialSubject", true, "Object")) { return res; } JsonObject cs = vc.getJsonObject("credentialSubject"); path = path+".credentialSubject"; - if (!checkProperty(cs, path, "fhirVersion", true, "String")) { + if (!checkProperty(shc.getErrors(), cs, path, "fhirVersion", true, "String")) { return res; } JsonElement fv = cs.get("fhirVersion"); if (!VersionUtilities.versionsCompatible(context.getVersion(), fv.asString())) { - logError(ValidationMessage.NO_RULE_DATE, line(fv), col(fv), path+".fhirVersion", IssueType.STRUCTURE, "Card claims to be of version "+fv.asString()+", cannot be validated against version "+context.getVersion(), IssueSeverity.ERROR); + logError(shc.getErrors(), ValidationMessage.NO_RULE_DATE, line(fv), col(fv), path+".fhirVersion", IssueType.STRUCTURE, "Card claims to be of version "+fv.asString()+", cannot be validated against version "+context.getVersion(), IssueSeverity.ERROR); return res; } - if (!checkProperty(cs, path, "fhirBundle", true, "Object")) { + if (!checkProperty(shc.getErrors(), cs, path, "fhirBundle", true, "Object")) { return res; } // ok. all checks passed, we can now validate the bundle - Element e = jsonParser.parse(cs.getJsonObject("fhirBundle")); - if (e != null) { - res.add(new NamedElement(path, e)); - } - } + NamedElement bnd = new NamedElement(path, org.hl7.fhir.utilities.json.parser.JsonParser.composeBytes(cs.getJsonObject("fhirBundle"))); + res.add(bnd); + bnd.setElement(jsonParser.parse(bnd.getErrors(), cs.getJsonObject("fhirBundle"))); + } return res; } - + @Override public String getImpliedProfile() { @@ -163,27 +169,27 @@ public class SHCParser extends ParserBase { } - private boolean checkProperty(JsonObject obj, String path, String name, boolean required, String type) { + private boolean checkProperty(List errors, JsonObject obj, String path, String name, boolean required, String type) { JsonElement e = obj.get(name); if (e != null) { String t = e.type().toName(); if (!type.equals(t)) { - logError(ValidationMessage.NO_RULE_DATE, line(e), col(e), path+"."+name, IssueType.STRUCTURE, "Wrong Property Type in JSON Payload. Expected : "+type+" but found "+t, IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(e), col(e), path+"."+name, IssueType.STRUCTURE, "Wrong Property Type in JSON Payload. Expected : "+type+" but found "+t, IssueSeverity.ERROR); } else { return true; } } else if (required) { - logError(ValidationMessage.NO_RULE_DATE, line(obj), col(obj), path, IssueType.STRUCTURE, "Missing Property in JSON Payload: "+name, IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(obj), col(obj), path, IssueType.STRUCTURE, "Missing Property in JSON Payload: "+name, IssueSeverity.ERROR); } else { return true; } return false; } - private void checkNamedProperties(JsonObject obj, String path, String... names) { + private void checkNamedProperties(List errors, JsonObject obj, String path, String... names) { for (JsonProperty e : obj.getProperties()) { if (!Utilities.existsInList(e.getName(), names)) { - logError(ValidationMessage.NO_RULE_DATE, line(e.getValue()), col(e.getValue()), path+"."+e.getName(), IssueType.STRUCTURE, "Unknown Property in JSON Payload", IssueSeverity.WARNING); + logError(errors, ValidationMessage.NO_RULE_DATE, line(e.getValue()), col(e.getValue()), path+"."+e.getName(), IssueType.STRUCTURE, "Unknown Property in JSON Payload", IssueSeverity.WARNING); } } } @@ -242,12 +248,12 @@ public class SHCParser extends ParserBase { return b.toString(); } - public JWT decodeJWT(String jwt) throws IOException, DataFormatException { + public JWT decodeJWT(List errors, String jwt) throws IOException, DataFormatException { if (jwt.startsWith("shc:/")) { jwt = decodeQRCode(jwt); } if (jwt.length() > MAX_ALLOWED_SHC_LENGTH) { - logError(ValidationMessage.NO_RULE_DATE, -1, -1, "jwt", IssueType.TOOLONG, "JWT Payload limit length is "+MAX_ALLOWED_SHC_LENGTH+" bytes for a single image - this has "+jwt.length()+" bytes", IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, -1, -1, "jwt", IssueType.TOOLONG, "JWT Payload limit length is "+MAX_ALLOWED_SHC_LENGTH+" bytes for a single image - this has "+jwt.length()+" bytes", IssueSeverity.ERROR); } String[] parts = splitToken(jwt); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHLParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHLParser.java new file mode 100644 index 000000000..d65b77b77 --- /dev/null +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHLParser.java @@ -0,0 +1,465 @@ +package org.hl7.fhir.r5.elementmodel; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.UnknownHostException; +import java.text.ParseException; +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Base64; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.zip.DataFormatException; +import java.util.Date; +import java.util.zip.Inflater; + +import org.hl7.fhir.exceptions.DefinitionException; +import org.hl7.fhir.exceptions.FHIRException; +import org.hl7.fhir.exceptions.FHIRFormatError; +import org.hl7.fhir.r5.context.IWorkerContext; +import org.hl7.fhir.r5.formats.IParser.OutputStyle; +import org.hl7.fhir.r5.test.utils.TestingUtilities; +import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; +import org.hl7.fhir.utilities.SimpleHTTPClient; +import org.hl7.fhir.utilities.TextFile; +import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.utilities.VersionUtilities; +import org.hl7.fhir.utilities.SimpleHTTPClient.HTTPResult; +import org.hl7.fhir.utilities.json.model.JsonArray; +import org.hl7.fhir.utilities.json.model.JsonElement; +import org.hl7.fhir.utilities.json.model.JsonElementType; +import org.hl7.fhir.utilities.json.model.JsonObject; +import org.hl7.fhir.utilities.json.model.JsonPrimitive; +import org.hl7.fhir.utilities.json.model.JsonProperty; +import org.hl7.fhir.utilities.validation.ValidationMessage; +import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; +import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; + +import com.nimbusds.jose.JWEObject; +import com.nimbusds.jose.Payload; +import com.nimbusds.jose.crypto.DirectDecrypter; + +/** + * this class is actually a smart health link retreiver. + * It's going to parse the link, check it, and then return + * 2 items, the link with validation information in an Element, and the + * parsed whatever that the link pointed to + * + * Error locations in the first item are in the decoded JSON file the URL contains, or 0,0 if not in the json file + * Error locations in the second item are in the decoded payload + * + * @author grahame + * + */ +public class SHLParser extends ParserBase { + private static boolean testMode; + + private boolean post = true; + private String url = null; + private byte[] key = null; + private String ct; + + public SHLParser(IWorkerContext context) { + super(context); + } + + public List parse(InputStream inStream) throws IOException, FHIRFormatError, DefinitionException, FHIRException { + byte[] content = TextFile.streamToBytes(inStream); + + List res = new ArrayList<>(); + NamedElement shl = addNamedElement(res, "shl", content); + String src = TextFile.bytesToString(content); + + if (src.startsWith("shlink:/")) { + src = src.substring(8); + } else if (src.contains("#shlink:/")) { + String pfx = src.substring(0, src.indexOf("#shlink:/")); + src = src.substring(src.indexOf("#shlink:/")+9); + if (!Utilities.isAbsoluteUrlLinkable(pfx)) { + logError(shl.getErrors(), "202-08-31", 1, 1, "shl", IssueType.STRUCTURE, "if a prefix is present, it must be a URL, not "+pfx, IssueSeverity.ERROR); + } + } else { + logError(shl.getErrors(), "202-08-31", 1, 1, "shl", IssueType.STRUCTURE, "This content does not appear to be an Smart Health Link", IssueSeverity.ERROR); + src = null; + } + if (src != null) { + NamedElement json = addNamedElement(res, "json", TextFile.stringToBytes(src, false)); + byte[] cntin = Base64.getUrlDecoder().decode(src); + JsonObject j = null; + try { + j = org.hl7.fhir.utilities.json.parser.JsonParser.parseObject(cntin); + } catch (Exception e) { + logError(json.getErrors(), "202-08-31", 1, 1, "shl.json", IssueType.STRUCTURE, "The JSON is not valid: "+e.getMessage(), IssueSeverity.ERROR); + } + if (j != null) { + byte[] cntout = org.hl7.fhir.utilities.json.parser.JsonParser.composeBytes(j, false); + if (!Arrays.equals(cntin, cntout)) { + logError(shl.getErrors(), "202-08-31", 1, 1, "shl", IssueType.STRUCTURE, "The JSON does not seem to be minified properly", IssueSeverity.ERROR); + } + if (checkJson(json.getErrors(), j)) { + HTTPResult cnt = null; + if (post) { + try { + cnt = fetchManifest(); + } catch (UnknownHostException e) { + logError(json.getErrors(), "202-08-31", 1, 1, "shl.json", IssueType.STRUCTURE, "The manifest could not be fetched because the host "+e.getMessage()+" is unknown", IssueSeverity.ERROR); + } catch (Exception e) { + logError(json.getErrors(), "202-08-31", 1, 1, "shl.json", IssueType.STRUCTURE, "The manifest could not be fetched: "+e.getMessage(), IssueSeverity.ERROR); + } + if (cnt != null) { + if (cnt.getContentType() == null) { + logError(json.getErrors(), "202-08-31", 1, 1, "shl.json.url.fetch()", IssueType.NOTFOUND, "The server did not return a Content-Type header - should be 'application/json'", IssueSeverity.WARNING); + } else if (!"application/json".equals(cnt.getContentType())) { + logError(json.getErrors(), "202-08-31", 1, 1, "shl.json.url.fetch()", IssueType.STRUCTURE, "The server returned the wrong Content-Type header '"+cnt.getContentType()+"' - must be 'application/json'", IssueSeverity.ERROR); + } + checkManifest(res, cnt); + } + } else { + try { + cnt = fetchFile(url+"?recipient=FHIR%20Validator", "application/jose"); + } catch (Exception e) { + logError(json.getErrors(), "202-08-31", 1, 1, "shl,json.url", IssueType.STRUCTURE, "The document could not be fetched: "+e.getMessage(), IssueSeverity.ERROR); + } + if (cnt != null) { + if (cnt.getContentType() == null) { + logError(json.getErrors(), "202-08-31", 1, 1, "shl.json.url.fetch()", IssueType.NOTFOUND, "The server did not return a Content-Type header - should be 'application/json'", IssueSeverity.WARNING); + } else if (!"application/json".equals(cnt.getContentType())) { + logError(json.getErrors(), "202-08-31", 1, 1, "shl.json.url.fetch()", IssueType.STRUCTURE, "The server returned the wrong Content-Type header '"+cnt.getContentType()+"' - must be 'application/json'", IssueSeverity.ERROR); + } + processContent(res, json.getErrors(), "shl.url.fetched()", "document", cnt.getContentAsString(), ct); + } + } + } + } + } + return res; + } + + + private void checkManifest(List res, HTTPResult cnt) throws IOException { + NamedElement manifest = addNamedElement(res, "manifest", cnt.getContent()); + + if (!cnt.getContentType().equals("application/json")) { + logError(manifest.getErrors(), "202-08-31", 1, 1, "manifest", IssueType.STRUCTURE, "The mime type should be application/json not "+cnt.getContentType(), IssueSeverity.ERROR); + } else { + JsonObject j = null; + try { + j = org.hl7.fhir.utilities.json.parser.JsonParser.parseObject(cnt.getContent()); + } catch (Exception e) { + logError(manifest.getErrors(), "202-08-31", 1, 1, "manifest", IssueType.STRUCTURE, "The JSON is not valid: "+e.getMessage(), IssueSeverity.ERROR); + } + if (j != null) { + for (JsonProperty p : j.getProperties()) { + if (!p.getName().equals("files")) { + logError(manifest.getErrors(), "202-08-31", p.getValue().getStart().getLine(), p.getValue().getStart().getCol(), "manifest."+p.getName(), + IssueType.STRUCTURE, "Unexpected property name "+p.getName(), IssueSeverity.WARNING); + } + } + } + if (j.has("files")) { + JsonElement f = j.get("files"); + if (f.isJsonArray()) { + int i = 0; + for (JsonElement e : f.asJsonArray()) { + if (e.isJsonObject()) { + processManifestEntry(res, manifest.getErrors(), e.asJsonObject(), "manifest.files["+i+"]", "files["+i+"]"); + } else { + logError(manifest.getErrors(), "202-08-31", e.getStart().getLine(), e.getStart().getCol(), "manifest.files["+i+"]", + IssueType.STRUCTURE, "files must be an object, not a "+f.type().name(), IssueSeverity.ERROR); + } + } + } else { + logError(manifest.getErrors(), "202-08-31", f.getStart().getLine(), f.getStart().getCol(), "manifest.files", + IssueType.STRUCTURE, "files must be an array, not a "+f.type().name(), IssueSeverity.ERROR); + } + } else { + logError(manifest.getErrors(), "202-08-31", j.getStart().getLine(), j.getStart().getCol(), "manifest", + IssueType.STRUCTURE, "files not found", IssueSeverity.WARNING); + } + } + } + + private void processManifestEntry(List res, List errors, JsonObject j, String path, String name) throws FHIRFormatError, DefinitionException, FHIRException, IOException { + for (JsonProperty p : j.getProperties()) { + if (!Utilities.existsInList(p.getName(), "contentType", "location", "embedded")) { + logError(errors, "202-08-31", p.getValue().getStart().getLine(), p.getValue().getStart().getCol(), "manifest."+p.getName(), + IssueType.STRUCTURE, "Unexpected property "+p.getName(), IssueSeverity.WARNING); + } + } + JsonElement cte = j.get("contentType"); + JsonElement loce = j.get("location"); + JsonElement embe = j.get("embedded"); + String ct = null; + if (cte == null) { + logError(errors, "202-08-31", j.getStart().getLine(), j.getStart().getCol(), path, IssueType.STRUCTURE, "contentType not found", IssueSeverity.ERROR); + } else if (!cte.isJsonString()) { + logError(errors, "202-08-31", j.getStart().getLine(), j.getStart().getCol(), path+".contentType", IssueType.STRUCTURE, "contentType must be a string not a "+cte.type().name(), IssueSeverity.ERROR); + } else { + ct = cte.asString(); + if (!Utilities.existsInList(ct, "application/smart-health-card", "application/smart-api-access", "application/fhir+json")) { + logError(errors, "202-08-31", j.getStart().getLine(), j.getStart().getCol(), path+".contentType", IssueType.STRUCTURE, "contentType must be one of application/smart-health-card, application/smart-api-access or application/fhir+json", IssueSeverity.ERROR); + ct = null; + } + } + if (loce != null && !loce.isJsonString()) { + logError(errors, "202-08-31", j.getStart().getLine(), j.getStart().getCol(), path+".location", IssueType.STRUCTURE, "location must be a string not a "+loce.type().name(), IssueSeverity.ERROR); + } + if (embe != null && !embe.isJsonString()) { + logError(errors, "202-08-31", j.getStart().getLine(), j.getStart().getCol(), path+".embedded", IssueType.STRUCTURE, "embedded must be a string not a "+embe.type().name(), IssueSeverity.ERROR); + } + if (loce == null && embe == null) { + logError(errors, "202-08-31", j.getStart().getLine(), j.getStart().getCol(), path, IssueType.STRUCTURE, "Found neither a location nor an embedded property", IssueSeverity.ERROR); + } else if (loce != null && embe != null) { + logError(errors, "202-08-31", j.getStart().getLine(), j.getStart().getCol(), path, IssueType.STRUCTURE, "Found both a location nor an embedded property - only one can be present", IssueSeverity.ERROR); + } else if (ct != null) { + if (embe != null) { + processContent(res, errors, path+".embedded", name, embe.asString(), ct); + } else if (loce != null) { // it will be, just removes a warning + HTTPResult cnt = null; + try { + cnt = fetchFile(loce.asString(), "application/jose"); + } catch (Exception e) { + logError(errors, "202-08-31", 1, 1, "shl", IssueType.STRUCTURE, "The document could not be fetched: "+e.getMessage(), IssueSeverity.ERROR); + } + if (cnt != null) { + if (cnt.getContentType() == null) { + logError(errors, "202-08-31", 1, 1, "shl.json.url.fetch()", IssueType.NOTFOUND, "The server did not return a Content-Type header - should be 'application/json'", IssueSeverity.WARNING); + } else if (!"application/json".equals(cnt.getContentType())) { + logError(errors, "202-08-31", 1, 1, "shl.json.url.fetch()", IssueType.STRUCTURE, "The server returned the wrong Content-Type header '"+cnt.getContentType()+"' - must be 'application/json'", IssueSeverity.ERROR); + } + processContent(res, errors, path+".url.fetch()", name, cnt.getContentAsString(), ct); + } + } + } + } + + private void processContent(List res, List errors, String path, String name, String jose, String ct) throws FHIRFormatError, DefinitionException, FHIRException, IOException { + byte[] cnt = null; + JWEObject jwe; + try { + jwe = JWEObject.parse(jose); + jwe.decrypt(new DirectDecrypter(key)); + cnt = jwe.getPayload().toBytes(); + } catch (Exception e) { + logError(errors, "202-08-31", 1, 1, path, IssueType.STRUCTURE, "Decruption failed: "+e.getMessage(), IssueSeverity.ERROR); + } + if (cnt != null) { + NamedElement doc = addNamedElement(res, name, cnt); + switch (ct) { + case "application/smart-health-card": + //a JSON file with a .verifiableCredential array containing SMART Health Card JWS strings, as specified by https://spec.smarthealth.cards#via-file-download. + SHCParser shc = new SHCParser(context); + res.addAll(shc.parse(new ByteArrayInputStream(cnt))); + break; + case "application/fhir+json": + // a JSON file containing any FHIR resource (e.g., an individual resource or a Bundle of resources). Generally this format may not be tamper-proof. + logError(doc.getErrors(), "202-08-31", 1, 1, name, IssueType.STRUCTURE, "Processing content of type 'application/smart-api-access' is not done yet", IssueSeverity.INFORMATION); + break; + case "application/smart-api-access": + // a JSON file with a SMART Access Token Response (see SMART App Launch). Two additional properties are defined: + // aud Required string indicating the FHIR Server Base URL where this token can be used (e.g., "https://server.example.org/fhir") + // query: Optional array of strings acting as hints to the client, indicating queries it might want to make (e.g., ["Coverage?patient=123&_tag=family-insurance"]) + logError(doc.getErrors(), "202-08-31", 1, 1, name, IssueType.STRUCTURE, "Processing content of type 'application/smart-api-access' is not done yet", IssueSeverity.INFORMATION); + break; + default: + logError(doc.getErrors(), "202-08-31", 1, 1, name, IssueType.STRUCTURE, "The Content-Type '"+ct+"' is not known", IssueSeverity.INFORMATION); + } + } + } + + private NamedElement addNamedElement(List res, String name, byte[] content) { + NamedElement result = new NamedElement(name, content); + res.add(result); + return result; + } + + + private HTTPResult fetchFile(String url, String ct) throws IOException { + SimpleHTTPClient fetcher = new SimpleHTTPClient(); + fetcher.addHeader("Accept", ct); + HTTPResult res = fetcher.get(url); + res.checkThrowException(); + return res; + } + + private HTTPResult fetchManifest() throws IOException { + if (testMode) { + return new HTTPResult(url, 200, "OK", "application/json", TextFile.streamToBytes(TestingUtilities.loadTestResourceStream("validator", "shlink.manifest.json"))); + } + SimpleHTTPClient fetcher = new SimpleHTTPClient(); + JsonObject j = new JsonObject(); + j.add("recipient", "FHIR Validator"); + HTTPResult res = fetcher.post(url, "application/json", org.hl7.fhir.utilities.json.parser.JsonParser.composeBytes(j), "application/json"); + res.checkThrowException(); + return res; + } + + private boolean checkJson(List errors, JsonObject j) { + boolean ok = true; + boolean fUrl = false; + boolean fKey = false; + boolean fCty = false; + boolean hp = false; + boolean hu = false; + for (JsonProperty p : j.getProperties()) { + switch (p.getName()) { + case "url": + fUrl = true; + if (!p.getValue().isJsonString()) { + logError(errors, "2023-08-31", p.getValue().getStart().getLine(), p.getValue().getStart().getCol(), "shl."+p.getName(), + IssueType.STRUCTURE, "url must be a string", IssueSeverity.ERROR); + ok = false; + } else if (!Utilities.isAbsoluteUrlLinkable(p.getValue().asString())) { + logError(errors, "2023-08-31", p.getValue().getStart().getLine(), p.getValue().getStart().getCol(), "shl."+p.getName(), + IssueType.STRUCTURE, "url is not valid: "+p.getValue().asString(), IssueSeverity.ERROR); + ok = false; + } else { + url = p.getValue().asString(); + } + break; + case "key": + fKey = true; + if (!p.getValue().isJsonString()) { + logError(errors, "2023-08-31", p.getValue().getStart().getLine(), p.getValue().getStart().getCol(), "shl."+p.getName(), + IssueType.STRUCTURE, "key must be a string", IssueSeverity.ERROR); + ok = false; + } else if (p.getValue().asString().length() != 43) { + logError(errors, "2023-08-31", p.getValue().getStart().getLine(), p.getValue().getStart().getCol(), "shl."+p.getName(), + IssueType.STRUCTURE, "key must contain 43 chars", IssueSeverity.ERROR); + ok = false; + } else { + key = Base64.getUrlDecoder().decode(p.getValue().asString()); + } + break; + case "exp": + if (!p.getValue().isJsonNumber()) { + logError(errors, "2023-08-31", p.getValue().getStart().getLine(), p.getValue().getStart().getCol(), "shl."+p.getName(), + IssueType.STRUCTURE, "exp must be a number", IssueSeverity.ERROR); + } else if (!Utilities.isDecimal(p.getValue().asJsonNumber().getValue(), false)) { + logError(errors, "2023-08-31", p.getValue().getStart().getLine(), p.getValue().getStart().getCol(), "shl."+p.getName(), + IssueType.STRUCTURE, "exp must be a valid number", IssueSeverity.ERROR); + } else { + String v = p.getValue().asJsonNumber().getValue(); + if (v.contains(".")) { + v = v.substring(0, v.indexOf(".")); + } + + long epochSecs = Long.valueOf(v); + LocalDateTime date = LocalDateTime.ofEpochSecond(epochSecs, 0, ZoneOffset.UTC); + LocalDateTime now = LocalDateTime.now(ZoneOffset.UTC); + Duration duration = Duration.between(now, date); + + if (date.isBefore(now)) { + logError(errors, "2023-08-31", p.getValue().getStart().getLine(), p.getValue().getStart().getCol(), "shl."+p.getName(), + IssueType.STRUCTURE, "The content has expired (by "+Utilities.describeDuration(duration)+")", IssueSeverity.WARNING); + } + } + break; + case "flag": + if (!p.getValue().isJsonString()) { + logError(errors, "2023-08-31", p.getValue().getStart().getLine(), p.getValue().getStart().getCol(), "shl."+p.getName(), + IssueType.STRUCTURE, "flag must be a string", IssueSeverity.ERROR); + } else { + String flag = p.getValue().asString(); + for (char c : flag.toCharArray()) { + switch (c) { + case 'L': // ok + break; + case 'P': + hp = true; + break; + case 'U': + hu = true; + break; + default: + logError(errors, "2023-08-31", p.getValue().getStart().getLine(), p.getValue().getStart().getCol(), "shl."+p.getName(), + IssueType.STRUCTURE, "Illegal Character "+c+" in flag", IssueSeverity.ERROR); + } + } + if (hu && hp) { + logError(errors, "2023-08-31", p.getValue().getStart().getLine(), p.getValue().getStart().getCol(), "shl."+p.getName(), + IssueType.STRUCTURE, "Illegal combination in flag: both P and U are present", IssueSeverity.ERROR); + } + if (hp) { + logError(errors, "2023-08-31", p.getValue().getStart().getLine(), p.getValue().getStart().getCol(), "shl."+p.getName(), + IssueType.BUSINESSRULE, "The validator is unable to retrieve the content referred to by the URL because a password is required", IssueSeverity.INFORMATION); + ok = false; + } + if (hu) { + post = false; + } + } + break; + case "label": + if (!p.getValue().isJsonString()) { + logError(errors, "2023-08-31", p.getValue().getStart().getLine(), p.getValue().getStart().getCol(), "shl."+p.getName(), + IssueType.STRUCTURE, "label must be a string", IssueSeverity.ERROR); + } else if (p.getValue().asString().length() > 80) { + logError(errors, "2023-08-31", p.getValue().getStart().getLine(), p.getValue().getStart().getCol(), "shl."+p.getName(), + IssueType.STRUCTURE, "label must be no longer than 80 chars", IssueSeverity.ERROR); + } + break; + case "cty" : + if (!p.getValue().isJsonString()) { + logError(errors, "2023-08-31", p.getValue().getStart().getLine(), p.getValue().getStart().getCol(), "shl."+p.getName(), + IssueType.STRUCTURE, "cty must be a string", IssueSeverity.ERROR); + } else if (!Utilities.existsInList(p.getValue().asString(), "application/smart-health-card", "application/smart-api-access", "application/fhir+json")) { + logError(errors, "2023-08-31", p.getValue().getStart().getLine(), p.getValue().getStart().getCol(), "shl."+p.getName(), + IssueType.STRUCTURE, "cty must be one of 'application/smart-health-card/, 'application/smart-api-access', 'application/fhir+json'", IssueSeverity.ERROR); + } else { + ct = p.getValue().asString(); + } + break; + case "v": + if (!p.getValue().isJsonString()) { + logError(errors, "2023-08-31", p.getValue().getStart().getLine(), p.getValue().getStart().getCol(), "shl."+p.getName(), + IssueType.STRUCTURE, "v must be a string", IssueSeverity.ERROR); + } else if (p.getValue().asString().length() <= 80) { + logError(errors, "2023-08-31", p.getValue().getStart().getLine(), p.getValue().getStart().getCol(), "shl."+p.getName(), + IssueType.STRUCTURE, "if present, v must be '1'", IssueSeverity.ERROR); + } + break; + default: + logError(errors, "202-08-31", p.getValue().getStart().getLine(), p.getValue().getStart().getCol(), "shl."+p.getName(), + IssueType.STRUCTURE, "Illegal property name "+p.getName(), IssueSeverity.ERROR); + } + } + if (hu && !fCty) { + logError(errors, "202-08-31", 1, 1, "shl", IssueType.STRUCTURE, "Flag 'U' found, but no 'cty' header which is required for the U flag", IssueSeverity.ERROR); + ok = false; + } + if (!fUrl) { + logError(errors, "202-08-31", 1, 1, "shl", IssueType.STRUCTURE, "No url found", IssueSeverity.ERROR); + ok = false; + } + if (!fKey) { + logError(errors, "202-08-31", 1, 1, "shl", IssueType.STRUCTURE, "No key found", IssueSeverity.ERROR); + ok = false; + } + return ok; + } + + public void compose(Element e, OutputStream destination, OutputStyle style, String base) throws FHIRException, IOException { + throw new FHIRFormatError("Writing resources is not supported for the SHL format"); + // because then we'd have to try to sign, and we're just not going to be doing that from the element model + } + + public static boolean isTestMode() { + return testMode; + } + + public static void setTestMode(boolean testMode) { + SHLParser.testMode = testMode; + } + + +} diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/TurtleParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/TurtleParser.java index e5f0e70ee..f2b5e731e 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/TurtleParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/TurtleParser.java @@ -1,5 +1,7 @@ package org.hl7.fhir.r5.elementmodel; +import java.io.ByteArrayInputStream; + /* Copyright (c) 2011+, HL7, Inc. All rights reserved. @@ -43,6 +45,7 @@ import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRFormatError; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.elementmodel.Element.SpecialElement; +import org.hl7.fhir.r5.elementmodel.ParserBase.NamedElement; import org.hl7.fhir.r5.formats.IParser.OutputStyle; import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent; import org.hl7.fhir.r5.model.StructureDefinition; @@ -78,53 +81,52 @@ public class TurtleParser extends ParserBase { super(context); } @Override - public List parse(InputStream input) throws IOException, FHIRException { - List res = new ArrayList<>(); + public List parse(InputStream inStream) throws IOException, FHIRException { + byte[] content = TextFile.streamToBytes(inStream); + NamedElement ctxt = new NamedElement("ttl", content); + ByteArrayInputStream stream = new ByteArrayInputStream(content); + Turtle src = new Turtle(); if (policy == ValidationPolicy.EVERYTHING) { try { - src.parse(TextFile.streamToString(input)); + src.parse(TextFile.streamToString(stream)); } catch (Exception e) { - logError(ValidationMessage.NO_RULE_DATE, -1, -1, "(document)", IssueType.INVALID, context.formatMessage(I18nConstants.ERROR_PARSING_TURTLE_, e.getMessage()), IssueSeverity.FATAL); + logError(ctxt.getErrors(), ValidationMessage.NO_RULE_DATE, -1, -1, "(document)", IssueType.INVALID, context.formatMessage(I18nConstants.ERROR_PARSING_TURTLE_, e.getMessage()), IssueSeverity.FATAL); return null; } - Element e = parse(src); - if (e != null) { - res.add(new NamedElement(null, e)); - } + ctxt.setElement(parse(ctxt.getErrors(), src)); } else { - src.parse(TextFile.streamToString(input)); - Element e = parse(src); - if (e != null) { - res.add(new NamedElement(null, e)); - } + src.parse(TextFile.streamToString(stream)); + ctxt.setElement(parse(ctxt.getErrors(), src)); } + List res = new ArrayList<>(); + res.add(ctxt); return res; } - private Element parse(Turtle src) throws FHIRException { + private Element parse(List errors, Turtle src) throws FHIRException { // we actually ignore the stated URL here for (TTLComplex cmp : src.getObjects().values()) { for (String p : cmp.getPredicates().keySet()) { if ((FHIR_URI_BASE + "nodeRole").equals(p) && cmp.getPredicates().get(p).hasValue(FHIR_URI_BASE + "treeRoot")) { - return parse(src, cmp); + return parse(errors, src, cmp); } } } // still here: well, we didn't find a start point String msg = "Error parsing Turtle: unable to find any node maked as the entry point (where " + FHIR_URI_BASE + "nodeRole = " + FHIR_URI_BASE + "treeRoot)"; if (policy == ValidationPolicy.EVERYTHING) { - logError(ValidationMessage.NO_RULE_DATE, -1, -1, "(document)", IssueType.INVALID, msg, IssueSeverity.FATAL); + logError(errors, ValidationMessage.NO_RULE_DATE, -1, -1, "(document)", IssueType.INVALID, msg, IssueSeverity.FATAL); return null; } else { throw new FHIRFormatError(msg); } } - private Element parse(Turtle src, TTLComplex cmp) throws FHIRException { + private Element parse(List errors, Turtle src, TTLComplex cmp) throws FHIRException { TTLObject type = cmp.getPredicates().get("http://www.w3.org/2000/01/rdf-schema#type"); if (type == null) { - logError(ValidationMessage.NO_RULE_DATE, cmp.getLine(), cmp.getCol(), "(document)", IssueType.INVALID, context.formatMessage(I18nConstants.UNKNOWN_RESOURCE_TYPE_MISSING_RDFSTYPE), IssueSeverity.FATAL); + logError(errors, ValidationMessage.NO_RULE_DATE, cmp.getLine(), cmp.getCol(), "(document)", IssueType.INVALID, context.formatMessage(I18nConstants.UNKNOWN_RESOURCE_TYPE_MISSING_RDFSTYPE), IssueSeverity.FATAL); return null; } if (type instanceof TTLList) { @@ -137,7 +139,7 @@ public class TurtleParser extends ParserBase { } } if (!(type instanceof TTLURL)) { - logError(ValidationMessage.NO_RULE_DATE, cmp.getLine(), cmp.getCol(), "(document)", IssueType.INVALID, context.formatMessage(I18nConstants.UNEXPECTED_DATATYPE_FOR_RDFSTYPE), IssueSeverity.FATAL); + logError(errors, ValidationMessage.NO_RULE_DATE, cmp.getLine(), cmp.getCol(), "(document)", IssueType.INVALID, context.formatMessage(I18nConstants.UNEXPECTED_DATATYPE_FOR_RDFSTYPE), IssueSeverity.FATAL); return null; } String name = ((TTLURL) type).getUri(); @@ -145,19 +147,19 @@ public class TurtleParser extends ParserBase { name = name.substring(name.lastIndexOf("/")+1); String path = "/"+name; - StructureDefinition sd = getDefinition(cmp.getLine(), cmp.getCol(), ns, name); + StructureDefinition sd = getDefinition(errors, cmp.getLine(), cmp.getCol(), ns, name); if (sd == null) return null; Element result = new Element(name, new Property(context, sd.getSnapshot().getElement().get(0), sd)); result.markLocation(cmp.getLine(), cmp.getCol()); result.setType(name); - parseChildren(src, path, cmp, result, false); + parseChildren(errors, src, path, cmp, result, false); result.numberChildren(); return result; } - private void parseChildren(Turtle src, String path, TTLComplex object, Element element, boolean primitive) throws FHIRException { + private void parseChildren(List errors, Turtle src, String path, TTLComplex object, Element element, boolean primitive) throws FHIRException { List properties = element.getProperty().getChildProperties(element.getName(), null); Set processed = new HashSet(); @@ -170,10 +172,10 @@ public class TurtleParser extends ParserBase { if (property.isChoice()) { for (TypeRefComponent type : property.getDefinition().getType()) { String eName = property.getName().substring(0, property.getName().length()-3) + Utilities.capitalize(type.getCode()); - parseChild(src, object, element, processed, property, path, getFormalName(property, eName)); + parseChild(errors, src, object, element, processed, property, path, getFormalName(property, eName)); } } else { - parseChild(src, object, element, processed, property, path, getFormalName(property)); + parseChild(errors, src, object, element, processed, property, path, getFormalName(property)); } } @@ -182,13 +184,13 @@ public class TurtleParser extends ParserBase { for (String u : object.getPredicates().keySet()) { if (!processed.contains(u)) { TTLObject n = object.getPredicates().get(u); - logError(ValidationMessage.NO_RULE_DATE, n.getLine(), n.getCol(), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.UNRECOGNISED_PREDICATE_, u), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, n.getLine(), n.getCol(), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.UNRECOGNISED_PREDICATE_, u), IssueSeverity.ERROR); } } } } - private void parseChild(Turtle src, TTLComplex object, Element context, Set processed, Property property, String path, String name) throws FHIRException { + private void parseChild(List errors, Turtle src, TTLComplex object, Element context, Set processed, Property property, String path, String name) throws FHIRException { processed.add(name); String npath = path+"/"+property.getName(); TTLObject e = object.getPredicates().get(FHIR_URI_BASE + name); @@ -197,22 +199,22 @@ public class TurtleParser extends ParserBase { if (property.isList() && (e instanceof TTLList)) { TTLList arr = (TTLList) e; for (TTLObject am : arr.getList()) { - parseChildInstance(src, npath, object, context, property, name, am); + parseChildInstance(errors, src, npath, object, context, property, name, am); } } else { - parseChildInstance(src, npath, object, context, property, name, e); + parseChildInstance(errors, src, npath, object, context, property, name, e); } } - private void parseChildInstance(Turtle src, String npath, TTLComplex object, Element element, Property property, String name, TTLObject e) throws FHIRException { + private void parseChildInstance(List errors, Turtle src, String npath, TTLComplex object, Element element, Property property, String name, TTLObject e) throws FHIRException { if (property.isResource()) - parseResource(src, npath, object, element, property, name, e); + parseResource(errors, src, npath, object, element, property, name, e); else if (e instanceof TTLComplex) { TTLComplex child = (TTLComplex) e; Element n = new Element(tail(name), property).markLocation(e.getLine(), e.getCol()); element.getChildren().add(n); if (property.isPrimitive(property.getType(tail(name)))) { - parseChildren(src, npath, child, n, true); + parseChildren(errors, src, npath, child, n, true); TTLObject val = child.getPredicates().get(FHIR_URI_BASE + "value"); if (val != null) { if (val instanceof TTLLiteral) { @@ -221,13 +223,13 @@ public class TurtleParser extends ParserBase { // todo: check type n.setValue(value); } else - logError(ValidationMessage.NO_RULE_DATE, object.getLine(), object.getCol(), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_PROPERTY_MUST_BE_A_LITERAL_NOT_, "a "+e.getClass().getName()), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, object.getLine(), object.getCol(), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_PROPERTY_MUST_BE_A_LITERAL_NOT_, "a "+e.getClass().getName()), IssueSeverity.ERROR); } } else - parseChildren(src, npath, child, n, false); + parseChildren(errors, src, npath, child, n, false); } else - logError(ValidationMessage.NO_RULE_DATE, object.getLine(), object.getCol(), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_PROPERTY_MUST_BE_A_URI_OR_BNODE_NOT_, "a "+e.getClass().getName()), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, object.getLine(), object.getCol(), npath, IssueType.INVALID, context.formatMessage(I18nConstants.THIS_PROPERTY_MUST_BE_A_URI_OR_BNODE_NOT_, "a "+e.getClass().getName()), IssueSeverity.ERROR); } @@ -235,7 +237,7 @@ public class TurtleParser extends ParserBase { return name.substring(name.lastIndexOf(".")+1); } - private void parseResource(Turtle src, String npath, TTLComplex object, Element element, Property property, String name, TTLObject e) throws FHIRException { + private void parseResource(List errors, Turtle src, String npath, TTLComplex object, Element element, Property property, String name, TTLObject e) throws FHIRException { TTLComplex obj; if (e instanceof TTLComplex) obj = (TTLComplex) e; @@ -243,7 +245,7 @@ public class TurtleParser extends ParserBase { String url = ((TTLURL) e).getUri(); obj = src.getObject(url); if (obj == null) { - logError(ValidationMessage.NO_RULE_DATE, e.getLine(), e.getCol(), npath, IssueType.INVALID, context.formatMessage(I18nConstants.REFERENCE_TO__CANNOT_BE_RESOLVED, url), IssueSeverity.FATAL); + logError(errors, ValidationMessage.NO_RULE_DATE, e.getLine(), e.getCol(), npath, IssueType.INVALID, context.formatMessage(I18nConstants.REFERENCE_TO__CANNOT_BE_RESOLVED, url), IssueSeverity.FATAL); return; } } else @@ -251,7 +253,7 @@ public class TurtleParser extends ParserBase { TTLObject type = obj.getPredicates().get("http://www.w3.org/2000/01/rdf-schema#type"); if (type == null) { - logError(ValidationMessage.NO_RULE_DATE, object.getLine(), object.getCol(), npath, IssueType.INVALID, context.formatMessage(I18nConstants.UNKNOWN_RESOURCE_TYPE_MISSING_RDFSTYPE), IssueSeverity.FATAL); + logError(errors, ValidationMessage.NO_RULE_DATE, object.getLine(), object.getCol(), npath, IssueType.INVALID, context.formatMessage(I18nConstants.UNKNOWN_RESOURCE_TYPE_MISSING_RDFSTYPE), IssueSeverity.FATAL); return; } if (type instanceof TTLList) { @@ -264,14 +266,14 @@ public class TurtleParser extends ParserBase { } } if (!(type instanceof TTLURL)) { - logError(ValidationMessage.NO_RULE_DATE, object.getLine(), object.getCol(), npath, IssueType.INVALID, context.formatMessage(I18nConstants.UNEXPECTED_DATATYPE_FOR_RDFSTYPE), IssueSeverity.FATAL); + logError(errors, ValidationMessage.NO_RULE_DATE, object.getLine(), object.getCol(), npath, IssueType.INVALID, context.formatMessage(I18nConstants.UNEXPECTED_DATATYPE_FOR_RDFSTYPE), IssueSeverity.FATAL); return; } String rt = ((TTLURL) type).getUri(); String ns = rt.substring(0, rt.lastIndexOf("/")); rt = rt.substring(rt.lastIndexOf("/")+1); - StructureDefinition sd = getDefinition(object.getLine(), object.getCol(), ns, rt); + StructureDefinition sd = getDefinition(errors, object.getLine(), object.getCol(), ns, rt); if (sd == null) return; @@ -279,7 +281,7 @@ public class TurtleParser extends ParserBase { element.getChildren().add(n); n.updateProperty(new Property(this.context, sd.getSnapshot().getElement().get(0), sd), SpecialElement.fromProperty(n.getProperty()), property); n.setType(rt); - parseChildren(src, npath, obj, n, false); + parseChildren(errors, src, npath, obj, n, false); } private String getFormalName(Property property) { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/VerticalBarParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/VerticalBarParser.java index e9e2deed5..4773cd671 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/VerticalBarParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/VerticalBarParser.java @@ -32,6 +32,7 @@ package org.hl7.fhir.r5.elementmodel; import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -45,6 +46,7 @@ import org.hl7.fhir.exceptions.FHIRFormatError; import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.formats.IParser.OutputStyle; import org.hl7.fhir.r5.model.StructureDefinition; +import org.hl7.fhir.utilities.TextFile; /** * This class provides special support for parsing v2 by the v2 logical model @@ -452,16 +454,18 @@ public class VerticalBarParser extends ParserBase { private Delimiters delimiters = new Delimiters(); @Override - public List parse(InputStream stream) throws IOException, FHIRFormatError, DefinitionException, FHIRException { + public List parse(InputStream inStream) throws IOException, FHIRFormatError, DefinitionException, FHIRException { StructureDefinition sd = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/v2/StructureDefinition/Message"); Element message = new Element("Message", new Property(context, sd.getSnapshot().getElementFirstRep(), sd)); + byte[] content = TextFile.streamToBytes(inStream); + ByteArrayInputStream stream = new ByteArrayInputStream(content); VerticalBarParserReader reader = new VerticalBarParserReader(new BufferedInputStream(stream), charset); preDecode(reader); while (!reader.isFinished()) // && (getOptions().getSegmentLimit() == 0 || getOptions().getSegmentLimit() > message.getSegments().size())) readSegment(message, reader); List res = new ArrayList<>(); - res.add(new NamedElement(null, message)); + res.add(new NamedElement(null, message, content)); return res; } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/XmlParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/XmlParser.java index e6e555395..cdb71764d 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/XmlParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/XmlParser.java @@ -1,5 +1,7 @@ package org.hl7.fhir.r5.elementmodel; +import java.io.ByteArrayInputStream; + /* Copyright (c) 2011+, HL7, Inc. All rights reserved. @@ -64,6 +66,7 @@ import org.hl7.fhir.r5.utils.formats.XmlLocationAnnotator; import org.hl7.fhir.r5.utils.formats.XmlLocationData; import org.hl7.fhir.utilities.ElementDecoration; import org.hl7.fhir.utilities.StringPair; +import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.i18n.I18nConstants; import org.hl7.fhir.utilities.validation.ValidationMessage; @@ -108,8 +111,12 @@ public class XmlParser extends ParserBase { this.allowXsiLocation = allowXsiLocation; } - public List parse(InputStream stream) throws FHIRFormatError, DefinitionException, FHIRException, IOException { - List res = new ArrayList<>(); + public List parse(InputStream inStream) throws FHIRFormatError, DefinitionException, FHIRException, IOException { + + byte[] content = TextFile.streamToBytes(inStream); + NamedElement context = new NamedElement("xml", content); + + ByteArrayInputStream stream = new ByteArrayInputStream(content); Document doc = null; try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); @@ -125,11 +132,11 @@ public class XmlParser extends ParserBase { if (policy == ValidationPolicy.EVERYTHING) { // The SAX interface appears to not work when reporting the correct version/encoding. // if we can, we'll inspect the header/encoding ourselves - if (stream.markSupported()) { - stream.mark(1024); - version = checkHeader(stream); - stream.reset(); - } + + stream.mark(1024); + version = checkHeader(context.getErrors(), stream); + stream.reset(); + // use a slower parser that keeps location data TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer nullTransformer = transformerFactory.newTransformer(); @@ -161,18 +168,17 @@ public class XmlParser extends ParserBase { if (e.getMessage().contains("lineNumber:") && e.getMessage().contains("columnNumber:")) { int line = Utilities.parseInt(extractVal(e.getMessage(), "lineNumber"), 0); int col = Utilities.parseInt(extractVal(e.getMessage(), "columnNumber"), 0); - logError(ValidationMessage.NO_RULE_DATE, line, col, "(xml)", IssueType.INVALID, e.getMessage().substring(e.getMessage().lastIndexOf(";")+1).trim(), IssueSeverity.FATAL); + logError(context.getErrors(), ValidationMessage.NO_RULE_DATE, line, col, "(xml)", IssueType.INVALID, e.getMessage().substring(e.getMessage().lastIndexOf(";")+1).trim(), IssueSeverity.FATAL); } else { - logError(ValidationMessage.NO_RULE_DATE, 0, 0, "(xml)", IssueType.INVALID, e.getMessage(), IssueSeverity.FATAL); + logError(context.getErrors(), ValidationMessage.NO_RULE_DATE, 0, 0, "(xml)", IssueType.INVALID, e.getMessage(), IssueSeverity.FATAL); } doc = null; } if (doc != null) { - Element e = parse(doc); - if (e != null) { - res.add(new NamedElement(null, e)); - } + context.setElement(parse(context.getErrors(), doc)); } + List res = new ArrayList<>(); + res.add(context); return res; } @@ -182,12 +188,12 @@ public class XmlParser extends ParserBase { src = src.substring(0, src.indexOf(";")).trim(); return src; } - private void checkForProcessingInstruction(Document document) throws FHIRFormatError { + private void checkForProcessingInstruction(List errors, Document document) throws FHIRFormatError { if (policy == ValidationPolicy.EVERYTHING && FormatUtilities.FHIR_NS.equals(document.getDocumentElement().getNamespaceURI())) { Node node = document.getFirstChild(); while (node != null) { if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE) - logError(ValidationMessage.NO_RULE_DATE, line(document, false), col(document, false), "(document)", IssueType.INVALID, context.formatMessage( + logError(errors, ValidationMessage.NO_RULE_DATE, line(document, false), col(document, false), "(document)", IssueType.INVALID, context.formatMessage( I18nConstants.NO_PROCESSING_INSTRUCTIONS_ALLOWED_IN_RESOURCES), IssueSeverity.ERROR); node = node.getNextSibling(); } @@ -205,27 +211,27 @@ public class XmlParser extends ParserBase { return loc == null ? 0 : end ? loc.getEndColumn() : loc.getStartColumn(); } - public Element parse(Document doc) throws FHIRFormatError, DefinitionException, FHIRException, IOException { - checkForProcessingInstruction(doc); + public Element parse(List errors, Document doc) throws FHIRFormatError, DefinitionException, FHIRException, IOException { + checkForProcessingInstruction(errors, doc); org.w3c.dom.Element element = doc.getDocumentElement(); - return parse(element); + return parse(errors, element); } - public Element parse(org.w3c.dom.Element element) throws FHIRFormatError, DefinitionException, FHIRException, IOException { + public Element parse(List errors, org.w3c.dom.Element element) throws FHIRFormatError, DefinitionException, FHIRException, IOException { String ns = element.getNamespaceURI(); String name = element.getLocalName(); String path = "/"+pathPrefix(ns)+name; - StructureDefinition sd = getDefinition(line(element, false), col(element, false), (ns == null ? "noNamespace" : ns), name); + StructureDefinition sd = getDefinition(errors, line(element, false), col(element, false), (ns == null ? "noNamespace" : ns), name); if (sd == null) return null; Element result = new Element(element.getLocalName(), new Property(context, sd.getSnapshot().getElement().get(0), sd)); result.setPath(element.getLocalName()); - checkElement(element, path, result.getProperty()); + checkElement(errors, element, path, result.getProperty()); result.markLocation(line(element, false), col(element, false)); result.setType(element.getLocalName()); - parseChildren(path, element, result); + parseChildren(errors, path, element, result); result.numberChildren(); return result; } @@ -264,33 +270,33 @@ public class XmlParser extends ParserBase { return true; } - private void checkElement(org.w3c.dom.Element element, String path, Property prop) throws FHIRFormatError { + private void checkElement(List errors, org.w3c.dom.Element element, String path, Property prop) throws FHIRFormatError { if (policy == ValidationPolicy.EVERYTHING) { if (empty(element) && FormatUtilities.FHIR_NS.equals(element.getNamespaceURI())) // this rule only applies to FHIR Content - logError(ValidationMessage.NO_RULE_DATE, line(element, false), col(element, false), path, IssueType.INVALID, context.formatMessage(I18nConstants.ELEMENT_MUST_HAVE_SOME_CONTENT), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(element, false), col(element, false), path, IssueType.INVALID, context.formatMessage(I18nConstants.ELEMENT_MUST_HAVE_SOME_CONTENT), IssueSeverity.ERROR); String ns = prop.getXmlNamespace(); String elementNs = element.getNamespaceURI(); if (elementNs == null) { elementNs = "noNamespace"; } if (!elementNs.equals(ns)) - logError(ValidationMessage.NO_RULE_DATE, line(element, false), col(element, false), path, IssueType.INVALID, context.formatMessage(I18nConstants.WRONG_NAMESPACE__EXPECTED_, ns), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(element, false), col(element, false), path, IssueType.INVALID, context.formatMessage(I18nConstants.WRONG_NAMESPACE__EXPECTED_, ns), IssueSeverity.ERROR); } } - public Element parse(org.w3c.dom.Element base, String type) throws Exception { - StructureDefinition sd = getDefinition(0, 0, FormatUtilities.FHIR_NS, type); + public Element parse(List errors, org.w3c.dom.Element base, String type) throws Exception { + StructureDefinition sd = getDefinition(errors, 0, 0, FormatUtilities.FHIR_NS, type); Element result = new Element(base.getLocalName(), new Property(context, sd.getSnapshot().getElement().get(0), sd)); result.setPath(base.getLocalName()); String path = "/"+pathPrefix(base.getNamespaceURI())+base.getLocalName(); - checkElement(base, path, result.getProperty()); + checkElement(errors, base, path, result.getProperty()); result.setType(base.getLocalName()); - parseChildren(path, base, result); + parseChildren(errors, path, base, result); result.numberChildren(); return result; } - private void parseChildren(String path, org.w3c.dom.Element node, Element element) throws FHIRFormatError, FHIRException, IOException, DefinitionException { + private void parseChildren(List errors, String path, org.w3c.dom.Element node, Element element) throws FHIRFormatError, FHIRException, IOException, DefinitionException { // this parsing routine retains the original order in a the XML file, to support validation reapComments(node, element); List properties = element.getProperty().getChildProperties(element.getName(), XMLUtil.getXsiType(node)); @@ -333,7 +339,7 @@ public class XmlParser extends ParserBase { } line = line(nt, end); col = col(nt, end); - logError(ValidationMessage.NO_RULE_DATE, line, col, path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.TEXT_SHOULD_NOT_BE_PRESENT, Utilities.makeSingleLine(n.getTextContent().trim())), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line, col, path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.TEXT_SHOULD_NOT_BE_PRESENT, Utilities.makeSingleLine(n.getTextContent().trim())), IssueSeverity.ERROR); } n = n.getNextSibling(); } @@ -344,7 +350,7 @@ public class XmlParser extends ParserBase { Node attr = node.getAttributes().item(i); String value = attr.getNodeValue(); if (!validAttrValue(value)) { - logError(ValidationMessage.NO_RULE_DATE, line, col, path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.XML_ATTR_VALUE_INVALID, attr.getNodeName()), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line, col, path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.XML_ATTR_VALUE_INVALID, attr.getNodeName()), IssueSeverity.ERROR); } if (!(attr.getNodeName().equals("xmlns") || attr.getNodeName().startsWith("xmlns:"))) { Property property = getAttrProp(properties, attr.getLocalName(), attr.getNamespaceURI()); @@ -369,7 +375,7 @@ public class XmlParser extends ParserBase { ok = ok || (attr.getLocalName().equals("schemaLocation")); // xsi:schemalocation allowed for non FHIR content ok = ok || (hasTypeAttr(element) && attr.getLocalName().equals("type") && FormatUtilities.NS_XSI.equals(attr.getNamespaceURI())); // xsi:type allowed if element says so if (!ok) { - logError(ValidationMessage.NO_RULE_DATE, line(node, false), col(node, false), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.UNDEFINED_ATTRIBUTE__ON__FOR_TYPE__PROPERTIES__, attr.getNodeName(), node.getNodeName(), element.fhirType(), properties), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(node, false), col(node, false), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.UNDEFINED_ATTRIBUTE__ON__FOR_TYPE__PROPERTIES__, attr.getNodeName(), node.getNodeName(), element.fhirType(), properties), IssueSeverity.ERROR); } } } @@ -397,7 +403,7 @@ public class XmlParser extends ParserBase { xhtml = xp.parseHtmlNode((org.w3c.dom.Element) child); if (policy == ValidationPolicy.EVERYTHING) { for (StringPair s : xp.getValidationIssues()) { - logError("2022-11-17", line(child, false), col(child, false), path, IssueType.INVALID, context.formatMessage(s.getName(), s.getValue()), IssueSeverity.ERROR); + logError(errors, "2022-11-17", line(child, false), col(child, false), path, IssueType.INVALID, context.formatMessage(s.getName(), s.getValue()), IssueSeverity.ERROR); } } } @@ -412,7 +418,7 @@ public class XmlParser extends ParserBase { } else { n.setPath(element.getPath()+"."+property.getName()); } - checkElement((org.w3c.dom.Element) child, npath, n.getProperty()); + checkElement(errors, (org.w3c.dom.Element) child, npath, n.getProperty()); boolean ok = true; if (property.isChoice()) { if (property.getDefinition().hasRepresentation(PropertyRepresentation.TYPEATTR)) { @@ -422,7 +428,7 @@ public class XmlParser extends ParserBase { xsiType = ToolingExtensions.readStringExtension(property.getDefinition(), "http://hl7.org/fhir/StructureDefinition/elementdefinition-defaulttype"); n.setType(xsiType); } else { - logError(ValidationMessage.NO_RULE_DATE, line(child, false), col(child, false), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.NO_TYPE_FOUND_ON_, child.getLocalName()), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(child, false), col(child, false), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.NO_TYPE_FOUND_ON_, child.getLocalName()), IssueSeverity.ERROR); ok = false; } } else { @@ -437,18 +443,18 @@ public class XmlParser extends ParserBase { element.getChildren().add(n); if (ok) { if (property.isResource()) - parseResource(npath, (org.w3c.dom.Element) child, n, property); + parseResource(errors, npath, (org.w3c.dom.Element) child, n, property); else - parseChildren(npath, (org.w3c.dom.Element) child, n); + parseChildren(errors, npath, (org.w3c.dom.Element) child, n); } } } else { - logError(ValidationMessage.NO_RULE_DATE, line(child, false), col(child, false), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.UNDEFINED_ELEMENT_, child.getLocalName(), path), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(child, false), col(child, false), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.UNDEFINED_ELEMENT_, child.getLocalName(), path), IssueSeverity.ERROR); } } else if (child.getNodeType() == Node.CDATA_SECTION_NODE){ - logError(ValidationMessage.NO_RULE_DATE, line(child, false), col(child, false), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.CDATA_IS_NOT_ALLOWED), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(child, false), col(child, false), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.CDATA_IS_NOT_ALLOWED), IssueSeverity.ERROR); } else if (!Utilities.existsInList(child.getNodeType(), 3, 8)) { - logError(ValidationMessage.NO_RULE_DATE, line(child, false), col(child, false), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.NODE_TYPE__IS_NOT_ALLOWED, Integer.toString(child.getNodeType())), IssueSeverity.ERROR); + logError(errors, ValidationMessage.NO_RULE_DATE, line(child, false), col(child, false), path, IssueType.STRUCTURE, context.formatMessage(I18nConstants.NODE_TYPE__IS_NOT_ALLOWED, Integer.toString(child.getNodeType())), IssueSeverity.ERROR); } child = child.getNextSibling(); } @@ -542,7 +548,7 @@ public class XmlParser extends ParserBase { throw new FHIRException(context.formatMessage(I18nConstants.UNKNOWN_DATE_FORMAT_, fmt)); } - private void parseResource(String string, org.w3c.dom.Element container, Element parent, Property elementProperty) throws FHIRFormatError, DefinitionException, FHIRException, IOException { + private void parseResource(List errors, String string, org.w3c.dom.Element container, Element parent, Property elementProperty) throws FHIRFormatError, DefinitionException, FHIRException, IOException { org.w3c.dom.Element res = XMLUtil.getFirstChild(container); String name = res.getLocalName(); StructureDefinition sd = context.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(name, null)); @@ -550,7 +556,7 @@ public class XmlParser extends ParserBase { throw new FHIRFormatError(context.formatMessage(I18nConstants.CONTAINED_RESOURCE_DOES_NOT_APPEAR_TO_BE_A_FHIR_RESOURCE_UNKNOWN_NAME_, res.getLocalName())); parent.updateProperty(new Property(context, sd.getSnapshot().getElement().get(0), sd), SpecialElement.fromProperty(parent.getProperty()), elementProperty); parent.setType(name); - parseChildren(res.getLocalName(), res, parent); + parseChildren(errors, res.getLocalName(), res, parent); } private void reapComments(org.w3c.dom.Element element, Element context) { @@ -767,7 +773,7 @@ public class XmlParser extends ParserBase { } } - private String checkHeader(InputStream stream) throws IOException { + private String checkHeader(List errors, InputStream stream) throws IOException { try { // the stream will either start with the UTF-8 BOF or with list) { CommaSeparatedStringBuilder self = new CommaSeparatedStringBuilder(); for (String s : list) { diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/SimpleHTTPClient.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/SimpleHTTPClient.java index 0ef2e6501..d7a177b7e 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/SimpleHTTPClient.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/SimpleHTTPClient.java @@ -25,7 +25,7 @@ public class SimpleHTTPClient { TOKEN } - public class Header { + public static class Header { private String name; private String value; public Header(String name, String value) { @@ -44,7 +44,7 @@ public class SimpleHTTPClient { private static final int MAX_REDIRECTS = 5; private static int counter = 1; - public class HTTPResult { + public static class HTTPResult { private int code; private String contentType; private byte[] content; @@ -90,6 +90,10 @@ public class SimpleHTTPClient { public String getMessage() { return message; + } + + public String getContentAsString() { + return new String(content, StandardCharsets.UTF_8); } } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ResourceChecker.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ResourceChecker.java index 0f3f7de61..17dfc6e48 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ResourceChecker.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ResourceChecker.java @@ -69,6 +69,9 @@ public class ResourceChecker { if (src.startsWith("shc:/")) { return FhirFormat.SHC; } + if (src.startsWith("shlink:/") || src.contains("#shlink:/")) { + return FhirFormat.SHL; + } } catch (Exception e) { } return Manager.FhirFormat.TEXT; @@ -101,9 +104,13 @@ public class ResourceChecker { } try { String s = new String(cnt, StandardCharsets.UTF_8); - if (s.startsWith("shc:/")) + if (s.startsWith("shlink:/") || s.contains("#shlink:/")) { + return FhirFormat.SHL; + } + if (s.startsWith("shc:/")) { s = SHCParser.decodeQRCode(s); - JWT jwt = new SHCParser(context).decodeJWT(s); + } + JWT jwt = new SHCParser(context).decodeJWT(null, s); return Manager.FhirFormat.SHC; } catch (Exception e) { if (debug) { diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java index 4ab08508a..1ce1becfe 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidationEngine.java @@ -700,7 +700,7 @@ public class ValidationEngine implements IValidatorResourceFetcher, IValidationP if (sourceSD.getKind() == StructureDefinition.StructureDefinitionKind.LOGICAL) { parser.setLogical(sourceSD); } - org.hl7.fhir.r5.elementmodel.Element src = parser.parseSingle(new ByteArrayInputStream(source.getBytes())); + org.hl7.fhir.r5.elementmodel.Element src = parser.parseSingle(new ByteArrayInputStream(source.getBytes()), null); scu.transform(null, src, map, resource); resource.populatePaths(null); return resource; diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java index 15adbcec2..530dcb8bf 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java @@ -514,6 +514,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private Map crLookups = new HashMap<>(); private boolean logProgress; private CodingsObserver codingObserver; + public List validatedContent; public InstanceValidator(@Nonnull IWorkerContext theContext, @Nonnull IEvaluationContext hostServices, @Nonnull XVerExtensionManager xverManager) { super(theContext, xverManager, false); @@ -724,7 +725,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat if (parser instanceof XmlParser) { ((XmlParser) parser).setAllowXsiLocation(allowXsiLocation); } - parser.setupValidation(ValidationPolicy.EVERYTHING, errors); + parser.setupValidation(ValidationPolicy.EVERYTHING); if (parser instanceof XmlParser) { ((XmlParser) parser).setAllowXsiLocation(allowXsiLocation); } @@ -732,14 +733,14 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat ((JsonParser) parser).setAllowComments(allowComments); } long t = System.nanoTime(); - List list = null; + validatedContent = null; try { - list = parser.parse(stream); + validatedContent = parser.parse(stream); } catch (IOException e1) { throw new FHIRException(e1); } timeTracker.load(t); - if (list != null && !list.isEmpty()) { + if (validatedContent != null && !validatedContent.isEmpty()) { String url = parser.getImpliedProfile(); if (url != null) { StructureDefinition sd = context.fetchResource(StructureDefinition.class, url); @@ -749,11 +750,14 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat profiles.add(sd); } } - for (NamedElement ne : list) { - validate(appContext, errors, ne.getName(), ne.getElement(), profiles); + for (NamedElement ne : validatedContent) { + if (ne.getElement() != null) { + validate(appContext, ne.getErrors(), validatedContent.size() > 1 ? ne.getName() : null, ne.getElement(), profiles); + } + errors.addAll(ne.getErrors()); } } - return (list == null || list.isEmpty()) ? null : list.get(0).getElement(); // todo: this is broken, but fixing it really complicates things elsewhere, so we do this for now + return (validatedContent == null || validatedContent.isEmpty()) ? null : validatedContent.get(0).getElement(); // todo: this is broken, but fixing it really complicates things elsewhere, so we do this for now } @Override @@ -796,11 +800,11 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat @Override public org.hl7.fhir.r5.elementmodel.Element validate(Object appContext, List errors, org.w3c.dom.Element element, List profiles) throws FHIRException { XmlParser parser = new XmlParser(context); - parser.setupValidation(ValidationPolicy.EVERYTHING, errors); + parser.setupValidation(ValidationPolicy.EVERYTHING); long t = System.nanoTime(); Element e; try { - e = parser.parse(element); + e = parser.parse(errors, element); } catch (IOException e1) { throw new FHIRException(e1); } @@ -828,11 +832,11 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat @Override public org.hl7.fhir.r5.elementmodel.Element validate(Object appContext, List errors, Document document, List profiles) throws FHIRException { XmlParser parser = new XmlParser(context); - parser.setupValidation(ValidationPolicy.EVERYTHING, errors); + parser.setupValidation(ValidationPolicy.EVERYTHING); long t = System.nanoTime(); Element e; try { - e = parser.parse(document); + e = parser.parse(errors, document); } catch (IOException e1) { throw new FHIRException(e1); } @@ -859,9 +863,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat @Override public org.hl7.fhir.r5.elementmodel.Element validate(Object appContext, List errors, JsonObject object, List profiles) throws FHIRException { JsonParser parser = new JsonParser(context, new ProfileUtilities(context, null, null, fpe)); - parser.setupValidation(ValidationPolicy.EVERYTHING, errors); + parser.setupValidation(ValidationPolicy.EVERYTHING); long t = System.nanoTime(); - Element e = parser.parse(object); + Element e = parser.parse(errors, object); timeTracker.load(t); if (e != null) validate(appContext, errors, null, e, profiles); diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/R4R5MapTester.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/R4R5MapTester.java index 0b6128ada..8e0bd2148 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/R4R5MapTester.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/R4R5MapTester.java @@ -348,7 +348,7 @@ public class R4R5MapTester implements IValidatorResourceFetcher { private int testRoundTrip(JsonObject json, StructureDefinition sd, StructureDefinition tsd, ResolvedGroup tgtG, ResolvedGroup srcG, Stats stats, InputStream stream, String code) throws FHIRFormatError, DefinitionException, FHIRException, IOException { stats.example(); - Element r4 = new org.hl7.fhir.r5.elementmodel.JsonParser(context).setLogical(tsd).parseSingle(stream); + Element r4 = new org.hl7.fhir.r5.elementmodel.JsonParser(context).setLogical(tsd).parseSingle(stream, null); stats.parsed(); int elementCountBefore = r4.countDescendents()+1; String id = r4.getIdBase(); diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/r5/test/GeneralTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/r5/test/GeneralTests.java index a5325d288..37778e243 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/r5/test/GeneralTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/r5/test/GeneralTests.java @@ -21,9 +21,9 @@ public class GeneralTests { org.hl7.fhir.r5.elementmodel.XmlParser xp = new org.hl7.fhir.r5.elementmodel.XmlParser(TestingUtilities.getSharedWorkerContext()); xp.setAllowXsiLocation(true); List errorList = new ArrayList<>(); - xp.setupValidation(ValidationPolicy.EVERYTHING, errorList); + xp.setupValidation(ValidationPolicy.EVERYTHING); try { - Object resource = xp.parse(stream); + xp.parseSingle(stream, errorList); } catch (Exception e) { e.printStackTrace(); } diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTests.java index 8548922ab..42b27d1f5 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/validation/tests/ValidationTests.java @@ -34,6 +34,7 @@ import org.hl7.fhir.r5.elementmodel.Element; import org.hl7.fhir.r5.elementmodel.Manager; import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat; import org.hl7.fhir.r5.elementmodel.ObjectConverter; +import org.hl7.fhir.r5.elementmodel.SHLParser; import org.hl7.fhir.r5.formats.IParser.OutputStyle; import org.hl7.fhir.r5.formats.JsonParser; import org.hl7.fhir.r5.formats.XmlParser; @@ -170,6 +171,7 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe TestingUtilities.injectCorePackageLoader(); CacheVerificationLogger logger = new CacheVerificationLogger(); +// SHLParser.setTestMode(true); long setup = System.nanoTime(); logOutput("---- " + name + " ---------------------------------------------------------------- ("+System.getProperty("java.vm.name")+")"); @@ -692,16 +694,16 @@ public class ValidationTests implements IEvaluationContext, IValidatorResourceFe if (url.equals("Patient/test")) { res = new ObjectConverter(vCurr.getContext()).convert(new Patient()); } else if (TestingUtilities.findTestResource("validator", url.replace("/", "-").toLowerCase() + ".json")) { - res = Manager.makeParser(vCurr.getContext(), FhirFormat.JSON).parseSingle(TestingUtilities.loadTestResourceStream("validator", url.replace("/", "-").toLowerCase() + ".json")); + res = Manager.makeParser(vCurr.getContext(), FhirFormat.JSON).parseSingle(TestingUtilities.loadTestResourceStream("validator", url.replace("/", "-").toLowerCase() + ".json"), null); } else if (TestingUtilities.findTestResource("validator", url.replace("/", "-").toLowerCase() + ".xml")) { - res = Manager.makeParser(vCurr.getContext(), FhirFormat.XML).parseSingle(TestingUtilities.loadTestResourceStream("validator", url.replace("/", "-").toLowerCase() + ".xml")); + res = Manager.makeParser(vCurr.getContext(), FhirFormat.XML).parseSingle(TestingUtilities.loadTestResourceStream("validator", url.replace("/", "-").toLowerCase() + ".xml"), null); } if (res == null && url.contains("/")) { String tail = url.substring(url.indexOf("/") + 1); if (TestingUtilities.findTestResource("validator", tail.replace("/", "-").toLowerCase() + ".json")) { - res = Manager.makeParser(vCurr.getContext(), FhirFormat.JSON).parseSingle(TestingUtilities.loadTestResourceStream("validator", tail.replace("/", "-").toLowerCase() + ".json")); + res = Manager.makeParser(vCurr.getContext(), FhirFormat.JSON).parseSingle(TestingUtilities.loadTestResourceStream("validator", tail.replace("/", "-").toLowerCase() + ".json"), null); } else if (TestingUtilities.findTestResource("validator", tail.replace("/", "-").toLowerCase() + ".xml")) { - res = Manager.makeParser(vCurr.getContext(), FhirFormat.XML).parseSingle(TestingUtilities.loadTestResourceStream("validator", tail.replace("/", "-").toLowerCase() + ".xml")); + res = Manager.makeParser(vCurr.getContext(), FhirFormat.XML).parseSingle(TestingUtilities.loadTestResourceStream("validator", tail.replace("/", "-").toLowerCase() + ".xml"), null); } } return res; diff --git a/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/cvx.cache b/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/cvx.cache index 0cc314938..3f595bde8 100644 --- a/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/cvx.cache +++ b/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/cvx.cache @@ -15,7 +15,6 @@ v: { "code" : "207", "system" : "http://hl7.org/fhir/sid/cvx", "version" : "20210406", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -37,7 +36,6 @@ v: { "severity" : "error", "error" : "Wrong Display Name 'X SARS-COV-2 (COVID-19) vaccine, mRNA, spike protein, LNP, preservative free, 100 mcg/0.5mL dose' for http://hl7.org/fhir/sid/cvx#207 - should be 'SARS-COV-2 (COVID-19) vaccine, mRNA, spike protein, LNP, preservative free, 100 mcg/0.5mL dose' (for the language(s) '--') (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -59,7 +57,6 @@ v: { "code" : "208", "system" : "http://hl7.org/fhir/sid/cvx", "version" : "20210406", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -81,7 +78,6 @@ v: { "code" : "208", "system" : "http://hl7.org/fhir/sid/cvx", "version" : "20210406", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -102,6 +98,225 @@ v: { "severity" : "error", "error" : "Unknown Code '209' in the system 'http://hl7.org/fhir/sid/cvx'; The provided code 'http://hl7.org/fhir/sid/cvx#209' is not in the value set 'http://hl7.org/fhir/ValueSet/@all' (from Tx-Server)", "class" : "UNKNOWN", + "issues" : { + "resourceType" : "OperationOutcome" +} + +} +------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://hl7.org/fhir/sid/cvx", + "code" : "115" +}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": { + "resourceType" : "Parameters", + "parameter" : [{ + "name" : "profile-url", + "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891" + }] +}}#### +v: { + "display" : "tetanus toxoid, reduced diphtheria toxoid, and acellular pertussis vaccine, adsorbed", + "code" : "115", + "system" : "http://hl7.org/fhir/sid/cvx", + "version" : "20210406", + "unknown-systems" : "", + "issues" : { + "resourceType" : "OperationOutcome" +} + +} +------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://hl7.org/fhir/sid/cvx", + "code" : "10" +}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": { + "resourceType" : "Parameters", + "parameter" : [{ + "name" : "profile-url", + "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891" + }] +}}#### +v: { + "display" : "poliovirus vaccine, inactivated", + "code" : "10", + "system" : "http://hl7.org/fhir/sid/cvx", + "version" : "20210406", + "unknown-systems" : "", + "issues" : { + "resourceType" : "OperationOutcome" +} + +} +------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://hl7.org/fhir/sid/cvx", + "code" : "85" +}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": { + "resourceType" : "Parameters", + "parameter" : [{ + "name" : "profile-url", + "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891" + }] +}}#### +v: { + "display" : "hepatitis A vaccine, unspecified formulation", + "code" : "85", + "system" : "http://hl7.org/fhir/sid/cvx", + "version" : "20210406", + "unknown-systems" : "", + "issues" : { + "resourceType" : "OperationOutcome" +} + +} +------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://hl7.org/fhir/sid/cvx", + "code" : "25" +}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": { + "resourceType" : "Parameters", + "parameter" : [{ + "name" : "profile-url", + "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891" + }] +}}#### +v: { + "display" : "typhoid vaccine, live, oral", + "code" : "25", + "system" : "http://hl7.org/fhir/sid/cvx", + "version" : "20210406", + "unknown-systems" : "", + "issues" : { + "resourceType" : "OperationOutcome" +} + +} +------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://hl7.org/fhir/sid/cvx", + "code" : "37" +}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": { + "resourceType" : "Parameters", + "parameter" : [{ + "name" : "profile-url", + "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891" + }] +}}#### +v: { + "display" : "yellow fever vaccine", + "code" : "37", + "system" : "http://hl7.org/fhir/sid/cvx", + "version" : "20210406", + "unknown-systems" : "", + "issues" : { + "resourceType" : "OperationOutcome" +} + +} +------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://hl7.org/fhir/sid/cvx", + "code" : "185" +}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": { + "resourceType" : "Parameters", + "parameter" : [{ + "name" : "profile-url", + "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891" + }] +}}#### +v: { + "display" : "Seasonal, quadrivalent, recombinant, injectable influenza vaccine, preservative free", + "code" : "185", + "system" : "http://hl7.org/fhir/sid/cvx", + "version" : "20210406", + "unknown-systems" : "", + "issues" : { + "resourceType" : "OperationOutcome" +} + +} +------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://hl7.org/fhir/sid/cvx", + "code" : "150" +}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": { + "resourceType" : "Parameters", + "parameter" : [{ + "name" : "profile-url", + "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891" + }] +}}#### +v: { + "display" : "Influenza, injectable, quadrivalent, preservative free", + "code" : "150", + "system" : "http://hl7.org/fhir/sid/cvx", + "version" : "20210406", + "unknown-systems" : "", + "issues" : { + "resourceType" : "OperationOutcome" +} + +} +------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://hl7.org/fhir/sid/cvx", + "code" : "207" +}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": { + "resourceType" : "Parameters", + "parameter" : [{ + "name" : "profile-url", + "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891" + }] +}}#### +v: { + "display" : "SARS-COV-2 (COVID-19) vaccine, mRNA, spike protein, LNP, preservative free, 100 mcg/0.5mL dose", + "code" : "207", + "system" : "http://hl7.org/fhir/sid/cvx", + "version" : "20210406", + "unknown-systems" : "", + "issues" : { + "resourceType" : "OperationOutcome" +} + +} +------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://hl7.org/fhir/sid/cvx", + "code" : "171" +}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": { + "resourceType" : "Parameters", + "parameter" : [{ + "name" : "profile-url", + "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891" + }] +}}#### +v: { + "display" : "Influenza, injectable, Madin Darby Canine Kidney, preservative free, quadrivalent", + "code" : "171", + "system" : "http://hl7.org/fhir/sid/cvx", + "version" : "20210406", + "unknown-systems" : "", + "issues" : { + "resourceType" : "OperationOutcome" +} + +} +------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://hl7.org/fhir/sid/cvx", + "code" : "88" +}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": { + "resourceType" : "Parameters", + "parameter" : [{ + "name" : "profile-url", + "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891" + }] +}}#### +v: { + "display" : "influenza virus vaccine, unspecified formulation", + "code" : "88", + "system" : "http://hl7.org/fhir/sid/cvx", + "version" : "20210406", "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" diff --git a/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/http___standardterms.edqm.eu.cache b/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/http___standardterms.edqm.eu.cache index a72e6eb41..86d9f0349 100644 --- a/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/http___standardterms.edqm.eu.cache +++ b/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/http___standardterms.edqm.eu.cache @@ -15,6 +15,28 @@ v: { "code" : "20049000", "system" : "http://standardterms.edqm.eu", "version" : "5 March 2019", + "issues" : { + "resourceType" : "OperationOutcome" +} + +} +------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://standardterms.edqm.eu", + "code" : "20053000", + "display" : "Oral use" +}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": { + "resourceType" : "Parameters", + "parameter" : [{ + "name" : "profile-url", + "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891" + }] +}}#### +v: { + "display" : "Oral use", + "code" : "20053000", + "system" : "http://standardterms.edqm.eu", + "version" : "5 March 2019", "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" diff --git a/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/iso3166.cache b/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/iso3166.cache index e1000d804..f75fd1f40 100644 --- a/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/iso3166.cache +++ b/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/iso3166.cache @@ -15,7 +15,6 @@ v: { "code" : "NO", "system" : "urn:iso:std:iso:3166", "version" : "2018", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -37,7 +36,6 @@ v: { "code" : "US", "system" : "urn:iso:std:iso:3166", "version" : "2018", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -59,7 +57,6 @@ v: { "code" : "US", "system" : "urn:iso:std:iso:3166", "version" : "2018", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -81,6 +78,27 @@ v: { "code" : "NO", "system" : "urn:iso:std:iso:3166", "version" : "2018", + "issues" : { + "resourceType" : "OperationOutcome" +} + +} +------------------------------------------------------------------------------------- +{"code" : { + "system" : "urn:iso:std:iso:3166", + "code" : "NO", + "display" : "Alderney" +}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": { + "resourceType" : "Parameters", + "parameter" : [{ + "name" : "profile-url", + "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891" + }] +}}#### +v: { + "severity" : "error", + "error" : "Wrong Display Name 'Alderney' for urn:iso:std:iso:3166#NO - should be 'Norway' (for the language(s) '--') (from Tx-Server)", + "class" : "UNKNOWN", "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" diff --git a/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/loinc.cache b/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/loinc.cache index 96d991ded..060df9b1d 100644 --- a/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/loinc.cache +++ b/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/loinc.cache @@ -14,7 +14,6 @@ v: { "severity" : "error", "error" : "Wrong Display Name 'O2 % BldC Oximetry' for http://loinc.org#59408-5 - should be one of 26 choices: 'Oxygen saturation in Arterial blood by Pulse oximetry', 'SaO2 % BldA PulseOx', 'O2 SaO2' (pl-PL), 'saturacja krwi tlenem' (pl-PL), 'MFr O2' (zh-CN), 'tO2' (zh-CN), '总氧' (zh-CN), '氧气 SaO2 动脉血 动脉血O2饱和度 可用数量表示的' (zh-CN), '定量性' (zh-CN), '数值型' (zh-CN), '数量型' (zh-CN), '连续数值型标尺 时刻' (zh-CN), '随机' (zh-CN), '随意' (zh-CN), '瞬间 肺部测量指标与呼吸机管理 脉搏血氧测定法' (zh-CN), '脉搏血氧定量' (zh-CN), '脉搏血氧测定' (zh-CN), '脉搏血氧仪 血氧测定法 饱和 饱和状态 饱和程度' (zh-CN), 'O2-Sättigung' (de-DE), 'Frazione di massa Gestione ventilazione polmonare Punto nel tempo (episodio) Sangue arterioso' (it-IT), 'Oksijen doymuşluğu' (tr-TR), 'Количественный Кровь артериальная Массовая доля Насыщение кислородом Оксигемометрия' (ru-RU), 'Гемоксиметрия Точка во времени' (ru-RU), 'Момент' (ru-RU), 'zuurstofsaturatiemeting' (nl-NL) or 'O2 SatO2' (fr-BE) (for the language(s) '--') (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -37,7 +36,6 @@ v: { "code" : "2708-6", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -60,7 +58,6 @@ v: { "code" : "3150-0", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -82,7 +79,6 @@ v: { "severity" : "error", "error" : "Wrong Display Name 'Flow Rate' for http://loinc.org#3151-8 - should be one of 37 choices: 'Inhaled oxygen flow rate', 'Inhaled O2 flow rate', 'O2' (zh-CN), 'tO2' (zh-CN), '总氧' (zh-CN), '氧气 体积速率(单位时间)' (zh-CN), '单位时间内体积的变化速率' (zh-CN), '流量 可用数量表示的' (zh-CN), '定量性' (zh-CN), '数值型' (zh-CN), '数量型' (zh-CN), '连续数值型标尺 吸入气' (zh-CN), '吸入气体' (zh-CN), '吸入的空气 所吸入的氧' (zh-CN), '已吸入的氧气 时刻' (zh-CN), '随机' (zh-CN), '随意' (zh-CN), '瞬间 气 气体类 空气' (zh-CN), 'Inhaled O2' (pt-BR), 'vRate' (pt-BR), 'Volume rate' (pt-BR), 'Flow' (pt-BR), 'Point in time' (pt-BR), 'Random' (pt-BR), 'IhG' (pt-BR), 'Inhaled Gas' (pt-BR), 'Inspired' (pt-BR), 'Quantitative' (pt-BR), 'QNT' (pt-BR), 'Quant' (pt-BR), 'Quan' (pt-BR), 'Gases' (pt-BR), 'Clinico Gas inalati Punto nel tempo (episodio) Tasso di Volume' (it-IT), 'Количественный Объемная скорость Точка во времени' (ru-RU), 'Момент' (ru-RU), 'ingeademde O2' (nl-NL) or 'O2-Zufuhr' (de-AT) (for the language(s) '--') (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -104,7 +100,6 @@ v: { "code" : "59408-5", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -125,7 +120,6 @@ v: { "severity" : "error", "error" : "The provided code 'http://loinc.org#2708-6' is not in the value set 'http://hl7.org/fhir/us/core/ValueSet/us-core-vital-signs--0|4.0.0' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -147,7 +141,6 @@ v: { "code" : "2708-6", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -169,7 +162,6 @@ v: { "severity" : "error", "error" : "Wrong Display Name 'O2 % BldC Oximetry' for http://loinc.org#59408-5 - should be one of 26 choices: 'Oxygen saturation in Arterial blood by Pulse oximetry', 'SaO2 % BldA PulseOx', 'O2 SaO2' (pl-PL), 'saturacja krwi tlenem' (pl-PL), 'MFr O2' (zh-CN), 'tO2' (zh-CN), '总氧' (zh-CN), '氧气 SaO2 动脉血 动脉血O2饱和度 可用数量表示的' (zh-CN), '定量性' (zh-CN), '数值型' (zh-CN), '数量型' (zh-CN), '连续数值型标尺 时刻' (zh-CN), '随机' (zh-CN), '随意' (zh-CN), '瞬间 肺部测量指标与呼吸机管理 脉搏血氧测定法' (zh-CN), '脉搏血氧定量' (zh-CN), '脉搏血氧测定' (zh-CN), '脉搏血氧仪 血氧测定法 饱和 饱和状态 饱和程度' (zh-CN), 'O2-Sättigung' (de-DE), 'Frazione di massa Gestione ventilazione polmonare Punto nel tempo (episodio) Sangue arterioso' (it-IT), 'Oksijen doymuşluğu' (tr-TR), 'Количественный Кровь артериальная Массовая доля Насыщение кислородом Оксигемометрия' (ru-RU), 'Гемоксиметрия Точка во времени' (ru-RU), 'Момент' (ru-RU), 'zuurstofsaturatiemeting' (nl-NL) or 'O2 SatO2' (fr-BE) (for the language(s) '--') (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -192,7 +184,6 @@ v: { "code" : "2708-6", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -214,7 +205,6 @@ v: { "code" : "59408-5", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -236,7 +226,6 @@ v: { "code" : "2708-6", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -258,7 +247,6 @@ v: { "code" : "3150-0", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -281,7 +269,6 @@ v: { "code" : "3150-0", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -303,7 +290,6 @@ v: { "code" : "3150-0", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -325,7 +311,6 @@ v: { "code" : "3151-8", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -347,7 +332,6 @@ v: { "severity" : "error", "error" : "Wrong Display Name 'Flow Rate' for http://loinc.org#3151-8 - should be one of 37 choices: 'Inhaled oxygen flow rate', 'Inhaled O2 flow rate', 'O2' (zh-CN), 'tO2' (zh-CN), '总氧' (zh-CN), '氧气 体积速率(单位时间)' (zh-CN), '单位时间内体积的变化速率' (zh-CN), '流量 可用数量表示的' (zh-CN), '定量性' (zh-CN), '数值型' (zh-CN), '数量型' (zh-CN), '连续数值型标尺 吸入气' (zh-CN), '吸入气体' (zh-CN), '吸入的空气 所吸入的氧' (zh-CN), '已吸入的氧气 时刻' (zh-CN), '随机' (zh-CN), '随意' (zh-CN), '瞬间 气 气体类 空气' (zh-CN), 'Inhaled O2' (pt-BR), 'vRate' (pt-BR), 'Volume rate' (pt-BR), 'Flow' (pt-BR), 'Point in time' (pt-BR), 'Random' (pt-BR), 'IhG' (pt-BR), 'Inhaled Gas' (pt-BR), 'Inspired' (pt-BR), 'Quantitative' (pt-BR), 'QNT' (pt-BR), 'Quant' (pt-BR), 'Quan' (pt-BR), 'Gases' (pt-BR), 'Clinico Gas inalati Punto nel tempo (episodio) Tasso di Volume' (it-IT), 'Количественный Объемная скорость Точка во времени' (ru-RU), 'Момент' (ru-RU), 'ingeademde O2' (nl-NL) or 'O2-Zufuhr' (de-AT) (for the language(s) '--') (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -369,7 +353,6 @@ v: { "code" : "3151-8", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -413,7 +396,6 @@ v: { "code" : "5792-7", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -435,7 +417,6 @@ v: { "code" : "11502-2", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -457,7 +438,6 @@ v: { "code" : "11502-2", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -479,7 +459,6 @@ v: { "code" : "11502-2", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -500,7 +479,6 @@ v: { "code" : "60591-5", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -522,7 +500,6 @@ v: { "code" : "60591-5", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -543,7 +520,6 @@ v: { "code" : "60591-5", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -565,7 +541,6 @@ v: { "code" : "76437-3", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -587,7 +562,6 @@ v: { "code" : "10160-0", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -609,7 +583,6 @@ v: { "code" : "48765-2", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -631,7 +604,6 @@ v: { "code" : "11450-4", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -653,7 +625,6 @@ v: { "code" : "47519-4", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -675,7 +646,6 @@ v: { "code" : "30954-2", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -697,7 +667,6 @@ v: { "code" : "8716-3", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -719,7 +688,6 @@ v: { "code" : "29762-2", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -741,7 +709,6 @@ v: { "code" : "10162-6", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -763,7 +730,6 @@ v: { "code" : "51899-3", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -786,7 +752,6 @@ v: { "code" : "46418-0", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -809,7 +774,6 @@ v: { "code" : "77140-2", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -832,7 +796,6 @@ v: { "code" : "4535-1", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -855,7 +818,6 @@ v: { "code" : "29463-7", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -878,7 +840,6 @@ v: { "code" : "8302-2", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -901,7 +862,6 @@ v: { "code" : "39156-5", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -924,7 +884,6 @@ v: { "code" : "85354-9", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -947,7 +906,6 @@ v: { "code" : "8480-6", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -970,7 +928,6 @@ v: { "code" : "8462-4", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -993,7 +950,6 @@ v: { "code" : "883-9", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1016,7 +972,6 @@ v: { "code" : "57024-2", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1038,7 +993,6 @@ v: { "code" : "59284-0", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1060,7 +1014,6 @@ v: { "code" : "59284-0", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1082,7 +1035,6 @@ v: { "code" : "46418-0", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1105,7 +1057,6 @@ v: { "code" : "46418-0", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1127,7 +1078,6 @@ v: { "code" : "46418-0", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1149,7 +1099,6 @@ v: { "code" : "77140-2", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1172,7 +1121,6 @@ v: { "code" : "77140-2", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1194,7 +1142,6 @@ v: { "code" : "77140-2", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1216,7 +1163,6 @@ v: { "code" : "4535-1", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1239,7 +1185,6 @@ v: { "code" : "4535-1", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1261,7 +1206,6 @@ v: { "code" : "4535-1", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1283,7 +1227,6 @@ v: { "code" : "29463-7", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1306,7 +1249,6 @@ v: { "code" : "29463-7", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1328,7 +1270,6 @@ v: { "code" : "29463-7", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1350,7 +1291,6 @@ v: { "code" : "8302-2", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1373,7 +1313,6 @@ v: { "code" : "8302-2", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1395,7 +1334,6 @@ v: { "code" : "8302-2", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1417,7 +1355,6 @@ v: { "code" : "39156-5", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1440,7 +1377,6 @@ v: { "code" : "39156-5", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1462,7 +1398,6 @@ v: { "code" : "39156-5", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1484,7 +1419,6 @@ v: { "code" : "85354-9", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1507,7 +1441,6 @@ v: { "code" : "85354-9", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1529,7 +1462,6 @@ v: { "code" : "85354-9", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1551,7 +1483,6 @@ v: { "code" : "8480-6", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1574,7 +1505,6 @@ v: { "code" : "8480-6", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1596,7 +1526,6 @@ v: { "code" : "8480-6", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1618,7 +1547,6 @@ v: { "code" : "8462-4", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1641,7 +1569,6 @@ v: { "code" : "8462-4", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1663,7 +1590,6 @@ v: { "code" : "8462-4", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1684,7 +1610,6 @@ v: { "severity" : "error", "error" : "The provided code 'http://loinc.org#883-9' is not in the value set 'http://hl7.org/fhir/ValueSet/observation-vitalsignresult--0|4.0.1' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1705,7 +1630,6 @@ v: { "severity" : "error", "error" : "The provided code 'http://loinc.org#46418-0' is not in the value set 'http://hl7.org/fhir/ValueSet/observation-vitalsignresult--0|4.0.1' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1726,7 +1650,6 @@ v: { "severity" : "error", "error" : "The provided code 'http://loinc.org#77140-2' is not in the value set 'http://hl7.org/fhir/ValueSet/observation-vitalsignresult--0|4.0.1' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1747,7 +1670,6 @@ v: { "severity" : "error", "error" : "The provided code 'http://loinc.org#4535-1' is not in the value set 'http://hl7.org/fhir/ValueSet/observation-vitalsignresult--0|4.0.1' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1768,7 +1690,6 @@ v: { "severity" : "error", "error" : "The provided code 'http://loinc.org#29463-7' is not in the value set 'https://mednet.swiss/fhir/ValueSet/mni-obs-laboratory--0|0.5.0' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1789,7 +1710,6 @@ v: { "severity" : "error", "error" : "The provided code 'http://loinc.org#8302-2' is not in the value set 'https://mednet.swiss/fhir/ValueSet/mni-obs-laboratory--0|0.5.0' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1810,7 +1730,6 @@ v: { "severity" : "error", "error" : "The provided code 'http://loinc.org#39156-5' is not in the value set 'https://mednet.swiss/fhir/ValueSet/mni-obs-laboratory--0|0.5.0' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1831,7 +1750,6 @@ v: { "severity" : "error", "error" : "The provided code 'http://loinc.org#85354-9' is not in the value set 'https://mednet.swiss/fhir/ValueSet/mni-obs-laboratory--0|0.5.0' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1852,7 +1770,6 @@ v: { "severity" : "error", "error" : "The provided code 'http://loinc.org#883-9' is not in the value set 'https://mednet.swiss/fhir/ValueSet/mni-obs-laboratory--0|0.5.0' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1874,7 +1791,6 @@ v: { "code" : "60591-5", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1897,7 +1813,6 @@ v: { "code" : "60591-5", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1919,7 +1834,6 @@ v: { "code" : "60591-5", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1942,7 +1856,6 @@ v: { "code" : "48765-2", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1965,7 +1878,6 @@ v: { "code" : "10160-0", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1988,7 +1900,6 @@ v: { "code" : "11450-4", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2010,7 +1921,6 @@ v: { "severity" : "error", "error" : "Wrong Display Name 'NDC labeler code request' for http://loinc.org#51726-8 - should be one of 22 choices: 'FDA product label NDC labeler code request', 'FDA label NDC labeler code request', 'FDA 药品标签 National Drug Code' (zh-CN), 'NDC' (zh-CN), '国家药品验证号' (zh-CN), '国家药品代码' (zh-CN), '美国国家药品代码' (zh-CN), '全国药品代码' (zh-CN), 'NDC labeler code' (zh-CN), 'NDC 标识者识别代码' (zh-CN), 'NDC 厂家号' (zh-CN), 'NDC 贴签厂商代码请求' (zh-CN), 'NDC 标签号申请 叙述' (zh-CN), '叙述性文字' (zh-CN), '报告' (zh-CN), '报告型' (zh-CN), '文字叙述' (zh-CN), '文本叙述型' (zh-CN), '文本描述' (zh-CN), '文本描述型 监管类文档' (zh-CN), 'Documentazione normativa Etichetta di prodotto della Food and Drug Administ' (it-IT) or 'Описательный' (ru-RU) (for the language(s) '--') (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2032,7 +1942,6 @@ v: { "severity" : "error", "error" : "Unknown Code 'X-34133-9' in the system 'http://loinc.org'; The provided code 'http://loinc.org#X-34133-9' is not in the value set 'http://hl7.org/fhir/ValueSet/@all' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2053,7 +1962,6 @@ v: { "severity" : "error", "error" : "Unknown Code 'X-34133-9' in the system 'http://loinc.org'; The provided code 'http://loinc.org#X-34133-9' is not in the value set 'http://hl7.org/fhir/ValueSet/c80-doc-typecodes--0|4.0.1' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2075,7 +1983,6 @@ v: { "severity" : "error", "error" : "Unknown Code 'X-34133-9' in the system 'http://loinc.org'; The provided code 'http://loinc.org#X-34133-9' is not in the value set 'http://hl7.org/fhir/ValueSet/@all' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2098,7 +2005,6 @@ v: { "code" : "80764-4", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2120,7 +2026,6 @@ v: { "code" : "56445-0", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2144,7 +2049,6 @@ v: { "code" : "56445-0", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2167,7 +2071,6 @@ v: { "code" : "56445-0", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2190,7 +2093,6 @@ v: { "severity" : "error", "error" : "Wrong Display Name 'Allergies and adverse reactions' for http://loinc.org#48765-2 - should be one of 28 choices: 'Allergies and adverse reactions Document', 'Allergies &or adverse reactions Doc', '临床文档型' (zh-CN), '临床文档' (zh-CN), '文档' (zh-CN), '文书' (zh-CN), '医疗文书' (zh-CN), '临床医疗文书 医疗服务对象' (zh-CN), '客户' (zh-CN), '病人' (zh-CN), '病患' (zh-CN), '病号' (zh-CN), '超系统 - 病人 发现是一个原子型临床观察指标,并不是作为印象的概括陈述。体格检查、病史、系统检查及其他此类观察指标的属性均为发现。它们的标尺对于编码型发现可能是名义型,而对于叙述型文本之中所报告的发现,则可能是叙述型。' (zh-CN), '发现物' (zh-CN), '所见' (zh-CN), '结果' (zh-CN), '结论 变态反应与不良反应 文档.其他' (zh-CN), '杂项类文档' (zh-CN), '其他文档 时刻' (zh-CN), '随机' (zh-CN), '随意' (zh-CN), '瞬间 杂项' (zh-CN), '杂项类' (zh-CN), '杂项试验 过敏反应' (zh-CN), '过敏' (zh-CN), 'Allergie e reazioni avverse Documentazione miscellanea Miscellanea Osservazione paziente Punto nel tempo (episodio)' (it-IT), 'Документ Точка во времени' (ru-RU) or 'Момент' (ru-RU) (for the language(s) '--') (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2212,7 +2114,6 @@ v: { "code" : "34133-9", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2235,7 +2136,6 @@ v: { "code" : "34133-9", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2257,7 +2157,6 @@ v: { "code" : "34133-9", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2279,7 +2178,6 @@ v: { "code" : "34133-9", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2303,7 +2201,6 @@ v: { "code" : "57852-6", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2325,7 +2222,6 @@ v: { "code" : "18842-5", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2348,7 +2244,6 @@ v: { "code" : "18842-5", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2370,7 +2265,6 @@ v: { "code" : "18842-5", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2392,7 +2286,6 @@ v: { "code" : "29299-5", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2414,7 +2307,6 @@ v: { "severity" : "error", "error" : "Unknown Code '�g��' in the system 'http://loinc.org'; The provided code 'http://loinc.org#�g��' is not in the value set 'http://hl7.org/fhir/ValueSet/@all' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2437,7 +2329,6 @@ v: { "code" : "8867-4", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2460,7 +2351,6 @@ v: { "code" : "10331-7", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2482,7 +2372,6 @@ v: { "severity" : "error", "error" : "Wrong Display Name '����' for http://loinc.org#18684-1 - should be one of 46 choices: 'First Blood pressure Set', 'ED Health Insurance Portability and Accountability Act of 1996' (zh-CN), 'HIPAA' (zh-CN), '健康保險可攜與責任法' (zh-CN), 'HIPAA法案' (zh-CN), '健康保险可移植性和问责法1996年' (zh-CN), '美国健康保险携带和责任法案' (zh-CN), '医疗保险便携性和责任法案' (zh-CN), '医疗保险便携性与责任法案' (zh-CN), '醫療保險可攜性與責任法' (zh-CN), 'HIPAA 信息附件.急诊' (zh-CN), 'HIPAA 信息附件.急诊科' (zh-CN), 'HIPAA 信息附件.急诊科就医' (zh-CN), 'HIPAA 信息附件.急诊科就诊' (zh-CN), '健康保险便携与责任法案信息附件.急诊' (zh-CN), '健康保险便携与责任法案信息附件.急诊 临床信息附件集' (zh-CN), '临床信息附件集合' (zh-CN), '集' (zh-CN), '集合 信息附件' (zh-CN), '健康保险便携与责任法案信息附件' (zh-CN), '附件 医疗服务对象' (zh-CN), '客户' (zh-CN), '病人' (zh-CN), '病患' (zh-CN), '病号' (zh-CN), '超系统 - 病人 压强 复合属性' (zh-CN), '复杂型属性' (zh-CN), '复杂属性 就医' (zh-CN), '就医过程 急诊科 急诊科(DEEDS)变量' (zh-CN), 'DEEDS 变量' (zh-CN), '急诊' (zh-CN), '急诊科' (zh-CN), 'Emergency Department' (zh-CN), 'ED' (zh-CN), '急诊科(急诊科系统代码之数据元素)变量' (zh-CN), '急诊科(急诊科系统代码之数据元素)指标' (zh-CN), '急诊科(美国CDC急诊科系统代码之数据元素)指标' (zh-CN), '急诊科指标 急诊科(Emergency Department,ED) 急诊部 第一个' (zh-CN), '第一次' (zh-CN), '首个' (zh-CN), '首次 血' (zh-CN), '全血' (zh-CN), 'Allegato Allegato di reparto di emergenza (pronto soccorso) Complesso Emergenza (DEEDS - Data Elements for Emergency Dep Incontro' (it-IT), 'Appuntamento paziente Stabilito' (it-IT), 'Fissato' (it-IT) or 'Встреча Комплекс' (ru-RU) (for the language(s) '--') (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2504,7 +2393,6 @@ v: { "severity" : "error", "error" : "Wrong Display Name '���k������' for http://loinc.org#8480-6 - should be one of 33 choices: 'Systolic blood pressure', 'BP sys', '一般血压' (zh-CN), '血压.原子型' (zh-CN), '血压指标.原子型 压力' (zh-CN), '压强 可用数量表示的' (zh-CN), '定量性' (zh-CN), '数值型' (zh-CN), '数量型' (zh-CN), '连续数值型标尺 时刻' (zh-CN), '随机' (zh-CN), '随意' (zh-CN), '瞬间 血管内收缩期' (zh-CN), '血管内心缩期 血管内的' (zh-CN), 'Pressure' (pt-BR), 'Point in time' (pt-BR), 'Random' (pt-BR), 'Art sys' (pt-BR), 'Quantitative' (pt-BR), 'QNT' (pt-BR), 'Quant' (pt-BR), 'Quan' (pt-BR), 'IV' (pt-BR), 'Intravenous' (pt-BR), 'BLOOD PRESSURE MEASUREMENTS.ATOM' (pt-BR), 'BP systolic' (pt-BR), 'Blood pressure systolic' (pt-BR), 'Sys BP' (pt-BR), 'SBP' (pt-BR), 'Pressione Pressione arteriosa - atomica Punto nel tempo (episodio)' (it-IT), 'Давление Количественный Точка во времени' (ru-RU), 'Момент' (ru-RU) or 'Blutdruck systolisch' (de-AT) (for the language(s) '--') (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2526,7 +2414,6 @@ v: { "severity" : "error", "error" : "Wrong Display Name '�g��������' for http://loinc.org#8462-4 - should be one of 36 choices: 'Diastolic blood pressure', 'BP dias', '一般血压' (zh-CN), '血压.原子型' (zh-CN), '血压指标.原子型 压力' (zh-CN), '压强 可用数量表示的' (zh-CN), '定量性' (zh-CN), '数值型' (zh-CN), '数量型' (zh-CN), '连续数值型标尺 时刻' (zh-CN), '随机' (zh-CN), '随意' (zh-CN), '瞬间 血管内心舒期' (zh-CN), '血管内舒张期 血管内的' (zh-CN), 'Dias' (pt-BR), 'Diast' (pt-BR), 'Pressure' (pt-BR), 'Point in time' (pt-BR), 'Random' (pt-BR), 'Art sys' (pt-BR), 'Quantitative' (pt-BR), 'QNT' (pt-BR), 'Quant' (pt-BR), 'Quan' (pt-BR), 'IV' (pt-BR), 'Intravenous' (pt-BR), 'Diastoli' (pt-BR), 'BLOOD PRESSURE MEASUREMENTS.ATOM' (pt-BR), 'Blood pressure diastolic' (pt-BR), 'BP diastolic' (pt-BR), 'Dias BP' (pt-BR), 'DBP' (pt-BR), 'Pressione Pressione arteriosa - atomica Punto nel tempo (episodio)' (it-IT), 'Внутрисосудистый диастолический Давление Количественный Точка во времени' (ru-RU), 'Момент' (ru-RU) or 'Blutdruck diastolisch' (de-AT) (for the language(s) '--') (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2549,7 +2436,6 @@ v: { "code" : "718-7", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2572,7 +2458,6 @@ v: { "code" : "38483-4", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2595,7 +2480,6 @@ v: { "code" : "2093-3", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2618,7 +2502,6 @@ v: { "code" : "44261-6", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2642,7 +2525,6 @@ v: { "code" : "29463-7", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2664,7 +2546,6 @@ v: { "code" : "29463-7", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2686,7 +2567,6 @@ v: { "code" : "69548-6", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2708,7 +2588,6 @@ v: { "code" : "LA9633-4", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2730,7 +2609,6 @@ v: { "code" : "LA26398-0", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2752,7 +2630,6 @@ v: { "code" : "48018-6", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2774,7 +2651,6 @@ v: { "code" : "81252-9", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2796,7 +2672,6 @@ v: { "code" : "81290-9", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2818,7 +2693,6 @@ v: { "code" : "48002-0", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2840,7 +2714,6 @@ v: { "code" : "LA6684-0", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2862,7 +2735,6 @@ v: { "code" : "69548-6", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2884,7 +2756,6 @@ v: { "code" : "69548-6", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2918,7 +2789,6 @@ v: { "code" : "LA9633-4", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2952,7 +2822,6 @@ v: { "code" : "LA9633-4", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2986,7 +2855,6 @@ v: { "code" : "LA26398-0", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -3020,7 +2888,6 @@ v: { "code" : "LA26398-0", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -3054,7 +2921,6 @@ v: { "code" : "LA6684-0", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -3088,7 +2954,6 @@ v: { "code" : "LA6684-0", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -3110,7 +2975,6 @@ v: { "code" : "8310-5", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -3133,7 +2997,6 @@ v: { "code" : "LA20271-5", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -3156,7 +3019,6 @@ v: { "code" : "LA20278-0", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -3179,7 +3041,6 @@ v: { "code" : "LA20275-6", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -3202,7 +3063,6 @@ v: { "code" : "LA20276-4", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -3225,7 +3085,6 @@ v: { "code" : "LA20296-2", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -3248,7 +3107,6 @@ v: { "code" : "LA32-8", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -3271,7 +3129,6 @@ v: { "code" : "LA33-6", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -3421,7 +3278,6 @@ v: { "code" : "LA20271-5", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -3499,7 +3355,6 @@ v: { "code" : "LA20278-0", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -3557,7 +3412,6 @@ v: { "code" : "LA20275-6", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -3647,7 +3501,6 @@ v: { "code" : "LA20276-4", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -3717,7 +3570,6 @@ v: { "code" : "LA20296-2", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -3755,7 +3607,6 @@ v: { "code" : "LA32-8", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -3793,7 +3644,6 @@ v: { "code" : "LA33-6", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -3815,7 +3665,6 @@ v: { "code" : "LA33-6", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -3837,7 +3686,6 @@ v: { "code" : "LA32-8", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -3872,7 +3720,6 @@ v: { "code" : "LA33-6", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -3907,7 +3754,6 @@ v: { "code" : "LA32-8", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -3930,7 +3776,6 @@ v: { "code" : "88123-5", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -3953,7 +3798,6 @@ v: { "code" : "LA28397-0", "system" : "http://loinc.org", "version" : "2.74", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -3975,7 +3819,6 @@ v: { "severity" : "error", "error" : "Unknown Code 'test' in the system 'http://loinc.org'; The provided code 'http://loinc.org|http://loinc.org#test' is not in the value set 'http://hl7.org/fhir/ValueSet/@all' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -3997,6 +3840,161 @@ v: { "code" : "10155-0", "system" : "http://loinc.org", "version" : "2.74", + "issues" : { + "resourceType" : "OperationOutcome" +} + +} +------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://loinc.org", + "code" : "48765-2", + "display" : "Allergies and Adverse Reactions" +}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": { + "resourceType" : "Parameters", + "parameter" : [{ + "name" : "profile-url", + "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891" + }] +}}#### +v: { + "severity" : "error", + "error" : "Wrong Display Name 'Allergies and Adverse Reactions' for http://loinc.org#48765-2 - should be one of 28 choices: 'Allergies and adverse reactions Document', 'Allergies &or adverse reactions Doc', '临床文档型' (zh-CN), '临床文档' (zh-CN), '文档' (zh-CN), '文书' (zh-CN), '医疗文书' (zh-CN), '临床医疗文书 医疗服务对象' (zh-CN), '客户' (zh-CN), '病人' (zh-CN), '病患' (zh-CN), '病号' (zh-CN), '超系统 - 病人 发现是一个原子型临床观察指标,并不是作为印象的概括陈述。体格检查、病史、系统检查及其他此类观察指标的属性均为发现。它们的标尺对于编码型发现可能是名义型,而对于叙述型文本之中所报告的发现,则可能是叙述型。' (zh-CN), '发现物' (zh-CN), '所见' (zh-CN), '结果' (zh-CN), '结论 变态反应与不良反应 文档.其他' (zh-CN), '杂项类文档' (zh-CN), '其他文档 时刻' (zh-CN), '随机' (zh-CN), '随意' (zh-CN), '瞬间 杂项' (zh-CN), '杂项类' (zh-CN), '杂项试验 过敏反应' (zh-CN), '过敏' (zh-CN), 'Allergie e reazioni avverse Documentazione miscellanea Miscellanea Osservazione paziente Punto nel tempo (episodio)' (it-IT), 'Документ Точка во времени' (ru-RU) or 'Момент' (ru-RU) (for the language(s) '--') (from Tx-Server)", + "class" : "UNKNOWN", + "unknown-systems" : "", + "issues" : { + "resourceType" : "OperationOutcome" +} + +} +------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://loinc.org", + "code" : "10160-0", + "display" : "Medication List" +}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": { + "resourceType" : "Parameters", + "parameter" : [{ + "name" : "profile-url", + "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891" + }] +}}#### +v: { + "severity" : "error", + "error" : "Wrong Display Name 'Medication List' for http://loinc.org#10160-0 - should be one of 48 choices: 'History of Medication use Narrative', 'Hx of Medication use', '医疗服务对象' (zh-CN), '客户' (zh-CN), '病人' (zh-CN), '病患' (zh-CN), '病号' (zh-CN), '超系统 - 病人 历史' (zh-CN), '史' (zh-CN), '病史 历史纪录与体格检查 历史纪录与体格检查.历史记录' (zh-CN), '历史纪录与体格检查.历史记录类' (zh-CN), '历史纪录与体格检查.历史记录类别' (zh-CN), '历史纪录与体格检查.病史' (zh-CN), '历史纪录与体格检查.病史类' (zh-CN), '历史纪录与体格检查.病史类别' (zh-CN), '历史纪录与体格检查.病史记录' (zh-CN), '历史纪录与体格检查.病史记录类' (zh-CN), '历史纪录与体格检查.病史记录类别' (zh-CN), '历史纪录与体格检查小节.历史记录' (zh-CN), '历史纪录与体格检查小节.历史记录类' (zh-CN), '历史纪录与体格检查小节.历史记录类别' (zh-CN), '历史纪录与体格检查小节.病史' (zh-CN), '历史纪录与体格检查小节.病史类' (zh-CN), '历史纪录与体格检查小节.病史类别 历史纪录与体格检查小节 叙述' (zh-CN), '叙述性文字' (zh-CN), '报告' (zh-CN), '报告型' (zh-CN), '文字叙述' (zh-CN), '文本叙述型' (zh-CN), '文本描述' (zh-CN), '文本描述型 处理用药' (zh-CN), '处理用药物' (zh-CN), '处理药物' (zh-CN), '治疗用药' (zh-CN), '治疗用药物' (zh-CN), '用药' (zh-CN), '药物处理' (zh-CN), '药物治疗' (zh-CN), '治疗药物 时刻' (zh-CN), '随机' (zh-CN), '随意' (zh-CN), '瞬间 病史与体格检查 药物使用历史' (zh-CN), '药物使用史' (zh-CN), 'Anamnesi paziente Punto nel tempo (episodio) Storia' (it-IT), 'Anamnesi' (it-IT), 'История Лекарственный анамнез Описательный Точка во времени' (ru-RU), 'Момент' (ru-RU) or 'anamnese geneesmiddelen' (nl-NL) (for the language(s) '--') (from Tx-Server)", + "class" : "UNKNOWN", + "unknown-systems" : "", + "issues" : { + "resourceType" : "OperationOutcome" +} + +} +------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://loinc.org", + "code" : "11450-4", + "display" : "Problem List" +}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": { + "resourceType" : "Parameters", + "parameter" : [{ + "name" : "profile-url", + "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891" + }] +}}#### +v: { + "severity" : "error", + "error" : "Wrong Display Name 'Problem List' for http://loinc.org#11450-4 - should be one of 53 choices: 'Problem list - Reported', 'Problem list Reported', '分类型应答' (zh-CN), '分类型结果' (zh-CN), '名义性' (zh-CN), '名称型' (zh-CN), '名词型' (zh-CN), '名词性' (zh-CN), '标称性' (zh-CN), '没有自然次序的名义型或分类型应答 医疗服务对象' (zh-CN), '客户' (zh-CN), '病人' (zh-CN), '病患' (zh-CN), '病号' (zh-CN), '超系统 - 病人 历史纪录与体格检查 历史纪录与体格检查.历史记录' (zh-CN), '历史纪录与体格检查.历史记录类' (zh-CN), '历史纪录与体格检查.历史记录类别' (zh-CN), '历史纪录与体格检查.病史' (zh-CN), '历史纪录与体格检查.病史类' (zh-CN), '历史纪录与体格检查.病史类别' (zh-CN), '历史纪录与体格检查.病史记录' (zh-CN), '历史纪录与体格检查.病史记录类' (zh-CN), '历史纪录与体格检查.病史记录类别' (zh-CN), '历史纪录与体格检查小节.历史记录' (zh-CN), '历史纪录与体格检查小节.历史记录类' (zh-CN), '历史纪录与体格检查小节.历史记录类别' (zh-CN), '历史纪录与体格检查小节.病史' (zh-CN), '历史纪录与体格检查小节.病史类' (zh-CN), '历史纪录与体格检查小节.病史类别 历史纪录与体格检查小节 发现是一个原子型临床观察指标,并不是作为印象的概括陈述。体格检查、病史、系统检查及其他此类观察指标的属性均为发现。它们的标尺对于编码型发现可能是名义型,而对于叙述型文本之中所报告的发现,则可能是叙述型。' (zh-CN), '发现物' (zh-CN), '所见' (zh-CN), '结果' (zh-CN), '结论 时刻' (zh-CN), '随机' (zh-CN), '随意' (zh-CN), '瞬间 病史与体格检查 问题目录' (zh-CN), '问题清单 难题' (zh-CN), '困难' (zh-CN), '棘手问题' (zh-CN), '麻烦' (zh-CN), '乱子' (zh-CN), '疑难问题' (zh-CN), '疑难' (zh-CN), 'Finding' (pt-BR), 'Findings' (pt-BR), 'Point in time' (pt-BR), 'Random' (pt-BR), 'Nominal' (pt-BR), 'Anamnesi Osservazione paziente Punto nel tempo (episodio)' (it-IT), 'Анамнестические сведения' (ru-RU), 'Сообщенная третьим лицом информация Номинальный' (ru-RU), 'Именной Список проблем Точка во времени' (ru-RU) or 'Момент' (ru-RU) (for the language(s) '--') (from Tx-Server)", + "class" : "UNKNOWN", + "unknown-systems" : "", + "issues" : { + "resourceType" : "OperationOutcome" +} + +} +------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://loinc.org", + "code" : "11369-6", + "display" : "History of Immunizations" +}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": { + "resourceType" : "Parameters", + "parameter" : [{ + "name" : "profile-url", + "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891" + }] +}}#### +v: { + "severity" : "error", + "error" : "Wrong Display Name 'History of Immunizations' for http://loinc.org#11369-6 - should be one of 43 choices: 'History of Immunization Narrative', 'Hx of Immunization', '免疫接种历史' (zh-CN), '免疫史' (zh-CN), '接种史' (zh-CN), '免疫接种史 医疗服务对象' (zh-CN), '客户' (zh-CN), '病人' (zh-CN), '病患' (zh-CN), '病号' (zh-CN), '超系统 - 病人 历史' (zh-CN), '史' (zh-CN), '病史 历史纪录与体格检查 历史纪录与体格检查.历史记录' (zh-CN), '历史纪录与体格检查.历史记录类' (zh-CN), '历史纪录与体格检查.历史记录类别' (zh-CN), '历史纪录与体格检查.病史' (zh-CN), '历史纪录与体格检查.病史类' (zh-CN), '历史纪录与体格检查.病史类别' (zh-CN), '历史纪录与体格检查.病史记录' (zh-CN), '历史纪录与体格检查.病史记录类' (zh-CN), '历史纪录与体格检查.病史记录类别' (zh-CN), '历史纪录与体格检查小节.历史记录' (zh-CN), '历史纪录与体格检查小节.历史记录类' (zh-CN), '历史纪录与体格检查小节.历史记录类别' (zh-CN), '历史纪录与体格检查小节.病史' (zh-CN), '历史纪录与体格检查小节.病史类' (zh-CN), '历史纪录与体格检查小节.病史类别 历史纪录与体格检查小节 叙述' (zh-CN), '叙述性文字' (zh-CN), '报告' (zh-CN), '报告型' (zh-CN), '文字叙述' (zh-CN), '文本叙述型' (zh-CN), '文本描述' (zh-CN), '文本描述型 时刻' (zh-CN), '随机' (zh-CN), '随意' (zh-CN), '瞬间 病史与体格检查' (zh-CN), 'Anamnesi paziente Punto nel tempo (episodio) Storia' (it-IT), 'Anamnesi' (it-IT), 'История Описательный Точка во времени' (ru-RU), 'Момент' (ru-RU), 'anamnese vaccinatie' (nl-NL) or 'Immunisierungsstatus' (de-AT) (for the language(s) '--') (from Tx-Server)", + "class" : "UNKNOWN", + "unknown-systems" : "", + "issues" : { + "resourceType" : "OperationOutcome" +} + +} +------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://loinc.org", + "code" : "29762-2", + "display" : "Social History" +}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": { + "resourceType" : "Parameters", + "parameter" : [{ + "name" : "profile-url", + "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891" + }] +}}#### +v: { + "severity" : "error", + "error" : "Wrong Display Name 'Social History' for http://loinc.org#29762-2 - should be one of 45 choices: 'Social history Narrative', 'Social Hx', '医疗服务对象' (zh-CN), '客户' (zh-CN), '病人' (zh-CN), '病患' (zh-CN), '病号' (zh-CN), '超系统 - 病人 历史纪录与体格检查 历史纪录与体格检查.历史记录' (zh-CN), '历史纪录与体格检查.历史记录类' (zh-CN), '历史纪录与体格检查.历史记录类别' (zh-CN), '历史纪录与体格检查.病史' (zh-CN), '历史纪录与体格检查.病史类' (zh-CN), '历史纪录与体格检查.病史类别' (zh-CN), '历史纪录与体格检查.病史记录' (zh-CN), '历史纪录与体格检查.病史记录类' (zh-CN), '历史纪录与体格检查.病史记录类别' (zh-CN), '历史纪录与体格检查小节.历史记录' (zh-CN), '历史纪录与体格检查小节.历史记录类' (zh-CN), '历史纪录与体格检查小节.历史记录类别' (zh-CN), '历史纪录与体格检查小节.病史' (zh-CN), '历史纪录与体格检查小节.病史类' (zh-CN), '历史纪录与体格检查小节.病史类别 历史纪录与体格检查小节 发现是一个原子型临床观察指标,并不是作为印象的概括陈述。体格检查、病史、系统检查及其他此类观察指标的属性均为发现。它们的标尺对于编码型发现可能是名义型,而对于叙述型文本之中所报告的发现,则可能是叙述型。' (zh-CN), '发现物' (zh-CN), '所见' (zh-CN), '结果' (zh-CN), '结论 叙述' (zh-CN), '叙述性文字' (zh-CN), '报告' (zh-CN), '报告型' (zh-CN), '文字叙述' (zh-CN), '文本叙述型' (zh-CN), '文本描述' (zh-CN), '文本描述型 时刻' (zh-CN), '随机' (zh-CN), '随意' (zh-CN), '瞬间 病史与体格检查 社会历史' (zh-CN), 'Finding' (pt-BR), 'Findings' (pt-BR), 'Point in time' (pt-BR), 'Random' (pt-BR), 'Narrative' (pt-BR), 'Report' (pt-BR), 'Anamnesi Osservazione paziente Punto nel tempo (episodio)' (it-IT), 'Описательный Социальный анамнез Точка во времени' (ru-RU) or 'Момент' (ru-RU) (for the language(s) '--') (from Tx-Server)", + "class" : "UNKNOWN", + "unknown-systems" : "", + "issues" : { + "resourceType" : "OperationOutcome" +} + +} +------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://loinc.org", + "code" : "72166-2", + "display" : "Tobacco smoking status" +}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": { + "resourceType" : "Parameters", + "parameter" : [{ + "name" : "profile-url", + "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891" + }] +}}#### +v: { + "display" : "Tobacco smoking status", + "code" : "72166-2", + "system" : "http://loinc.org", + "version" : "2.74", + "unknown-systems" : "", + "issues" : { + "resourceType" : "OperationOutcome" +} + +} +------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://loinc.org", + "code" : "LA15920-4", + "display" : "Former smoker" +}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": { + "resourceType" : "Parameters", + "parameter" : [{ + "name" : "profile-url", + "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891" + }] +}}#### +v: { + "display" : "Former smoker", + "code" : "LA15920-4", + "system" : "http://loinc.org", + "version" : "2.74", "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" diff --git a/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/rxnorm.cache b/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/rxnorm.cache index 778a99d7d..122fb3ea3 100644 --- a/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/rxnorm.cache +++ b/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/rxnorm.cache @@ -15,7 +15,6 @@ v: { "code" : "1000990", "system" : "http://www.nlm.nih.gov/research/umls/rxnorm", "version" : "??", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -38,7 +37,6 @@ v: { "code" : "1010603", "system" : "http://www.nlm.nih.gov/research/umls/rxnorm", "version" : "??", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -61,7 +59,6 @@ v: { "code" : "1298088", "system" : "http://www.nlm.nih.gov/research/umls/rxnorm", "version" : "??", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -84,7 +81,6 @@ v: { "code" : "1010600", "system" : "http://www.nlm.nih.gov/research/umls/rxnorm", "version" : "??", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -106,6 +102,27 @@ v: { "code" : "1591957", "system" : "http://www.nlm.nih.gov/research/umls/rxnorm", "version" : "??", + "issues" : { + "resourceType" : "OperationOutcome" +} + +} +------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://www.nlm.nih.gov/research/umls/rxnorm", + "code" : "617311", + "display" : "atorvastatin 40mg Oral Tablet" +}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": { + "resourceType" : "Parameters", + "parameter" : [{ + "name" : "profile-url", + "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891" + }] +}}#### +v: { + "severity" : "error", + "error" : "Wrong Display Name 'atorvastatin 40mg Oral Tablet' for http://www.nlm.nih.gov/research/umls/rxnorm#617311 - should be one of 3 choices: 'atorvastatin 40 MG Oral Tablet', 'atorvastatin (as atorvastatin calcium) 40 MG Oral Tablet' or 'atorvastatin calcium 40 MG Oral Tablet' (for the language(s) '--') (from Tx-Server)", + "class" : "UNKNOWN", "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" diff --git a/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/snomed.cache b/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/snomed.cache index 46366cbef..61072bb35 100644 --- a/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/snomed.cache +++ b/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/4.0.1/snomed.cache @@ -15,7 +15,6 @@ v: { "code" : "721912009", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -38,7 +37,6 @@ v: { "code" : "91935009", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -61,7 +59,6 @@ v: { "code" : "3718001", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -83,7 +80,6 @@ v: { "code" : "255604002", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -106,7 +102,6 @@ v: { "code" : "255604002", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -128,7 +123,6 @@ v: { "code" : "255604002", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -151,7 +145,6 @@ v: { "code" : "409002", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -173,7 +166,6 @@ v: { "code" : "6736007", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -195,7 +187,6 @@ v: { "severity" : "error", "error" : "Wrong Display Name 'Moderate' for http://snomed.info/sct#6736007 - should be one of 4 choices: 'Midgrade', 'Moderate (severity modifier) (qualifier value)', 'Moderate (severity modifier)' or 'Moderate severity' (for the language(s) '--') (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -217,7 +208,6 @@ v: { "code" : "6736007", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -240,7 +230,6 @@ v: { "code" : "437009", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -263,7 +252,6 @@ v: { "code" : "9846003", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -286,7 +274,6 @@ v: { "code" : "189009", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -309,7 +296,6 @@ v: { "code" : "911003", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -332,7 +318,6 @@ v: { "code" : "112144000", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -355,7 +340,6 @@ v: { "code" : "80943009", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -378,7 +362,6 @@ v: { "code" : "77176002", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -401,7 +384,6 @@ v: { "code" : "38341003", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -424,7 +406,6 @@ v: { "code" : "1419004", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome", "issue" : [{ @@ -482,7 +463,6 @@ v: { "code" : "93880001", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -505,7 +485,6 @@ v: { "code" : "248986005", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -528,7 +507,6 @@ v: { "code" : "161714006", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -551,7 +529,6 @@ v: { "code" : "161713000", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -574,7 +551,6 @@ v: { "code" : "445872007", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -597,7 +573,6 @@ v: { "code" : "722446000", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -620,7 +595,6 @@ v: { "code" : "371531000", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -643,7 +617,6 @@ v: { "code" : "4241000179101", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -666,7 +639,6 @@ v: { "code" : "422735006", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -688,7 +660,6 @@ v: { "code" : "440545006", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -711,7 +682,6 @@ v: { "code" : "324252006", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome", "issue" : [{ @@ -747,7 +717,6 @@ v: { "severity" : "error", "error" : "Wrong Display Name 'Traveller's Diarrhea (disorder)' for http://snomed.info/sct#11840006 - should be one of 4 choices: 'Traveler's diarrhea', 'Turista', 'Traveler's diarrhoea' or 'Traveler's diarrhea (disorder)' (for the language(s) '--') (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -770,7 +739,6 @@ v: { "code" : "21522001", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -793,7 +761,6 @@ v: { "code" : "311504000", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -816,7 +783,6 @@ v: { "code" : "26643006", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -839,7 +805,6 @@ v: { "code" : "421521009", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -862,7 +827,6 @@ v: { "code" : "602001", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome", "issue" : [{ @@ -899,7 +863,6 @@ v: { "code" : "8821006", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -921,7 +884,6 @@ v: { "code" : "112144000", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -943,7 +905,6 @@ v: { "code" : "112144000", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -965,7 +926,6 @@ v: { "code" : "722446000", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -987,7 +947,6 @@ v: { "code" : "722446000", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1009,7 +968,6 @@ v: { "code" : "371531000", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1031,7 +989,6 @@ v: { "code" : "371531000", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1053,7 +1010,6 @@ v: { "code" : "4241000179101", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1075,7 +1031,6 @@ v: { "code" : "4241000179101", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1097,7 +1052,6 @@ v: { "code" : "422735006", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1119,7 +1073,6 @@ v: { "code" : "422735006", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1140,7 +1093,6 @@ v: { "severity" : "error", "error" : "The provided code 'http://snomed.info/sct#77176002' is not in the value set 'https://mednet.swiss/fhir/ValueSet/mni-obs-bloodGroup--0|0.5.0' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1161,7 +1113,6 @@ v: { "severity" : "error", "error" : "The provided code 'http://snomed.info/sct#38341003' is not in the value set 'https://mednet.swiss/fhir/ValueSet/mni-obs-bloodGroup--0|0.5.0' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1185,7 +1136,6 @@ v: { "code" : "454281000124100", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/731000124108/version/20230301", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1207,7 +1157,6 @@ v: { "severity" : "error", "error" : "Wrong Display Name 'Progress note' for http://snomed.info/sct#371532007 - should be one of 3 choices: 'Progress report', 'Report of subsequent visit' or 'Progress report (record artifact)' (for the language(s) '--') (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1230,7 +1179,6 @@ v: { "code" : "371525003", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1252,7 +1200,6 @@ v: { "code" : "371532007", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1274,7 +1221,6 @@ v: { "code" : "371532007", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1296,7 +1242,6 @@ v: { "code" : "371525003", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1318,7 +1263,6 @@ v: { "code" : "371525003", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1341,7 +1285,6 @@ v: { "code" : "419891008", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1364,7 +1307,6 @@ v: { "code" : "371525003", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1387,7 +1329,6 @@ v: { "code" : "17621005", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1410,7 +1351,6 @@ v: { "code" : "722172003", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1433,7 +1373,6 @@ v: { "code" : "394609007", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1456,7 +1395,6 @@ v: { "code" : "71388002", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1502,7 +1440,6 @@ v: { "code" : "410534003", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1525,7 +1462,6 @@ v: { "code" : "10828004", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1548,7 +1484,6 @@ v: { "code" : "233588003", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1571,7 +1506,6 @@ v: { "code" : "324689003", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1594,7 +1528,6 @@ v: { "code" : "442311008", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1617,7 +1550,6 @@ v: { "code" : "840539006", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1639,7 +1571,6 @@ v: { "severity" : "error", "error" : "Wrong Display Name 'COVID-19' for http://snomed.info/sct#840535000 - should be one of 7 choices: 'Antibody to 2019 novel coronavirus', 'Antibody to 2019-nCoV', 'Antibody to severe acute respiratory syndrome coronavirus 2 (substance)', 'Antibody to severe acute respiratory syndrome coronavirus 2', 'Antibody to SARS-CoV-2', 'Severe acute respiratory syndrome coronavirus 2 Ab' or 'Severe acute respiratory syndrome coronavirus 2 antibody' (for the language(s) '--') (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1662,7 +1593,6 @@ v: { "code" : "840535000", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1685,7 +1615,6 @@ v: { "code" : "32485007", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1708,7 +1637,6 @@ v: { "code" : "32713005", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1730,7 +1658,6 @@ v: { "severity" : "error", "error" : "Unable to find code 10821000202101 in http://snomed.info/sct (version http://snomed.info/sct/900000000000207008/version/20230731); Unknown Code '10821000202101' in the system 'http://snomed.info/sct'; The provided code 'http://snomed.info/sct#10821000202101' is not in the value set 'http://hl7.org/fhir/ValueSet/@all' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1752,7 +1679,6 @@ v: { "severity" : "error", "error" : "Wrong Display Name 'Diagnostisk med biopsi' for http://snomed.info/sct#446745002 - should be one of 2 choices: 'Colonoscopy and biopsy of colon (procedure)' or 'Colonoscopy and biopsy of colon' (for the language(s) '--') (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1775,7 +1701,6 @@ v: { "code" : "73761001", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1797,7 +1722,6 @@ v: { "severity" : "error", "error" : "Unable to find code 8921000202108 in http://snomed.info/sct (version http://snomed.info/sct/900000000000207008/version/20230731); Unknown Code '8921000202108' in the system 'http://snomed.info/sct'; The provided code 'http://snomed.info/sct#8921000202108' is not in the value set 'http://hl7.org/fhir/ValueSet/@all' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1819,7 +1743,6 @@ v: { "severity" : "error", "error" : "Unable to find code 8951000202101 in http://snomed.info/sct (version http://snomed.info/sct/900000000000207008/version/20230731); Unknown Code '8951000202101' in the system 'http://snomed.info/sct'; The provided code 'http://snomed.info/sct#8951000202101' is not in the value set 'http://hl7.org/fhir/ValueSet/@all' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1842,7 +1765,6 @@ v: { "code" : "300577008", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1864,7 +1786,6 @@ v: { "severity" : "error", "error" : "Unable to find code 10291000202102 in http://snomed.info/sct (version http://snomed.info/sct/900000000000207008/version/20230731); Unknown Code '10291000202102' in the system 'http://snomed.info/sct'; The provided code 'http://snomed.info/sct#10291000202102' is not in the value set 'http://hl7.org/fhir/ValueSet/@all' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1887,7 +1808,6 @@ v: { "code" : "722818007", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1909,7 +1829,6 @@ v: { "severity" : "error", "error" : "Unable to find code 8901000202102 in http://snomed.info/sct (version http://snomed.info/sct/900000000000207008/version/20230731); Unknown Code '8901000202102' in the system 'http://snomed.info/sct'; The provided code 'http://snomed.info/sct#8901000202102' is not in the value set 'http://hl7.org/fhir/ValueSet/@all' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1932,7 +1851,6 @@ v: { "code" : "10291000132101", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1954,7 +1872,6 @@ v: { "severity" : "error", "error" : "Unable to find code 8911000202100 in http://snomed.info/sct (version http://snomed.info/sct/900000000000207008/version/20230731); Unknown Code '8911000202100' in the system 'http://snomed.info/sct'; The provided code 'http://snomed.info/sct#8911000202100' is not in the value set 'http://hl7.org/fhir/ValueSet/@all' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1977,7 +1894,6 @@ v: { "code" : "10301000132102", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -1999,7 +1915,6 @@ v: { "severity" : "error", "error" : "Unable to find code 8891000202103 in http://snomed.info/sct (version http://snomed.info/sct/900000000000207008/version/20230731); Unknown Code '8891000202103' in the system 'http://snomed.info/sct'; The provided code 'http://snomed.info/sct#8891000202103' is not in the value set 'http://hl7.org/fhir/ValueSet/@all' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2022,7 +1937,6 @@ v: { "code" : "10311000132100", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2044,7 +1958,6 @@ v: { "code" : "10291000132101", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2066,7 +1979,6 @@ v: { "code" : "10301000132102", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2088,7 +2000,6 @@ v: { "code" : "10311000132100", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2110,7 +2021,6 @@ v: { "code" : "246206008", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2132,7 +2042,6 @@ v: { "severity" : "error", "error" : "Unable to find code 15991000202102 in http://snomed.info/sct (version http://snomed.info/sct/900000000000207008/version/20230731); Unknown Code '15991000202102' in the system 'http://snomed.info/sct'; The provided code 'http://snomed.info/sct#15991000202102' is not in the value set 'http://hl7.org/fhir/ValueSet/@all' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2154,7 +2063,6 @@ v: { "code" : "17621005", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2177,7 +2085,6 @@ v: { "code" : "712510007", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2199,7 +2106,6 @@ v: { "code" : "32485007", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2221,7 +2127,6 @@ v: { "code" : "32713005", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2242,7 +2147,6 @@ v: { "severity" : "error", "error" : "Unable to find code 10821000202101 in http://snomed.info/sct (version http://snomed.info/sct/900000000000207008/version/20230731); Unknown Code '10821000202101' in the system 'http://snomed.info/sct'; The provided code 'http://snomed.info/sct#10821000202101' is not in the value set 'http://hl7.org/fhir/ValueSet/@all' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2264,7 +2168,6 @@ v: { "code" : "446745002", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2285,7 +2188,6 @@ v: { "severity" : "error", "error" : "Unable to find code 8921000202108 in http://snomed.info/sct (version http://snomed.info/sct/900000000000207008/version/20230731); Unknown Code '8921000202108' in the system 'http://snomed.info/sct'; The provided code 'http://snomed.info/sct#8921000202108' is not in the value set 'http://hl7.org/fhir/ValueSet/@all' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2306,7 +2208,6 @@ v: { "severity" : "error", "error" : "Unable to find code 8951000202101 in http://snomed.info/sct (version http://snomed.info/sct/900000000000207008/version/20230731); Unknown Code '8951000202101' in the system 'http://snomed.info/sct'; The provided code 'http://snomed.info/sct#8951000202101' is not in the value set 'http://hl7.org/fhir/ValueSet/@all' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2328,7 +2229,6 @@ v: { "code" : "712510007", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2350,7 +2250,6 @@ v: { "code" : "372756006", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2372,7 +2271,6 @@ v: { "code" : "387458008", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2395,7 +2293,6 @@ v: { "code" : "372756006", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2418,7 +2315,6 @@ v: { "code" : "387458008", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2486,7 +2382,6 @@ v: { "code" : "276885007", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2509,7 +2404,6 @@ v: { "code" : "58108001", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome", "issue" : [{ @@ -2601,7 +2495,6 @@ v: { "code" : "119339001", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2623,7 +2516,6 @@ v: { "code" : "5933001", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2691,7 +2583,6 @@ v: { "severity" : "error", "error" : "Wrong Display Name 'Paracetamol 500mg tablets' for http://snomed.info/sct#322236009 - should be one of 3 choices: 'Acetaminophen 500 mg oral tablet', 'Paracetamol 500 mg oral tablet' or 'Product containing precisely paracetamol 500 milligram/1 each conventional release oral tablet (clinical drug)' (for the language(s) '--') (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2713,7 +2604,6 @@ v: { "code" : "428673006", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2735,7 +2625,6 @@ v: { "severity" : "error", "error" : "Unable to find code 35901911000001104 in http://snomed.info/sct (version http://snomed.info/sct/900000000000207008/version/20230731); Unknown Code '35901911000001104' in the system 'http://snomed.info/sct'; The provided code 'http://snomed.info/sct#35901911000001104' is not in the value set 'http://hl7.org/fhir/ValueSet/@all' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2757,7 +2646,6 @@ v: { "code" : "258773002", "system" : "http://snomed.info/sct", "version" : "http://snomed.info/sct/900000000000207008/version/20230731", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2779,7 +2667,6 @@ v: { "severity" : "error", "error" : "Wrong Display Name 'Ibuprofen 200mg tablets' for http://snomed.info/sct#329652003 - should be one of 2 choices: 'Ibuprofen 200 mg oral tablet' or 'Product containing precisely ibuprofen 200 milligram/1 each conventional release oral tablet (clinical drug)' (for the language(s) '--') (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2801,7 +2688,6 @@ v: { "severity" : "error", "error" : "Unable to find code 39695211000001102 in http://snomed.info/sct (version http://snomed.info/sct/900000000000207008/version/20230731); Unknown Code '39695211000001102' in the system 'http://snomed.info/sct'; The provided code 'http://snomed.info/sct#39695211000001102' is not in the value set 'http://hl7.org/fhir/ValueSet/@all' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2823,7 +2709,6 @@ v: { "severity" : "error", "error" : "Unable to find code 56248011000036107 in http://snomed.info/sct (version http://snomed.info/sct/900000000000207008/version/20230731); Unknown Code '56248011000036107' in the system 'http://snomed.info/sct'; The provided code 'http://snomed.info/sct#56248011000036107' is not in the value set 'http://hl7.org/fhir/ValueSet/@all' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2844,7 +2729,6 @@ v: { "severity" : "error", "error" : "Unable to find code 1 in http://snomed.info/sct (version http://snomed.info/sct/900000000000207008/version/20230731); Unknown Code '1' in the system 'http://snomed.info/sct'; The provided code 'http://snomed.info/sct#1' is not in the value set 'http://hl7.org/fhir/ValueSet/@all' (from Tx-Server)", "class" : "UNKNOWN", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -2865,6 +2749,74 @@ v: { "severity" : "error", "error" : "Unable to find code 2 in http://snomed.info/sct (version http://snomed.info/sct/900000000000207008/version/20230731); Unknown Code '2' in the system 'http://snomed.info/sct'; The provided code 'http://snomed.info/sct#2' is not in the value set 'http://hl7.org/fhir/ValueSet/@all' (from Tx-Server)", "class" : "UNKNOWN", + "issues" : { + "resourceType" : "OperationOutcome" +} + +} +------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://snomed.info/sct", + "code" : "38341003", + "display" : "HT - Hypertension" +}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": { + "resourceType" : "Parameters", + "parameter" : [{ + "name" : "profile-url", + "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891" + }] +}}#### +v: { + "display" : "High blood pressure", + "code" : "38341003", + "system" : "http://snomed.info/sct", + "version" : "http://snomed.info/sct/900000000000207008/version/20230731", + "unknown-systems" : "", + "issues" : { + "resourceType" : "OperationOutcome" +} + +} +------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://snomed.info/sct", + "code" : "42343007", + "display" : "Congestive heart failure" +}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": { + "resourceType" : "Parameters", + "parameter" : [{ + "name" : "profile-url", + "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891" + }] +}}#### +v: { + "display" : "Congestive heart failure", + "code" : "42343007", + "system" : "http://snomed.info/sct", + "version" : "http://snomed.info/sct/900000000000207008/version/20230731", + "unknown-systems" : "", + "issues" : { + "resourceType" : "OperationOutcome" +} + +} +------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://snomed.info/sct", + "code" : "9014002", + "display" : "Psoriasis" +}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"ALL_CHECKS", "displayWarningMode":"false", "versionFlexible":"false", "profile": { + "resourceType" : "Parameters", + "parameter" : [{ + "name" : "profile-url", + "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891" + }] +}}#### +v: { + "display" : "Psoriasis", + "code" : "9014002", + "system" : "http://snomed.info/sct", + "version" : "http://snomed.info/sct/900000000000207008/version/20230731", "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" diff --git a/pom.xml b/pom.xml index b274b0250..e8b7f36fd 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 32.0.1-jre 6.4.1 - 1.4.1 + 1.4.2-SNAPSHOT 2.15.2 5.9.2 1.8.2 @@ -283,6 +283,13 @@ xpp3 1.1.6 + + + + com.nimbusds + nimbus-jose-jwt + 9.30.2 + From be4957c9af6375f67e2892efd395cd57299a21e9 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Sat, 2 Sep 2023 23:35:00 +0700 Subject: [PATCH 2/8] fix typos --- .../main/java/org/hl7/fhir/r5/elementmodel/SHLParser.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHLParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHLParser.java index d65b77b77..ca2200812 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHLParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHLParser.java @@ -131,9 +131,9 @@ public class SHLParser extends ParserBase { } if (cnt != null) { if (cnt.getContentType() == null) { - logError(json.getErrors(), "202-08-31", 1, 1, "shl.json.url.fetch()", IssueType.NOTFOUND, "The server did not return a Content-Type header - should be 'application/json'", IssueSeverity.WARNING); + logError(json.getErrors(), "202-08-31", 1, 1, "shl.json.url.fetch()", IssueType.NOTFOUND, "The server did not return a Content-Type header - should be 'application/jose'", IssueSeverity.WARNING); } else if (!"application/json".equals(cnt.getContentType())) { - logError(json.getErrors(), "202-08-31", 1, 1, "shl.json.url.fetch()", IssueType.STRUCTURE, "The server returned the wrong Content-Type header '"+cnt.getContentType()+"' - must be 'application/json'", IssueSeverity.ERROR); + logError(json.getErrors(), "202-08-31", 1, 1, "shl.json.url.fetch()", IssueType.STRUCTURE, "The server returned the wrong Content-Type header '"+cnt.getContentType()+"' - must be 'application/jose'", IssueSeverity.ERROR); } processContent(res, json.getErrors(), "shl.url.fetched()", "document", cnt.getContentAsString(), ct); } @@ -232,9 +232,9 @@ public class SHLParser extends ParserBase { } if (cnt != null) { if (cnt.getContentType() == null) { - logError(errors, "202-08-31", 1, 1, "shl.json.url.fetch()", IssueType.NOTFOUND, "The server did not return a Content-Type header - should be 'application/json'", IssueSeverity.WARNING); + logError(errors, "202-08-31", 1, 1, "shl.json.url.fetch()", IssueType.NOTFOUND, "The server did not return a Content-Type header - should be 'application/jose'", IssueSeverity.WARNING); } else if (!"application/json".equals(cnt.getContentType())) { - logError(errors, "202-08-31", 1, 1, "shl.json.url.fetch()", IssueType.STRUCTURE, "The server returned the wrong Content-Type header '"+cnt.getContentType()+"' - must be 'application/json'", IssueSeverity.ERROR); + logError(errors, "202-08-31", 1, 1, "shl.json.url.fetch()", IssueType.STRUCTURE, "The server returned the wrong Content-Type header '"+cnt.getContentType()+"' - must be 'application/jose'", IssueSeverity.ERROR); } processContent(res, errors, path+".url.fetch()", name, cnt.getContentAsString(), ct); } From 5cc4e3ef03075f3e05830fe2316ba888730de9df Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Mon, 4 Sep 2023 13:38:22 +1000 Subject: [PATCH 3/8] rework the way intermediary content is handled in the validator + fix impose-profile handling for IPS-AU --- .../hl7/fhir/r5/elementmodel/FmlParser.java | 2 +- .../hl7/fhir/r5/elementmodel/JsonParser.java | 2 +- .../hl7/fhir/r5/elementmodel/ParserBase.java | 12 +++-- .../hl7/fhir/r5/elementmodel/SHCParser.java | 4 +- .../hl7/fhir/r5/elementmodel/SHLParser.java | 17 ++++--- .../fhir/r5/elementmodel/TurtleParser.java | 2 +- .../r5/elementmodel/VerticalBarParser.java | 2 +- .../hl7/fhir/r5/elementmodel/XmlParser.java | 2 +- .../instance/InstanceValidator.java | 46 +++++++++++++++++++ 9 files changed, 72 insertions(+), 17 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/FmlParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/FmlParser.java index 87bbf5f0d..73a50c6c1 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/FmlParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/FmlParser.java @@ -50,7 +50,7 @@ public class FmlParser extends ParserBase { ByteArrayInputStream stream = new ByteArrayInputStream(content); String text = TextFile.streamToString(stream); List result = new ArrayList<>(); - NamedElement ctxt = new NamedElement("fml", content); + NamedElement ctxt = new NamedElement("focus", "fml", content); ctxt.setElement(parse(ctxt.getErrors(), text)); result.add(ctxt); return result; diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java index 770dd311d..4f3084af1 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java @@ -119,7 +119,7 @@ public class JsonParser extends ParserBase { @Override public List parse(InputStream inStream) throws IOException, FHIRException { byte[] content = TextFile.streamToBytes(inStream); - NamedElement ctxt = new NamedElement("json", content); + NamedElement ctxt = new NamedElement("focus", "json", content); ByteArrayInputStream stream = new ByteArrayInputStream(content); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/ParserBase.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/ParserBase.java index 572d5ebea..344afc760 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/ParserBase.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/ParserBase.java @@ -71,21 +71,24 @@ public abstract class ParserBase { public class NamedElement { private String name; + private String extension; private Element element; private byte[] content; private List errors = new ArrayList<>(); - public NamedElement(String name, Element element, byte[] content) { + public NamedElement(String name, String extension, Element element, byte[] content) { super(); this.name = name; this.element = element; this.content = content; + this.extension = extension; } - public NamedElement(String name, byte[] content) { + public NamedElement(String name, String extension, byte[] content) { super(); this.name = name; this.content = content; + this.extension = extension; } public String getName() { @@ -106,7 +109,10 @@ public abstract class ParserBase { public void setElement(Element element) { this.element = element; - + } + + public String getFilename() { + return name+"."+extension; } } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHCParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHCParser.java index 5193c4a1c..0760a2531 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHCParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHCParser.java @@ -62,7 +62,7 @@ public class SHCParser extends ParserBase { byte[] content = TextFile.streamToBytes(inStream); ByteArrayInputStream stream = new ByteArrayInputStream(content); List res = new ArrayList<>(); - NamedElement shc = new NamedElement("shc", content); + NamedElement shc = new NamedElement("shc", "json", content); res.add(shc); String src = TextFile.streamToString(stream).trim(); @@ -146,7 +146,7 @@ public class SHCParser extends ParserBase { return res; } // ok. all checks passed, we can now validate the bundle - NamedElement bnd = new NamedElement(path, org.hl7.fhir.utilities.json.parser.JsonParser.composeBytes(cs.getJsonObject("fhirBundle"))); + NamedElement bnd = new NamedElement(path, "json", org.hl7.fhir.utilities.json.parser.JsonParser.composeBytes(cs.getJsonObject("fhirBundle"))); res.add(bnd); bnd.setElement(jsonParser.parse(bnd.getErrors(), cs.getJsonObject("fhirBundle"))); } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHLParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHLParser.java index ca2200812..2ed4b8e07 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHLParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/SHLParser.java @@ -76,7 +76,7 @@ public class SHLParser extends ParserBase { byte[] content = TextFile.streamToBytes(inStream); List res = new ArrayList<>(); - NamedElement shl = addNamedElement(res, "shl", content); + NamedElement shl = addNamedElement(res, "shl", "txt", content); String src = TextFile.bytesToString(content); if (src.startsWith("shlink:/")) { @@ -92,8 +92,8 @@ public class SHLParser extends ParserBase { src = null; } if (src != null) { - NamedElement json = addNamedElement(res, "json", TextFile.stringToBytes(src, false)); byte[] cntin = Base64.getUrlDecoder().decode(src); + NamedElement json = addNamedElement(res, "json", "json", cntin); JsonObject j = null; try { j = org.hl7.fhir.utilities.json.parser.JsonParser.parseObject(cntin); @@ -146,7 +146,7 @@ public class SHLParser extends ParserBase { private void checkManifest(List res, HTTPResult cnt) throws IOException { - NamedElement manifest = addNamedElement(res, "manifest", cnt.getContent()); + NamedElement manifest = addNamedElement(res, "manifest", "json", cnt.getContent()); if (!cnt.getContentType().equals("application/json")) { logError(manifest.getErrors(), "202-08-31", 1, 1, "manifest", IssueType.STRUCTURE, "The mime type should be application/json not "+cnt.getContentType(), IssueSeverity.ERROR); @@ -243,6 +243,7 @@ public class SHLParser extends ParserBase { } private void processContent(List res, List errors, String path, String name, String jose, String ct) throws FHIRFormatError, DefinitionException, FHIRException, IOException { + NamedElement bin = addNamedElement(res, "encrypted", "jose", TextFile.stringToBytes(jose, false)); byte[] cnt = null; JWEObject jwe; try { @@ -250,10 +251,9 @@ public class SHLParser extends ParserBase { jwe.decrypt(new DirectDecrypter(key)); cnt = jwe.getPayload().toBytes(); } catch (Exception e) { - logError(errors, "202-08-31", 1, 1, path, IssueType.STRUCTURE, "Decruption failed: "+e.getMessage(), IssueSeverity.ERROR); + logError(bin.getErrors(), "202-08-31", 1, 1, path, IssueType.STRUCTURE, "Decruption failed: "+e.getMessage(), IssueSeverity.ERROR); } if (cnt != null) { - NamedElement doc = addNamedElement(res, name, cnt); switch (ct) { case "application/smart-health-card": //a JSON file with a .verifiableCredential array containing SMART Health Card JWS strings, as specified by https://spec.smarthealth.cards#via-file-download. @@ -261,23 +261,26 @@ public class SHLParser extends ParserBase { res.addAll(shc.parse(new ByteArrayInputStream(cnt))); break; case "application/fhir+json": + NamedElement doc = addNamedElement(res, name, "json", cnt); // a JSON file containing any FHIR resource (e.g., an individual resource or a Bundle of resources). Generally this format may not be tamper-proof. logError(doc.getErrors(), "202-08-31", 1, 1, name, IssueType.STRUCTURE, "Processing content of type 'application/smart-api-access' is not done yet", IssueSeverity.INFORMATION); break; case "application/smart-api-access": + doc = addNamedElement(res, name, "api.json", cnt); // a JSON file with a SMART Access Token Response (see SMART App Launch). Two additional properties are defined: // aud Required string indicating the FHIR Server Base URL where this token can be used (e.g., "https://server.example.org/fhir") // query: Optional array of strings acting as hints to the client, indicating queries it might want to make (e.g., ["Coverage?patient=123&_tag=family-insurance"]) logError(doc.getErrors(), "202-08-31", 1, 1, name, IssueType.STRUCTURE, "Processing content of type 'application/smart-api-access' is not done yet", IssueSeverity.INFORMATION); break; default: + doc = addNamedElement(res, name, "bin", cnt); logError(doc.getErrors(), "202-08-31", 1, 1, name, IssueType.STRUCTURE, "The Content-Type '"+ct+"' is not known", IssueSeverity.INFORMATION); } } } - private NamedElement addNamedElement(List res, String name, byte[] content) { - NamedElement result = new NamedElement(name, content); + private NamedElement addNamedElement(List res, String name, String type, byte[] content) { + NamedElement result = new NamedElement(name, type, content); res.add(result); return result; } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/TurtleParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/TurtleParser.java index f2b5e731e..35e3c223f 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/TurtleParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/TurtleParser.java @@ -83,7 +83,7 @@ public class TurtleParser extends ParserBase { @Override public List parse(InputStream inStream) throws IOException, FHIRException { byte[] content = TextFile.streamToBytes(inStream); - NamedElement ctxt = new NamedElement("ttl", content); + NamedElement ctxt = new NamedElement("focus", "ttl", content); ByteArrayInputStream stream = new ByteArrayInputStream(content); Turtle src = new Turtle(); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/VerticalBarParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/VerticalBarParser.java index 4773cd671..efd1022ab 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/VerticalBarParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/VerticalBarParser.java @@ -465,7 +465,7 @@ public class VerticalBarParser extends ParserBase { while (!reader.isFinished()) // && (getOptions().getSegmentLimit() == 0 || getOptions().getSegmentLimit() > message.getSegments().size())) readSegment(message, reader); List res = new ArrayList<>(); - res.add(new NamedElement(null, message, content)); + res.add(new NamedElement("focus", "hl7", message, content)); return res; } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/XmlParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/XmlParser.java index cdb71764d..e077f9256 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/XmlParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/XmlParser.java @@ -114,7 +114,7 @@ public class XmlParser extends ParserBase { public List parse(InputStream inStream) throws FHIRFormatError, DefinitionException, FHIRException, IOException { byte[] content = TextFile.streamToBytes(inStream); - NamedElement context = new NamedElement("xml", content); + NamedElement context = new NamedElement("focus", "xml", content); ByteArrayInputStream stream = new ByteArrayInputStream(content); Document doc = null; diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java index 530dcb8bf..f8426d395 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java @@ -176,6 +176,7 @@ import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.MarkDownProcessor; import org.hl7.fhir.utilities.SIDUtilities; import org.hl7.fhir.utilities.StandardsStatus; +import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.UnicodeUtilities; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.Utilities.DecimalStatus; @@ -269,6 +270,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private static final String HTML_FRAGMENT_REGEX = "[a-zA-Z]\\w*(((\\s+)(\\S)*)*)"; private static final boolean STACK_TRACE = false; private static final boolean DEBUG_ELEMENT = false; + private static final boolean SAVE_INTERMEDIARIES = false; // set this to true to get the intermediary formats while we are waiting for a UI around this z(SHC/SHL) private static final HashSet NO_TX_SYSTEM_EXEMPT = new HashSet<>(Arrays.asList("http://loinc.org", "http://unitsofmeasure.org", "http://hl7.org/fhir/sid/icd-9-cm", "http://snomed.info/sct", "http://www.nlm.nih.gov/research/umls/rxnorm")); private static final HashSet NO_HTTPS_LIST = new HashSet<>(Arrays.asList("https://loinc.org", "https://unitsofmeasure.org", "https://snomed.info/sct", "https://www.nlm.nih.gov/research/umls/rxnorm")); @@ -741,6 +743,13 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } timeTracker.load(t); if (validatedContent != null && !validatedContent.isEmpty()) { + if (SAVE_INTERMEDIARIES) { + int index = 0; + for (NamedElement ne : validatedContent) { + index++; + saveValidatedContent(ne, index); + } + } String url = parser.getImpliedProfile(); if (url != null) { StructureDefinition sd = context.fetchResource(StructureDefinition.class, url); @@ -760,6 +769,19 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return (validatedContent == null || validatedContent.isEmpty()) ? null : validatedContent.get(0).getElement(); // todo: this is broken, but fixing it really complicates things elsewhere, so we do this for now } + private void saveValidatedContent(NamedElement ne, int index) { + String tgt = null; + try { + tgt = Utilities.path("[tmp]", "validator", "content"); + Utilities.createDirectory(tgt); + tgt = Utilities.path(tgt, "content-"+index+"-"+ne.getFilename()); + TextFile.bytesToFile(ne.getContent(), tgt); + } catch (Exception e) { + System.out.println("Error saving internal content to '"+tgt+"': "+e.getLocalizedMessage()); + } + + } + @Override public org.hl7.fhir.r5.elementmodel.Element validate(Object appContext, List errors, Resource resource) throws FHIRException { return validate(appContext, errors, resource, new ArrayList<>()); @@ -4986,6 +5008,30 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat pct.done(); } + + if (defn.hasExtension(ToolingExtensions.EXT_SD_IMPOSE_PROFILE)) { + for (Extension ext : defn.getExtensionsByUrl(ToolingExtensions.EXT_SD_IMPOSE_PROFILE)) { + StructureDefinition sdi = context.fetchResource(StructureDefinition.class, ext.getValue().primitiveValue()); + if (sdi == null) { + warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), false, I18nConstants.VALIDATION_VAL_PROFILE_DEPENDS_NOT_RESOLVED, ext.getValue().primitiveValue(), defn.getVersionedUrl()); + } else { + if (crumbTrails) { + element.addMessage(signpost(errors, NO_RULE_DATE, IssueType.INFORMATIONAL, element.line(), element.col(), stack.getLiteralPath(), I18nConstants.VALIDATION_VAL_PROFILE_SIGNPOST_DEP, sdi.getUrl(), defn.getVersionedUrl())); + } + stack.resetIds(); + if (pctOwned) { + pct = new PercentageTracker(resource.countDescendents(), resource.fhirType(), sdi.getUrl(), logProgress); + } + ok = startInner(hostContext, errors, resource, element, sdi, stack, false, pct, mode.withSource(ProfileSource.ProfileDependency)) && ok; + if (pctOwned) { + pct.done(); + } + + } + } + } + + Element meta = element.getNamedChild(META); if (meta != null) { List profiles = new ArrayList(); From 808acb9d2989f3945fbc86e41a09b7adeb76ae97 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Mon, 4 Sep 2023 13:38:37 +1000 Subject: [PATCH 4/8] NPE proofing property handling for Code Systems --- .../r5/terminologies/CodeSystemUtilities.java | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/CodeSystemUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/CodeSystemUtilities.java index f4d5d76c3..a3a251414 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/CodeSystemUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/CodeSystemUtilities.java @@ -105,7 +105,7 @@ public class CodeSystemUtilities { @Override public int compare(ConceptDefinitionComponent o1, ConceptDefinitionComponent o2) { - return o1.getCode().compareToIgnoreCase(o2.getCode()); + return o1.hasCode() ? o1.getCode().compareToIgnoreCase(o2.getCode()) : 0; } } @@ -252,7 +252,7 @@ public class CodeSystemUtilities { private static String defineProperty(CodeSystem cs, String code, PropertyType pt) { String url = "http://hl7.org/fhir/concept-properties#"+code; for (PropertyComponent p : cs.getProperty()) { - if (p.getCode().equals(code)) { + if (p.hasCode() && p.getCode().equals(code)) { if (!p.getUri().equals(url)) { throw new Error("URI mismatch for code "+code+" url = "+p.getUri()+" vs "+url); } @@ -391,7 +391,7 @@ public class CodeSystemUtilities { public static void defineCodeSystemProperty(CodeSystem cs, String code, String description, PropertyType type) { for (PropertyComponent p : cs.getProperty()) { - if (p.getCode().equals(code)) + if (p.hasCode() && p.getCode().equals(code)) return; } cs.addProperty().setCode(code).setDescription(description).setType(type).setUri("http://hl7.org/fhir/concept-properties#"+code); @@ -466,7 +466,7 @@ public class CodeSystemUtilities { public static ConceptDefinitionComponent findCode(List list, String code) { for (ConceptDefinitionComponent c : list) { - if (c.getCode().equals(code)) + if (c.hasCode() && c.getCode().equals(code)) return c; ConceptDefinitionComponent s = findCode(c.getConcept(), code); if (s != null) @@ -477,7 +477,7 @@ public class CodeSystemUtilities { public static ConceptDefinitionComponent findCodeOrAltCode(List list, String code, String use) { for (ConceptDefinitionComponent c : list) { - if (c.getCode().equals(code)) + if (c.hasCode() && c.getCode().equals(code)) return c; for (ConceptPropertyComponent p : c.getProperty()) { if ("alternateCode".equals(p.getCode()) && (use == null || hasUse(p, use)) && p.hasValue() && p.getValue().isPrimitive() && code.equals(p.getValue().primitiveValue())) { @@ -537,29 +537,30 @@ public class CodeSystemUtilities { public static DataType readProperty(ConceptDefinitionComponent concept, String code) { for (ConceptPropertyComponent p : concept.getProperty()) - if (p.getCode().equals(code)) + if (p.hasCode() && p.getCode().equals(code)) return p.getValue(); return null; } public static ConceptPropertyComponent getProperty(ConceptDefinitionComponent concept, String code) { for (ConceptPropertyComponent p : concept.getProperty()) - if (p.getCode().equals(code)) + if (p.hasCode() && p.getCode().equals(code)) return p; return null; } public static List getPropertyValues(ConceptDefinitionComponent concept, String code) { List res = new ArrayList<>(); - for (ConceptPropertyComponent p : concept.getProperty()) { - if (p.getCode().equals(code)) { - res.add(p); + if (code != null) { + for (ConceptPropertyComponent p : concept.getProperty()) { + if (code.equals(p.getCode())) { + res.add(p); + } } } return res; } - // see http://hl7.org/fhir/R4/codesystem.html#hierachy // returns additional parents not in the heirarchy public static List getOtherChildren(CodeSystem cs, ConceptDefinitionComponent c) { @@ -828,7 +829,7 @@ public class CodeSystemUtilities { private static String defineProperty(CodeSystem cs, PropertyComponent pd, PropertyType pt) { for (PropertyComponent p : cs.getProperty()) { - if (p.getCode().equals(pd.getCode())) { + if (p.hasCode() && p.getCode().equals(pd.getCode())) { if (!p.getUri().equals(pd.getUri())) { throw new Error("URI mismatch for code "+pd.getCode()+" url = "+p.getUri()+" vs "+pd.getUri()); } @@ -846,7 +847,7 @@ public class CodeSystemUtilities { private static PropertyComponent getPropertyDefinition(CodeSystem cs, ConceptPropertyComponent p) { for (PropertyComponent t : cs.getProperty()) { - if (t.getCode().equals(p.getCode())) { + if (t.hasCode() && t.getCode().equals(p.getCode())) { return t; } } @@ -881,7 +882,7 @@ public class CodeSystemUtilities { public static boolean hasPropertyDef(CodeSystem cs, String property) { for (PropertyComponent pd : cs.getProperty()) { - if (pd.getCode().equals(property)) { + if (pd.hasCode() && pd.getCode().equals(property)) { return true; } } From 68b30fe819060007f2118f116049395106b70e23 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Mon, 4 Sep 2023 13:39:45 +1000 Subject: [PATCH 5/8] fix unknown code message to include code system version --- .../fhir/r5/terminologies/validation/ValueSetValidator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/validation/ValueSetValidator.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/validation/ValueSetValidator.java index 396952e0f..53afdf5b1 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/validation/ValueSetValidator.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/validation/ValueSetValidator.java @@ -688,10 +688,10 @@ public class ValueSetValidator extends ValueSetProcessBase { ConceptDefinitionComponent cc = cs.hasUserData("tx.cs.special") ? ((SpecialCodeSystem) cs.getUserData("tx.cs.special")).findConcept(code) : findCodeInConcept(cs.getConcept(), code.getCode(), allAltCodes); if (cc == null) { if (cs.getContent() == CodeSystemContentMode.FRAGMENT) { - String msg = context.formatMessage(I18nConstants.UNKNOWN_CODE__IN_FRAGMENT, code.getCode(), cs.getUrl()); + String msg = context.formatMessage(I18nConstants.UNKNOWN_CODE__IN_FRAGMENT, code.getCode(), cs.getVersionedUrl()); return new ValidationResult(IssueSeverity.WARNING, msg, makeIssue(IssueSeverity.ERROR, IssueType.CODEINVALID, path+".code", msg)); } else { - String msg = context.formatMessage(I18nConstants.UNKNOWN_CODE__IN_, code.getCode(), cs.getUrl()); + String msg = context.formatMessage(I18nConstants.UNKNOWN_CODE__IN_, code.getCode(), cs.getVersionedUrl()); return new ValidationResult(IssueSeverity.ERROR, msg, makeIssue(IssueSeverity.ERROR, IssueType.CODEINVALID, path+".code", msg)); } } From 3fa9a6725a6d2a1bf45068a9f17c304220a6e07a Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Mon, 4 Sep 2023 13:39:59 +1000 Subject: [PATCH 6/8] support for sub-packages in packagelist.json --- .../org/hl7/fhir/utilities/npm/PackageList.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageList.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageList.java index d89b7558d..220e610ef 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageList.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageList.java @@ -67,7 +67,22 @@ public class PackageList { json.set("date", date); } - public boolean isPartofMainSpec() { + public List subPackages() { + List list = new ArrayList<>(); + if (json.has("sub-packages")) { + list.addAll(json.getStrings("sub-packages")); + } + return list; + } + + public void clearSubPackages() { + json.remove("sub-packages"); + } + public void addSubPackage(String s) { + json.forceArray("sub-packages").add(s); + } + + private boolean isPartofMainSpec() { return Utilities.startsWithInList(path(), "http://hl7.org/fhir/DSTU2", "http://hl7.org/fhir/2015Sep", "http://hl7.org/fhir/2015May"); } From 84308e70b1e73bce7e503fba9c9880e0b39bcca5 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Mon, 4 Sep 2023 13:40:20 +1000 Subject: [PATCH 7/8] fix warning/error message about experimental property --- .../src/main/resources/Messages.properties | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages.properties b/org.hl7.fhir.utilities/src/main/resources/Messages.properties index 56270863e..04a1162f9 100644 --- a/org.hl7.fhir.utilities/src/main/resources/Messages.properties +++ b/org.hl7.fhir.utilities/src/main/resources/Messages.properties @@ -787,22 +787,22 @@ BUNDLE_BUNDLE_POSSIBLE_MATCH_NO_FU = Entry {0} matches the reference {1} by type BUNDLE_BUNDLE_POSSIBLE_MATCH_WRONG_FU = Entry {0} matches the reference {1} by type and id but it''s fullUrl {2} does not match the full target URL {3} by Bundle resolution rules SD_ILLEGAL_CHARACTERISTICS = This element has a {0} but the types {1} do not make this kind of constraint relevant SD_VALUE_COMPLEX_FIXED = For the complex type {0}, consider using a pattern rather than a fixed value to avoid over-constraining the instance -VALUESET_SHAREABLE_MISSING = The ShareableValueSet profile says that the {0} element is mandatory, but it is not present. Published value sets SHOULD conform to the ShareableValueSet profile -VALUESET_SHAREABLE_EXTRA_MISSING = The ShareableValueSet profile recommends that the {0} element is populated, but it is not present. Published value sets SHOULD conform to the ShareableValueSet profile -VALUESET_SHAREABLE_MISSING_HL7 = The ShareableValueSet profile says that the {0} element is mandatory, but it is not found. HL7 Published value sets SHALL conform to the ShareableValueSet profile -VALUESET_SHAREABLE_EXTRA_MISSING_HL7 = The ShareableValueSet profile recommends that the {0} element is populated, but it is not found. HL7 Published value sets SHALL conform to the ShareableValueSet profile -CODESYSTEM_SHAREABLE_MISSING = The ShareableCodeSystem profile says that the {0} element is mandatory, but it is not present. Published code systems SHOULD conform to the ShareableCodeSystem profile -CODESYSTEM_SHAREABLE_EXTRA_MISSING = The ShareableCodeSystem profile recommends that the {0} element is populated, but it is not present. Published code systems SHOULD conform to the ShareableCodeSystem profile -CODESYSTEM_SHAREABLE_MISSING_HL7 = The ShareableCodeSystem profile says that the {0} element is mandatory, but it is not found. HL7 Published code systems SHALL conform to the ShareableCodeSystem profile -CODESYSTEM_SHAREABLE_EXTRA_MISSING_HL7 = The ShareableCodeSystem profile recommends that the {0} element is populated, but it is not found. HL7 Published code systems SHALL conform to the ShareableCodeSystem profile -CONCEPTMAP_SHAREABLE_MISSING = The ShareableConceptMap profile says that the {0} element is mandatory, but it is not present. Published concept maps SHOULD conform to the ShareableConceptMap profile -CONCEPTMAP_SHAREABLE_EXTRA_MISSING = The ShareableConceptMap profile recommends that the {0} element is populated, but it is not present. Published concept maps SHOULD conform to the ShareableConceptMap profile -CONCEPTMAP_SHAREABLE_MISSING_HL7 = The ShareableConceptMap profile says that the {0} element is mandatory, but it is not found. HL7 Published concept maps SHALL conform to the ShareableConceptMap profile -CONCEPTMAP_SHAREABLE_EXTRA_MISSING_HL7 = The ShareableConceptMap profile recommends that the {0} element is populated, but it is not found. HL7 Published concept maps SHALL conform to the ShareableConceptMap profile -MEASURE_SHAREABLE_MISSING = The ShareableMeasure profile says that the {0} element is mandatory, but it is not present. Published measures SHOULD conform to the ShareableMeasure profile -MEASURE_SHAREABLE_EXTRA_MISSING = The ShareableMeasure profile recommends that the {0} element is populated, but it is not present. Published measures SHOULD conform to the ShareableMeasure profile -MEASURE_SHAREABLE_MISSING_HL7 = The ShareableMeasure profile says that the {0} element is mandatory, but it is not found. HL7 Published measures SHALL conform to the ShareableMeasure profile -MEASURE_SHAREABLE_EXTRA_MISSING_HL7 = The ShareableMeasure profile recommends that the {0} element is populated, but it is not found. HL7 Published measures SHALL conform to the ShareableMeasure profile +VALUESET_SHAREABLE_MISSING = Published value sets SHOULD conform to the ShareableValueSet profile, which says that the element ValueSet.{0} is mandatory, but it is not present +VALUESET_SHAREABLE_EXTRA_MISSING = Published value sets SHOULD conform to the ShareableValueSet profile, which says that the element ValueSet.{0} should be present, but it is not +VALUESET_SHAREABLE_MISSING_HL7 = Published value sets SHALL conform to the ShareableValueSet profile, which says that the element ValueSet.{0} is mandatory, but it is not present +VALUESET_SHAREABLE_EXTRA_MISSING_HL7 = Published value sets SHALL conform to the ShareableValueSet profile, which says that the element ValueSet.{0} should be present, but it is not +CODESYSTEM_SHAREABLE_MISSING = Published code systems SHOULD conform to the ShareableCodeSystem profile, which says that the element CodeSystem.{0} is mandatory, but it is not present +CODESYSTEM_SHAREABLE_EXTRA_MISSING = Published code systems SHOULD conform to the ShareableCodeSystem profile, which says that the element CodeSystem.{0} should be present, but it is not +CODESYSTEM_SHAREABLE_MISSING_HL7 = Published code systems SHALL conform to the ShareableCodeSystem profile, which says that the element CodeSystem.{0} is mandatory, but it is not present +CODESYSTEM_SHAREABLE_EXTRA_MISSING_HL7 = Published code systems SHALL conform to the ShareableCodeSystem profile, which says that the element CodeSystem.{0} should be present, but it is not +CONCEPTMAP_SHAREABLE_MISSING = Published concept maps SHOULD conform to the ShareableConceptMap profile, which says that the element ConceptMap.{0} is mandatory, but it is not present +CONCEPTMAP_SHAREABLE_EXTRA_MISSING = Published concept maps SHOULD conform to the ShareableConceptMap profile, which says that the element ConceptMap.{0} should be present, but it is not +CONCEPTMAP_SHAREABLE_MISSING_HL7 = Published concept maps SHALL conform to the ShareableConceptMap profile, which says that the element ConceptMap.{0} is mandatory, but it is not present +CONCEPTMAP_SHAREABLE_EXTRA_MISSING_HL7 = Published concept maps SHALL conform to the ShareableConceptMap profile, which says that the element ConceptMap.{0} should be present, but it is not +MEASURE_SHAREABLE_MISSING = Published measures SHOULD conform to the ShareableMeasure profile, which says that the element Measure.{0} is mandatory, but it is not present +MEASURE_SHAREABLE_EXTRA_MISSING = Published measures SHOULD conform to the ShareableMeasure profile, which says that the element Measure.{0} should be present, but it is not +MEASURE_SHAREABLE_MISSING_HL7 = Published measures SHALL conform to the ShareableMeasure profile, which says that the element Measure.{0} is mandatory, but it is not present +MEASURE_SHAREABLE_EXTRA_MISSING_HL7 = Published measures SHALL conform to the ShareableMeasure profile, which says that the element Measure.{0} should be present, but it is not TYPE_SPECIFIC_CHECKS_DT_MARKDOWN_HTML = The markdown contains content that appears to be an embedded HTML tag starting at ''{0}''. This will (or SHOULD) be escaped by the presentation layer. The content should be checked to confirm that this is the desired behaviour TYPE_SPECIFIER_ILLEGAL_TYPE = The Type specifier {1} specified an invalid type {0} TYPE_SPECIFIER_ABSTRACT_TYPE = The Type specifier {1} specified an abstract type {0} From d7d56f5cec9359cb1964ed601f0b1a3450c3ada8 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Mon, 4 Sep 2023 13:40:29 +1000 Subject: [PATCH 8/8] Support for IPS-AU --- .../org/hl7/fhir/validation/ValidatorCli.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidatorCli.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidatorCli.java index 7e9da4c83..b5c5afd35 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidatorCli.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/ValidatorCli.java @@ -283,6 +283,24 @@ public class ValidatorCli { res.add("hl7.fhir.uv.ips#1.1.0"); res.add("-profile"); res.add("http://hl7.org/fhir/uv/ips/StructureDefinition/Bundle-uv-ips"); + res.add("-extension"); + res.add("any"); + res.add("-bundle"); + res.add("Composition:0"); + res.add("http://hl7.org/fhir/uv/ips/StructureDefinition/Composition-uv-ips"); + } else if (a.equals("-ips:au")) { + res.add("-version"); + res.add("4.0"); + res.add("-check-ips-codes"); + res.add("-ig"); + res.add("hl7.fhir.au.ips#current"); + res.add("-profile"); + res.add("http://hl7.org.au/fhir/ips/StructureDefinition/Bundle-au-ips"); + res.add("-extension"); + res.add("any"); + res.add("-bundle"); + res.add("Composition:0"); + res.add("http://hl7.org.au/fhir/ips/StructureDefinition/Composition-au-ips"); } else if (a.equals("-ips#")) { res.add("-version"); res.add("4.0"); @@ -291,6 +309,11 @@ public class ValidatorCli { res.add("hl7.fhir.uv.ips#"+a.substring(5)); res.add("-profile"); res.add("http://hl7.org/fhir/uv/ips/StructureDefinition/Bundle-uv-ips"); + res.add("-extension"); + res.add("any"); + res.add("-bundle"); + res.add("Composition:0"); + res.add("http://hl7.org/fhir/uv/ips/StructureDefinition/Composition-uv-ips"); } else if (a.startsWith("-ips$")) { res.add("-version"); res.add("4.0"); @@ -299,6 +322,11 @@ public class ValidatorCli { res.add("hl7.fhir.uv.ips#current$"+a.substring(5)); res.add("-profile"); res.add("http://hl7.org/fhir/uv/ips/StructureDefinition/Bundle-uv-ips"); + res.add("-extension"); + res.add("any"); + res.add("-bundle"); + res.add("Composition:0"); + res.add("http://hl7.org/fhir/uv/ips/StructureDefinition/Composition-uv-ips"); } else { res.add(a); }