diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv30_50/datatypes30_50/ElementDefinition30_50.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv30_50/datatypes30_50/ElementDefinition30_50.java index 27f33cd02..3cf1d0ae9 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv30_50/datatypes30_50/ElementDefinition30_50.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv30_50/datatypes30_50/ElementDefinition30_50.java @@ -5,6 +5,7 @@ import java.util.stream.Collectors; import org.hl7.fhir.convertors.VersionConvertorConstants; import org.hl7.fhir.convertors.context.ConversionContext30_50; +import org.hl7.fhir.convertors.context.ConversionContext30_50; import org.hl7.fhir.convertors.conv30_50.VersionConvertor_30_50; import org.hl7.fhir.convertors.conv30_50.datatypes30_50.complextypes30_50.Coding30_50; import org.hl7.fhir.convertors.conv30_50.datatypes30_50.primitivetypes30_50.Boolean30_50; @@ -17,9 +18,17 @@ import org.hl7.fhir.convertors.conv30_50.datatypes30_50.primitivetypes30_50.Unsi import org.hl7.fhir.convertors.conv30_50.datatypes30_50.primitivetypes30_50.Uri30_50; import org.hl7.fhir.convertors.conv30_50.resources30_50.Enumerations30_50; import org.hl7.fhir.exceptions.FHIRException; +import org.hl7.fhir.dstu3.model.BooleanType; +import org.hl7.fhir.dstu3.model.Extension; +import org.hl7.fhir.dstu3.model.MarkdownType; +import org.hl7.fhir.dstu3.model.StringType; +import org.hl7.fhir.dstu3.model.UriType; import org.hl7.fhir.r5.model.CanonicalType; +import org.hl7.fhir.r5.model.CodeType; import org.hl7.fhir.r5.model.DataType; import org.hl7.fhir.r5.model.ElementDefinition; +import org.hl7.fhir.r5.model.UsageContext; +import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingAdditionalComponent; import org.hl7.fhir.utilities.Utilities; public class ElementDefinition30_50 { @@ -643,7 +652,8 @@ public class ElementDefinition30_50 { public static ElementDefinition.ElementDefinitionBindingComponent convertElementDefinitionBindingComponent(org.hl7.fhir.dstu3.model.ElementDefinition.ElementDefinitionBindingComponent src) throws FHIRException { if (src == null) return null; ElementDefinition.ElementDefinitionBindingComponent tgt = new ElementDefinition.ElementDefinitionBindingComponent(); - ConversionContext30_50.INSTANCE.getVersionConvertor_30_50().copyElement(src, tgt, VersionConvertor_30_50.EXT_SRC_TYPE); + ConversionContext30_50.INSTANCE.getVersionConvertor_30_50().copyElement(src, tgt, VersionConvertor_30_50.EXT_SRC_TYPE, + "http://hl7.org/fhir/5.0/StructureDefinition/extension-ElementDefinition.binding.additional"); if (src.hasStrength()) tgt.setStrengthElement(Enumerations30_50.convertBindingStrength(src.getStrengthElement())); if (src.hasDescription()) tgt.setDescriptionElement(String30_50.convertStringToMarkdown(src.getDescriptionElement())); if (src.hasValueSet()) { @@ -657,6 +667,9 @@ public class ElementDefinition30_50 { } tgt.setValueSet(VersionConvertorConstants.refToVS(tgt.getValueSet())); } + for (org.hl7.fhir.dstu3.model.Extension ext : src.getExtensionsByUrl("http://hl7.org/fhir/5.0/StructureDefinition/extension-ElementDefinition.binding.additional")) { + tgt.addAdditional(convertAdditional(ext)); + } return tgt; } @@ -680,9 +693,64 @@ public class ElementDefinition30_50 { else tgt.setValueSet(new org.hl7.fhir.dstu3.model.Reference(src.getValueSet())); } } + for (ElementDefinitionBindingAdditionalComponent ab : src.getAdditional()) { + tgt.addExtension(convertAdditional(ab)); + } return tgt; } + + private static ElementDefinitionBindingAdditionalComponent convertAdditional(Extension src) { + if (src == null) return null; + ElementDefinitionBindingAdditionalComponent tgt = new ElementDefinitionBindingAdditionalComponent(); + ConversionContext30_50.INSTANCE.getVersionConvertor_30_50().copyElement(src, tgt, "valueSet", "purpose", "documentation", "shortDoco", "usage", "any"); + if (src.hasExtension("purpose")) { + tgt.getPurposeElement().setValueAsString(src.getExtensionByUrl("purpose").getValue().primitiveValue()); + } + if (src.hasExtension("valueSet")) { + tgt.setValueSetElement(Uri30_50.convertCanonical((UriType) src.getExtensionByUrl("valueSet").getValue())); + } + if (src.hasExtension("documentation")) { + tgt.setDocumentationElement(MarkDown30_50.convertMarkdown((MarkdownType) src.getExtensionByUrl("documentation").getValue())); + } + if (src.hasExtension("shortDoco")) { + tgt.setShortDocoElement(String30_50.convertString((StringType) src.getExtensionByUrl("shortDoco").getValue())); + } + for (Extension t : src.getExtensionsByUrl("usage")) { + tgt.addUsage(UsageContext30_50.convertUsageContext((org.hl7.fhir.dstu3.model.UsageContext) t.getValue())); + } + if (src.hasExtension("any")) { + tgt.setAnyElement(Boolean30_50.convertBoolean((BooleanType) src.getExtensionByUrl("any").getValue())); + } + return tgt; + } + + private static Extension convertAdditional(ElementDefinitionBindingAdditionalComponent src) { + if (src == null) return null; + Extension tgt = new Extension(); + ConversionContext30_50.INSTANCE.getVersionConvertor_30_50().copyElement(src, tgt); + if (src.hasPurpose()) { + tgt.addExtension(new Extension("purpose", new org.hl7.fhir.dstu3.model.CodeType(src.getPurposeElement().primitiveValue()))); + } + if (src.hasValueSet()) { + tgt.addExtension(new Extension("valueSet", Uri30_50.convertCanonical(src.getValueSetElement()))); + } + if (src.hasDocumentation()) { + tgt.addExtension(new Extension("documentation", MarkDown30_50.convertMarkdown(src.getDocumentationElement()))); + } + if (src.hasShortDoco()) { + tgt.addExtension(new Extension("shortDoco", String30_50.convertString(src.getShortDocoElement()))); + } + for (UsageContext t : src.getUsage()) { + tgt.addExtension(new Extension("usage", UsageContext30_50.convertUsageContext(t))); + } + if (src.hasAny()) { + tgt.addExtension(new Extension("any", Boolean30_50.convertBoolean(src.getAnyElement()))); + } + + return tgt; + } + public static ElementDefinition.ElementDefinitionMappingComponent convertElementDefinitionMappingComponent(org.hl7.fhir.dstu3.model.ElementDefinition.ElementDefinitionMappingComponent src) throws FHIRException { if (src == null) return null; ElementDefinition.ElementDefinitionMappingComponent tgt = new ElementDefinition.ElementDefinitionMappingComponent(); diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/datatypes40_50/special40_50/ElementDefinition40_50.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/datatypes40_50/special40_50/ElementDefinition40_50.java index c46fcd586..f51e9f55f 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/datatypes40_50/special40_50/ElementDefinition40_50.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/datatypes40_50/special40_50/ElementDefinition40_50.java @@ -5,6 +5,7 @@ import java.util.stream.Collectors; import org.hl7.fhir.convertors.context.ConversionContext40_50; import org.hl7.fhir.convertors.conv40_50.datatypes40_50.BackboneElement40_50; import org.hl7.fhir.convertors.conv40_50.datatypes40_50.general40_50.Coding40_50; +import org.hl7.fhir.convertors.conv40_50.datatypes40_50.metadata40_50.UsageContext40_50; import org.hl7.fhir.convertors.conv40_50.datatypes40_50.primitive40_50.Boolean40_50; import org.hl7.fhir.convertors.conv40_50.datatypes40_50.primitive40_50.Canonical40_50; import org.hl7.fhir.convertors.conv40_50.datatypes40_50.primitive40_50.Code40_50; @@ -16,12 +17,22 @@ import org.hl7.fhir.convertors.conv40_50.datatypes40_50.primitive40_50.UnsignedI import org.hl7.fhir.convertors.conv40_50.datatypes40_50.primitive40_50.Uri40_50; import org.hl7.fhir.convertors.conv40_50.resources40_50.Enumerations40_50; import org.hl7.fhir.exceptions.FHIRException; +import org.hl7.fhir.r4.model.BooleanType; +import org.hl7.fhir.r4.model.CanonicalType; +import org.hl7.fhir.r4.model.Extension; +import org.hl7.fhir.r4.model.MarkdownType; +import org.hl7.fhir.r4.model.StringType; +import org.hl7.fhir.r5.model.CodeType; +import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingAdditionalComponent; +import org.hl7.fhir.r5.model.UsageContext; public class ElementDefinition40_50 { public static org.hl7.fhir.r5.model.ElementDefinition convertElementDefinition(org.hl7.fhir.r4.model.ElementDefinition src) throws FHIRException { if (src == null) return null; org.hl7.fhir.r5.model.ElementDefinition tgt = new org.hl7.fhir.r5.model.ElementDefinition(); - BackboneElement40_50.copyBackboneElement(src, tgt, "http://hl7.org/fhir/5.0/StructureDefinition/extension-ElementDefinition.mustHaveValue", "http://hl7.org/fhir/5.0/StructureDefinition/extension-ElementDefinition.valueAlternatives"); + BackboneElement40_50.copyBackboneElement(src, tgt, + "http://hl7.org/fhir/5.0/StructureDefinition/extension-ElementDefinition.mustHaveValue", + "http://hl7.org/fhir/5.0/StructureDefinition/extension-ElementDefinition.valueAlternatives"); if (src.hasPath()) tgt.setPathElement(String40_50.convertString(src.getPathElement())); tgt.setRepresentation(src.getRepresentation().stream().map(ElementDefinition40_50::convertPropertyRepresentation).collect(Collectors.toList())); if (src.hasSliceName()) tgt.setSliceNameElement(String40_50.convertString(src.getSliceNameElement())); @@ -604,10 +615,66 @@ public class ElementDefinition40_50 { public static org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent convertElementDefinitionBindingComponent(org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionBindingComponent src) throws FHIRException { if (src == null) return null; org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent tgt = new org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent(); - ConversionContext40_50.INSTANCE.getVersionConvertor_40_50().copyElement(src, tgt); + ConversionContext40_50.INSTANCE.getVersionConvertor_40_50().copyElement(src, tgt, + "http://hl7.org/fhir/5.0/StructureDefinition/extension-ElementDefinition.binding.additional"); if (src.hasStrength()) tgt.setStrengthElement(Enumerations40_50.convertBindingStrength(src.getStrengthElement())); if (src.hasDescription()) tgt.setDescriptionElement(String40_50.convertStringToMarkdown(src.getDescriptionElement())); if (src.hasValueSet()) tgt.setValueSetElement(Canonical40_50.convertCanonical(src.getValueSetElement())); + + for (org.hl7.fhir.r4.model.Extension ext : src.getExtensionsByUrl("http://hl7.org/fhir/5.0/StructureDefinition/extension-ElementDefinition.binding.additional")) { + tgt.addAdditional(convertAdditional(ext)); + } + return tgt; + } + + private static ElementDefinitionBindingAdditionalComponent convertAdditional(Extension src) { + if (src == null) return null; + ElementDefinitionBindingAdditionalComponent tgt = new ElementDefinitionBindingAdditionalComponent(); + ConversionContext40_50.INSTANCE.getVersionConvertor_40_50().copyElement(src, tgt, "valueSet", "purpose", "documentation", "shortDoco", "usage", "any"); + if (src.hasExtension("purpose")) { + tgt.getPurposeElement().setValueAsString(src.getExtensionByUrl("purpose").getValue().primitiveValue()); + } + if (src.hasExtension("valueSet")) { + tgt.setValueSetElement(Canonical40_50.convertCanonical((CanonicalType) src.getExtensionByUrl("valueSet").getValue())); + } + if (src.hasExtension("documentation")) { + tgt.setDocumentationElement(MarkDown40_50.convertMarkdown((MarkdownType) src.getExtensionByUrl("documentation").getValue())); + } + if (src.hasExtension("shortDoco")) { + tgt.setShortDocoElement(String40_50.convertString((StringType) src.getExtensionByUrl("shortDoco").getValue())); + } + for (Extension t : src.getExtensionsByUrl("usage")) { + tgt.addUsage(UsageContext40_50.convertUsageContext((org.hl7.fhir.r4.model.UsageContext) t.getValue())); + } + if (src.hasExtension("any")) { + tgt.setAnyElement(Boolean40_50.convertBoolean((BooleanType) src.getExtensionByUrl("any").getValue())); + } + return tgt; + } + + private static Extension convertAdditional(ElementDefinitionBindingAdditionalComponent src) { + if (src == null) return null; + Extension tgt = new Extension(); + ConversionContext40_50.INSTANCE.getVersionConvertor_40_50().copyElement(src, tgt); + if (src.hasPurpose()) { + tgt.addExtension(new Extension("purpose", new CodeType(src.getPurposeElement().primitiveValue()))); + } + if (src.hasValueSet()) { + tgt.addExtension(new Extension("valueSet", Canonical40_50.convertCanonical(src.getValueSetElement()))); + } + if (src.hasDocumentation()) { + tgt.addExtension(new Extension("documentation", MarkDown40_50.convertMarkdown(src.getDocumentationElement()))); + } + if (src.hasShortDoco()) { + tgt.addExtension(new Extension("shortDoco", String40_50.convertString(src.getShortDocoElement()))); + } + for (UsageContext t : src.getUsage()) { + tgt.addExtension(new Extension("usage", UsageContext40_50.convertUsageContext(t))); + } + if (src.hasAny()) { + tgt.addExtension(new Extension("any", Boolean40_50.convertBoolean(src.getAnyElement()))); + } + return tgt; } @@ -618,6 +685,9 @@ public class ElementDefinition40_50 { if (src.hasStrength()) tgt.setStrengthElement(Enumerations40_50.convertBindingStrength(src.getStrengthElement())); if (src.hasDescription()) tgt.setDescriptionElement(String40_50.convertString(src.getDescriptionElement())); if (src.hasValueSet()) tgt.setValueSetElement(Canonical40_50.convertCanonical(src.getValueSetElement())); + for (ElementDefinitionBindingAdditionalComponent ab : src.getAdditional()) { + tgt.addExtension(convertAdditional(ab)); + } return tgt; } diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv43_50/datatypes43_50/special43_50/ElementDefinition43_50.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv43_50/datatypes43_50/special43_50/ElementDefinition43_50.java index 44e7ddb2b..507366fe4 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv43_50/datatypes43_50/special43_50/ElementDefinition43_50.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv43_50/datatypes43_50/special43_50/ElementDefinition43_50.java @@ -3,6 +3,12 @@ package org.hl7.fhir.convertors.conv43_50.datatypes43_50.special43_50; import java.util.stream.Collectors; import org.hl7.fhir.convertors.context.ConversionContext43_50; +import org.hl7.fhir.convertors.context.ConversionContext43_50; +import org.hl7.fhir.convertors.conv43_50.datatypes43_50.metadata43_50.UsageContext43_50; +import org.hl7.fhir.convertors.conv43_50.datatypes43_50.primitive43_50.Boolean43_50; +import org.hl7.fhir.convertors.conv43_50.datatypes43_50.primitive43_50.Canonical43_50; +import org.hl7.fhir.convertors.conv43_50.datatypes43_50.primitive43_50.MarkDown43_50; +import org.hl7.fhir.convertors.conv43_50.datatypes43_50.primitive43_50.String43_50; import org.hl7.fhir.convertors.conv43_50.datatypes43_50.BackboneElement43_50; import org.hl7.fhir.convertors.conv43_50.datatypes43_50.general43_50.Coding43_50; import org.hl7.fhir.convertors.conv43_50.datatypes43_50.primitive43_50.Boolean43_50; @@ -16,6 +22,14 @@ import org.hl7.fhir.convertors.conv43_50.datatypes43_50.primitive43_50.UnsignedI import org.hl7.fhir.convertors.conv43_50.datatypes43_50.primitive43_50.Uri43_50; import org.hl7.fhir.convertors.conv43_50.resources43_50.Enumerations43_50; import org.hl7.fhir.exceptions.FHIRException; +import org.hl7.fhir.r4b.model.BooleanType; +import org.hl7.fhir.r4b.model.CanonicalType; +import org.hl7.fhir.r4b.model.Extension; +import org.hl7.fhir.r4b.model.MarkdownType; +import org.hl7.fhir.r4b.model.StringType; +import org.hl7.fhir.r5.model.CodeType; +import org.hl7.fhir.r5.model.UsageContext; +import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingAdditionalComponent; public class ElementDefinition43_50 { public static org.hl7.fhir.r5.model.ElementDefinition convertElementDefinition(org.hl7.fhir.r4b.model.ElementDefinition src) throws FHIRException { @@ -605,10 +619,14 @@ public class ElementDefinition43_50 { public static org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent convertElementDefinitionBindingComponent(org.hl7.fhir.r4b.model.ElementDefinition.ElementDefinitionBindingComponent src) throws FHIRException { if (src == null) return null; org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent tgt = new org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent(); - ConversionContext43_50.INSTANCE.getVersionConvertor_43_50().copyElement(src, tgt); + ConversionContext43_50.INSTANCE.getVersionConvertor_43_50().copyElement(src, tgt, + "http://hl7.org/fhir/5.0/StructureDefinition/extension-ElementDefinition.binding.additional"); if (src.hasStrength()) tgt.setStrengthElement(Enumerations43_50.convertBindingStrength(src.getStrengthElement())); if (src.hasDescription()) tgt.setDescriptionElement(String43_50.convertStringToMarkdown(src.getDescriptionElement())); if (src.hasValueSet()) tgt.setValueSetElement(Canonical43_50.convertCanonical(src.getValueSetElement())); + for (org.hl7.fhir.r4b.model.Extension ext : src.getExtensionsByUrl("http://hl7.org/fhir/5.0/StructureDefinition/extension-ElementDefinition.binding.additional")) { + tgt.addAdditional(convertAdditional(ext)); + } return tgt; } @@ -619,9 +637,64 @@ public class ElementDefinition43_50 { if (src.hasStrength()) tgt.setStrengthElement(Enumerations43_50.convertBindingStrength(src.getStrengthElement())); if (src.hasDescription()) tgt.setDescriptionElement(String43_50.convertString(src.getDescriptionElement())); if (src.hasValueSet()) tgt.setValueSetElement(Canonical43_50.convertCanonical(src.getValueSetElement())); + for (ElementDefinitionBindingAdditionalComponent ab : src.getAdditional()) { + tgt.addExtension(convertAdditional(ab)); + } return tgt; } + + private static ElementDefinitionBindingAdditionalComponent convertAdditional(Extension src) { + if (src == null) return null; + ElementDefinitionBindingAdditionalComponent tgt = new ElementDefinitionBindingAdditionalComponent(); + ConversionContext43_50.INSTANCE.getVersionConvertor_43_50().copyElement(src, tgt, "valueSet", "purpose", "documentation", "shortDoco", "usage", "any"); + if (src.hasExtension("purpose")) { + tgt.getPurposeElement().setValueAsString(src.getExtensionByUrl("purpose").getValue().primitiveValue()); + } + if (src.hasExtension("valueSet")) { + tgt.setValueSetElement(Canonical43_50.convertCanonical((CanonicalType) src.getExtensionByUrl("valueSet").getValue())); + } + if (src.hasExtension("documentation")) { + tgt.setDocumentationElement(MarkDown43_50.convertMarkdown((MarkdownType) src.getExtensionByUrl("documentation").getValue())); + } + if (src.hasExtension("shortDoco")) { + tgt.setShortDocoElement(String43_50.convertString((StringType) src.getExtensionByUrl("shortDoco").getValue())); + } + for (Extension t : src.getExtensionsByUrl("usage")) { + tgt.addUsage(UsageContext43_50.convertUsageContext((org.hl7.fhir.r4b.model.UsageContext) t.getValue())); + } + if (src.hasExtension("any")) { + tgt.setAnyElement(Boolean43_50.convertBoolean((BooleanType) src.getExtensionByUrl("any").getValue())); + } + return tgt; + } + + private static Extension convertAdditional(ElementDefinitionBindingAdditionalComponent src) { + if (src == null) return null; + Extension tgt = new Extension(); + ConversionContext43_50.INSTANCE.getVersionConvertor_43_50().copyElement(src, tgt); + if (src.hasPurpose()) { + tgt.addExtension(new Extension("purpose", new CodeType(src.getPurposeElement().primitiveValue()))); + } + if (src.hasValueSet()) { + tgt.addExtension(new Extension("valueSet", Canonical43_50.convertCanonical(src.getValueSetElement()))); + } + if (src.hasDocumentation()) { + tgt.addExtension(new Extension("documentation", MarkDown43_50.convertMarkdown(src.getDocumentationElement()))); + } + if (src.hasShortDoco()) { + tgt.addExtension(new Extension("shortDoco", String43_50.convertString(src.getShortDocoElement()))); + } + for (UsageContext t : src.getUsage()) { + tgt.addExtension(new Extension("usage", UsageContext43_50.convertUsageContext(t))); + } + if (src.hasAny()) { + tgt.addExtension(new Extension("any", Boolean43_50.convertBoolean(src.getAnyElement()))); + } + + return tgt; + } + public static org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionMappingComponent convertElementDefinitionMappingComponent(org.hl7.fhir.r4b.model.ElementDefinition.ElementDefinitionMappingComponent src) throws FHIRException { if (src == null) return null; org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionMappingComponent tgt = new org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionMappingComponent(); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/StructureDefinitionComparer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/StructureDefinitionComparer.java index 0727512fd..3f562a249 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/StructureDefinitionComparer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/StructureDefinitionComparer.java @@ -42,6 +42,7 @@ import org.hl7.fhir.r5.renderers.utils.RenderingContext.ResourceRendererMode; import org.hl7.fhir.r5.utils.DefinitionNavigator; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.utilities.i18n.I18nConstants; import org.hl7.fhir.utilities.i18n.RenderingI18nContext; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; @@ -1289,32 +1290,32 @@ public class StructureDefinitionComparer extends CanonicalResourceComparer imple boolean ext = false; if (tail(path).equals("extension")) { if (elementIsComplex(combined)) - row.setIcon("icon_extension_complex.png", HierarchicalTableGenerator.TEXT_ICON_EXTENSION_COMPLEX); + row.setIcon("icon_extension_complex.png", utilsLeft.getContext().formatMessage(RenderingI18nContext.TEXT_ICON_EXTENSION_COMPLEX)); else - row.setIcon("icon_extension_simple.png", HierarchicalTableGenerator.TEXT_ICON_EXTENSION_SIMPLE); + row.setIcon("icon_extension_simple.png", utilsLeft.getContext().formatMessage(RenderingI18nContext.TEXT_ICON_EXTENSION_SIMPLE)); ext = true; } else if (tail(path).equals("modifierExtension")) { if (elementIsComplex(combined)) - row.setIcon("icon_modifier_extension_complex.png", HierarchicalTableGenerator.TEXT_ICON_EXTENSION_COMPLEX); + row.setIcon("icon_modifier_extension_complex.png", utilsLeft.getContext().formatMessage(RenderingI18nContext.TEXT_ICON_EXTENSION_COMPLEX)); else - row.setIcon("icon_modifier_extension_simple.png", HierarchicalTableGenerator.TEXT_ICON_EXTENSION_SIMPLE); + row.setIcon("icon_modifier_extension_simple.png", utilsLeft.getContext().formatMessage(RenderingI18nContext.TEXT_ICON_EXTENSION_SIMPLE)); } else if (hasChoice(combined)) { if (allAreReference(combined)) - row.setIcon("icon_reference.png", HierarchicalTableGenerator.TEXT_ICON_REFERENCE); + row.setIcon("icon_reference.png", utilsLeft.getContext().formatMessage(RenderingI18nContext.TEXT_ICON_REFERENCE)); else { - row.setIcon("icon_choice.gif", HierarchicalTableGenerator.TEXT_ICON_CHOICE); + row.setIcon("icon_choice.gif", utilsLeft.getContext().formatMessage(RenderingI18nContext.TEXT_ICON_CHOICE)); typesRow = row; } } else if (combined.either().getDef().hasContentReference()) - row.setIcon("icon_reuse.png", HierarchicalTableGenerator.TEXT_ICON_REUSE); + row.setIcon("icon_reuse.png", utilsLeft.getContext().formatMessage(RenderingI18nContext.TEXT_ICON_REUSE)); else if (isPrimitive(combined)) - row.setIcon("icon_primitive.png", HierarchicalTableGenerator.TEXT_ICON_PRIMITIVE); + row.setIcon("icon_primitive.png", utilsLeft.getContext().formatMessage(RenderingI18nContext.TEXT_ICON_PRIMITIVE)); else if (hasTarget(combined)) - row.setIcon("icon_reference.png", HierarchicalTableGenerator.TEXT_ICON_REFERENCE); + row.setIcon("icon_reference.png", utilsLeft.getContext().formatMessage(RenderingI18nContext.TEXT_ICON_REFERENCE)); else if (isDataType(combined)) - row.setIcon("icon_datatype.gif", HierarchicalTableGenerator.TEXT_ICON_DATATYPE); + row.setIcon("icon_datatype.gif", utilsLeft.getContext().formatMessage(RenderingI18nContext.TEXT_ICON_DATATYPE)); else - row.setIcon("icon_resource.png", HierarchicalTableGenerator.TEXT_ICON_RESOURCE); + row.setIcon("icon_resource.png", utilsLeft.getContext().formatMessage(RenderingI18nContext.TEXT_ICON_RESOURCE)); String ref = defPath == null ? null : defPath + combined.either().getDef().getId(); String sName = tail(path); String sn = getSliceName(combined); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/LanguageUtils.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/LanguageUtils.java index b8f4cd014..d900a5fba 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/LanguageUtils.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/LanguageUtils.java @@ -19,6 +19,8 @@ import org.hl7.fhir.r5.model.DataType; import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingAdditionalComponent; import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionConstraintComponent; +import org.hl7.fhir.r5.model.Extension; +import org.hl7.fhir.r5.model.MarkdownType; import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.StringType; import org.hl7.fhir.r5.model.StructureDefinition; @@ -56,8 +58,9 @@ public class LanguageUtils { private static final String ORPHAN_TRANSLATIONS_NAME = "translations.orphans"; - private static final String SUPPLEMENT_NAME = "translations.supplement"; - + private static final String SUPPLEMENT_SOURCE_RESOURCE = "translations.supplemented"; + private static final String SUPPLEMENT_SOURCE_TRANSLATIONS = "translations.source-list"; + IWorkerContext context; private List crlist; @@ -332,18 +335,63 @@ public class LanguageUtils { return dstLang == null || srcLang == null ? false : dstLang.startsWith(srcLang) || "*".equals(srcLang); } - public static void fillSupplement(CodeSystem cs, List list) { - cs.setUserData(SUPPLEMENT_NAME, "true"); + public static void fillSupplement(CodeSystem csSrc, CodeSystem csDst, List list) { + csDst.setUserData(SUPPLEMENT_SOURCE_RESOURCE, csSrc); + csDst.setUserData(SUPPLEMENT_SOURCE_TRANSLATIONS, list); for (TranslationUnit tu : list) { - ConceptDefinitionComponent cd = CodeSystemUtilities.getCode(cs, tu.getId()); - if (cd != null && cd.hasDisplay() && cd.getDisplay().equals(tu.getSrcText())) { - cd.addDesignation().setLanguage(tu.getLanguage()).setValue(tu.getTgtText()); - } else { - addOrphanTranslation(cs, tu); + String code = tu.getId(); + String subCode = null; + if (code.contains("@")) { + subCode = code.substring(code.indexOf("@")+1); + code = code.substring(0, code.indexOf("@")); } + ConceptDefinitionComponent cdSrc = CodeSystemUtilities.getCode(csSrc, tu.getId()); + if (cdSrc == null) { + addOrphanTranslation(csSrc, tu); + } else { + ConceptDefinitionComponent cdDst = CodeSystemUtilities.getCode(csDst, cdSrc.getCode()); + if (cdDst == null) { + cdDst = csDst.addConcept().setCode(cdSrc.getCode()); + } + String tt = tu.getTgtText(); + if (tt.startsWith("!!")) { + tt = tt.substring(3); + } + if (subCode == null) { + cdDst.setDisplay(tt); + } else if ("definition".equals(subCode)) { + cdDst.setDefinition(tt); + } else { + boolean found = false; + for (ConceptDefinitionDesignationComponent d : cdSrc.getDesignation()) { + if (d.hasUse() && subCode.equals(d.getUse().getCode())) { + found = true; + cdDst.addDesignation().setUse(d.getUse()).setLanguage(tu.getLanguage()).setValue(tt); //.setUserData(SUPPLEMENT_SOURCE, tu); + break; + } + } + if (!found) { + for (Extension e : cdSrc.getExtension()) { + if (subCode.equals(tail(e.getUrl()))) { + found = true; + cdDst.addExtension().setUrl(e.getUrl()).setValue( + e.getValue().fhirType().equals("markdown") ? new MarkdownType(tt) : new StringType(tt)); //.setUserData(SUPPLEMENT_SOURCE, tu); + break; + } + } + } + if (!found) { + addOrphanTranslation(csSrc, tu); + } + } + } } } + private static Object tail(String url) { + return url.contains("/") ? url.substring(url.lastIndexOf("/")+1) : url; + } + private static void addOrphanTranslation(CodeSystem cs, TranslationUnit tu) { List list = (List) cs.getUserData(ORPHAN_TRANSLATIONS_NAME); if (list == null) { @@ -376,7 +424,7 @@ public class LanguageUtils { } public static boolean handlesAsResource(Resource resource) { - return (resource instanceof CodeSystem && resource.hasUserData(SUPPLEMENT_NAME)) || (resource instanceof StructureDefinition); + return (resource instanceof CodeSystem && resource.hasUserData(SUPPLEMENT_SOURCE_RESOURCE)) || (resource instanceof StructureDefinition); } public static boolean handlesAsElement(Element element) { @@ -388,10 +436,23 @@ public class LanguageUtils { if (res instanceof StructureDefinition) { StructureDefinition sd = (StructureDefinition) res; generateTranslations(list, sd, lang); + if (res.hasUserData(ORPHAN_TRANSLATIONS_NAME)) { + List orphans = (List) res.getUserData(ORPHAN_TRANSLATIONS_NAME); + for (TranslationUnit t : orphans) { + list.add(new TranslationUnit(lang, "!!"+t.getId(), t.getContext1(), t.getSrcText(), t.getTgtText())); + } + } } else { - CodeSystem cs = (CodeSystem) res; + CodeSystem cs = (CodeSystem) res.getUserData(SUPPLEMENT_SOURCE_RESOURCE); + List inputs = res.hasUserData(SUPPLEMENT_SOURCE_TRANSLATIONS) ? (List) res.getUserData(SUPPLEMENT_SOURCE_TRANSLATIONS) : new ArrayList<>(); for (ConceptDefinitionComponent cd : cs.getConcept()) { - generateTranslations(list, cd, lang); + generateTranslations(list, cd, lang, inputs); + } + if (cs.hasUserData(ORPHAN_TRANSLATIONS_NAME)) { + List orphans = (List) cs.getUserData(ORPHAN_TRANSLATIONS_NAME); + for (TranslationUnit t : orphans) { + list.add(new TranslationUnit(lang, "!!"+t.getId(), t.getContext1(), t.getSrcText(), t.getTgtText())); + } } } return list; @@ -434,26 +495,41 @@ public class LanguageUtils { } - private static void generateTranslations(List list, ConceptDefinitionComponent cd, String lang) { - String code = cd.getCode(); - String display = cd.getDisplay(); - String target = null; - for (ConceptDefinitionDesignationComponent d : cd.getDesignation()) { - if (target == null && !d.hasUse() && d.hasLanguage() && lang.equals(d.getLanguage())) { - target = d.getValue(); - } + private static void generateTranslations(List list, ConceptDefinitionComponent cd, String lang, List inputs) { + // we generate translation units for the display, the definition, and any designations and extensions that we find + // the id of the designation is the use.code (there will be a use) and for the extension, the tail of the extension URL + // todo: do we need to worry about name clashes? why would we, and more importantly, how would we solve that? + + addTranslationUnit(list, cd.getCode(), cd.getDisplay(), lang, inputs); + if (cd.hasDefinition()) { + addTranslationUnit(list, cd.getCode()+"@definition", cd.getDefinition(), lang, inputs); } for (ConceptDefinitionDesignationComponent d : cd.getDesignation()) { - if (target == null && d.hasLanguage() && lang.equals(d.getLanguage())) { - target = d.getValue(); - } + addTranslationUnit(list, cd.getCode()+"@"+d.getUse().getCode(), d.getValue(), lang, inputs); } - list.add(new TranslationUnit(lang, code, getDefinition(cd), display, target)); - for (ConceptDefinitionComponent cd1 : cd.getConcept()) { - generateTranslations(list, cd1, lang); + for (Extension e : cd.getExtension()) { + addTranslationUnit(list, cd.getCode()+"@"+tail(e.getUrl()), e.getValue().primitiveValue(), lang, inputs); } } + private static void addTranslationUnit(List list, String id, String srcText, String lang, List inputs) { + TranslationUnit existing = null; + for (TranslationUnit t : inputs) { + if (id.equals(t.getId())) { + existing = t; + break; + } + } + // not sure what to do with context? + if (existing == null) { + list.add(new TranslationUnit(lang, id, null, srcText, null)); + } else if (srcText.equals(existing.getSrcText())) { + list.add(new TranslationUnit(lang, id, null, srcText, existing.getTgtText())); + } else { + list.add(new TranslationUnit(lang, id, null, srcText, "!!"+existing.getTgtText()).setOriginal(existing.getSrcText())); + } + } + private static String getDefinition(ConceptDefinitionComponent cd) { ConceptPropertyComponent v = CodeSystemUtilities.getProperty(cd, "translation-context"); if (v != null && v.hasValue()) { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Parameters.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Parameters.java index 778594762..8ad954266 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Parameters.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Parameters.java @@ -1527,6 +1527,16 @@ public String toString() { return null; } + + public boolean hasPart(String name) { + for (ParametersParameterComponent t : getPart()) { + if (name.equals(t.getName())) { + return true; + } + } + return false; + } + // end addition } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/AdditionalBindingsRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/AdditionalBindingsRenderer.java index a2ac7a1c5..bbc768ade 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/AdditionalBindingsRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/AdditionalBindingsRenderer.java @@ -296,8 +296,8 @@ public class AdditionalBindingsRenderer { } } if (any) { - String newRepeat = binding.any ? /*!#*/"Any repeats" : /*!#*/"All repeats"; - String oldRepeat = binding.compare!=null && binding.compare.any ? /*!#*/"Any repeats" : /*!#*/"All repeats"; + String newRepeat = binding.any ? context.formatMessage(RenderingContext.ADD_BIND_ANY_REP) : context.formatMessage(RenderingContext.ADD_BIND_ALL_REP); + String oldRepeat = binding.compare!=null && binding.compare.any ? context.formatMessage(RenderingContext.ADD_BIND_ANY_REP) : context.formatMessage(RenderingContext.ADD_BIND_ALL_REP); compareString(tr.td().style("font-size: 11px"), newRepeat, oldRepeat); } if (doco) { @@ -360,7 +360,7 @@ public class AdditionalBindingsRenderer { if (r5) { td.ah(r5 ? corePath+"valueset-additional-binding-purpose.html#additional-binding-purpose-preferred" : corePath+"terminologies.html#strength", context.formatMessage(RenderingContext.ADD_BIND_RECOM_VALUE_SET)).tx(context.formatMessage(RenderingContext.ADD_BIND_PREF_BIND)); } else { - td.span(null, context.formatMessage(RenderingContext.ADD_BIND_RECOM_VALUE_SET)).tx(context.formatMessage(RenderingContext.ADD_BIND_RECOMMENDED)); + td.span(null, context.formatMessage(RenderingContext.ADD_BIND_RECOM_VALUE_SET)).tx(context.formatMessage(RenderingContext.ADD_BIND_PREFERRED)); } break; case "ui" : diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/BinaryRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/BinaryRenderer.java index 9273d3c84..3fb22f19e 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/BinaryRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/BinaryRenderer.java @@ -71,7 +71,7 @@ public class BinaryRenderer { public void render(XhtmlNode x, String id, String ct, byte[] cnt) throws IOException { filenames.clear(); if (ct == null) { - error(x, /*!#*/"No Content Type"); + error(x,"No Content Type"); } else if (ct.startsWith("image/")) { image(x, id, ct, cnt); } else if (isXml(ct)) { @@ -83,7 +83,7 @@ public class BinaryRenderer { } else if (isText(ct)) { text(x, cnt); } else { - error(x, /*!#*/"The Content Type '"+ct+"' is not rendered in this context"); + error(x, "The Content Type '"+ct+"' is not rendered in this context"); } } @@ -101,7 +101,7 @@ public class BinaryRenderer { } if (ext == null) { - error(x, /*!#*/"The Image Type '"+ct+"' is not rendered in this context"); + error(x, "The Image Type '"+ct+"' is not rendered in this context"); } else { String fn = "Binary-Native-"+id+ext; TextFile.bytesToFile(cnt, Utilities.path(folder, fn)); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java index 91b8e5a72..3264b8334 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/CodeSystemRenderer.java @@ -506,7 +506,7 @@ public class CodeSystemRenderer extends TerminologyRenderer { hasExtensions = true; if (ToolingExtensions.hasExtension(c, ToolingExtensions.EXT_REPLACED_BY)) { Coding cc = (Coding) ToolingExtensions.getExtension(c, ToolingExtensions.EXT_REPLACED_BY).getValue(); - td.tx(" "+/*!#*/"(replaced by "); + td.tx(" "+ context.formatMessage(RenderingContext.CODE_SYS_REPLACED_BY) + " "); String url = getCodingReference(cc, system); if (url != null) { td.ah(url).addText(cc.getCode()); @@ -636,9 +636,9 @@ public class CodeSystemRenderer extends TerminologyRenderer { } if (context.isCopyButton()) { td = tr.td(); - clipboard(td, "icon_clipboard_x.png", /*!#*/"XML", "\n"+(cs.getVersionNeeded() ? "\n" : "")+"\n\n"); + clipboard(td, "icon_clipboard_x.png", "XML", "\n"+(cs.getVersionNeeded() ? "\n" : "")+"\n\n"); td.nbsp(); - clipboard(td, "icon_clipboard_j.png", /*!#*/"JSON", "\"system\" : \""+Utilities.escapeXml(cs.getUrl())+"\",\n"+(cs.getVersionNeeded() ? "\"version\" : \""+Utilities.escapeXml(cs.getVersion())+"\",\n" : "")+"\"code\" : \""+Utilities.escapeXml(c.getCode())+"\",\n\"display\" : \""+Utilities.escapeXml(c.getDisplay())+"\"\n"); + clipboard(td, "icon_clipboard_j.png", "JSON", "\"system\" : \""+Utilities.escapeXml(cs.getUrl())+"\",\n"+(cs.getVersionNeeded() ? "\"version\" : \""+Utilities.escapeXml(cs.getVersion())+"\",\n" : "")+"\"code\" : \""+Utilities.escapeXml(c.getCode())+"\",\n\"display\" : \""+Utilities.escapeXml(c.getDisplay())+"\"\n"); } return hasExtensions; } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ConceptMapRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ConceptMapRenderer.java index 010f4262b..5b304246e 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ConceptMapRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ConceptMapRenderer.java @@ -783,7 +783,7 @@ public class ConceptMapRenderer extends TerminologyRenderer { private static void renderLinks(XhtmlNode td, List collateral) { if (collateral.size() > 0) { - td.tx(/*!#*/"Links:"); + td.tx( "Links:"); td.tx(" "); boolean first = true; for (CollateralDefinition c : collateral) { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java index bdddf9b10..31965a709 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java @@ -219,20 +219,20 @@ public class DataRenderer extends Renderer implements CodeResolver { // -- 3. General Purpose Terminology Support ----------------------------------------- - private static String month(String m) { + private static String snMonth(String m) { switch (m) { - case "1" : return /*!#*/"Jan"; - case "2" : return /*!#*/"Feb"; - case "3" : return /*!#*/"Mar"; - case "4" : return/*!#*/ "Apr"; - case "5" : return /*!#*/"May"; - case "6" : return /*!#*/"Jun"; - case "7" : return /*!#*/"Jul"; - case "8" : return /*!#*/"Aug"; - case "9" : return /*!#*/"Sep"; - case "10" : return /*!#*/"Oct"; - case "11" : return /*!#*/"Nov"; - case "12" : return /*!#*/"Dec"; + case "1" : return "Jan"; + case "2" : return "Feb"; + case "3" : return "Mar"; + case "4" : return "Apr"; + case "5" : return "May"; + case "6" : return "Jun"; + case "7" : return "Jul"; + case "8" : return "Aug"; + case "9" : return "Sep"; + case "10" : return "Oct"; + case "11" : return "Nov"; + case "12" : return "Dec"; default: return null; } } @@ -247,21 +247,21 @@ public class DataRenderer extends Renderer implements CodeResolver { ed = p[p.length-3]; String y = p[p.length-3].substring(4, 8); String m = p[p.length-3].substring(2, 4); - dt = " rel. "+month(m)+" "+y; + dt = " rel. "+snMonth(m)+" "+y; } else { ed = p[p.length-1]; } switch (ed) { - case "900000000000207008": return /*!#*/"Intl"+dt; - case "731000124108": return /*!#*/"US"+dt; - case "32506021000036107": return /*!#*/"AU"+dt; - case "449081005": return /*!#*/"ES"+dt; - case "554471000005108": return /*!#*/"DK"+dt; - case "11000146104": return /*!#*/"NL"+dt; - case "45991000052106": return /*!#*/"SE"+dt; - case "999000041000000102": return /*!#*/"UK"+dt; - case "20611000087101": return /*!#*/"CA"+dt; - case "11000172109": return /*!#*/"BE"+dt; + case "900000000000207008": return "Intl"+dt; + case "731000124108": return "US"+dt; + case "32506021000036107": return "AU"+dt; + case "449081005": return "ES"+dt; + case "554471000005108": return "DK"+dt; + case "11000146104": return "NL"+dt; + case "45991000052106": return "SE"+dt; + case "999000041000000102": return "UK"+dt; + case "20611000087101": return "CA"+dt; + case "11000172109": return "BE"+dt; default: return "??"+dt; } } else { @@ -269,25 +269,6 @@ public class DataRenderer extends Renderer implements CodeResolver { } } -// public static String describeSystem(String system) { -// if (system == null) -// return /*!#*/ "[not stated]"; -// if (system.equals("http://loinc.org")) -// return /*!#*/ "LOINC"; -// if (system.startsWith("http://snomed.info")) -// return /*!#*/ "SNOMED CT"; -// if (system.equals("http://www.nlm.nih.gov/research/umls/rxnorm")) -// return /*!#*/ "RxNorm"; -// if (system.equals("http://hl7.org/fhir/sid/icd-9")) -// return /*!#*/ "ICD-9"; -// if (system.equals("http://dicom.nema.org/resources/ontology/DCM")) -// return /*!#*/ "DICOM"; -// if (system.equals("http://unitsofmeasure.org")) -// return /*!#*/ "UCUM"; -// -// return system; -// } - public String displaySystem(String system) { if (system == null) return (context.formatMessage(RenderingContext.DATA_REND_NOT_STAT)); @@ -357,7 +338,7 @@ public class DataRenderer extends Renderer implements CodeResolver { protected String describeLang(String lang) { // special cases: if ("fr-CA".equals(lang)) { - return /*!#*/"French (Canadian)"; // this one was omitted from the value set + return "French (Canadian)"; // this one was omitted from the value set } ValueSet v = getContext().getWorker().findTxResource(ValueSet.class, "http://hl7.org/fhir/ValueSet/languages"); if (v != null) { @@ -703,7 +684,7 @@ public class DataRenderer extends Renderer implements CodeResolver { if (base instanceof DataType) { render(x, (DataType) base); } else { - x.tx(/*!#*/"to do: "+base.fhirType()); + x.tx(context.formatMessage(RenderingContext.DATA_REND_TO_DO, base.fhirType())); } } @@ -763,7 +744,7 @@ public class DataRenderer extends Renderer implements CodeResolver { addMarkdown(x, context.getTranslated((MarkdownType) type)); } else if (type instanceof Base64BinaryType) { Base64BinaryType b64 = (Base64BinaryType) type; - x.tx(/*!#*/"(base64 data - "+(b64.getValue() == null ? "0" : b64.getValue().length)+" bytes)"); + x.tx(context.formatMessage(RenderingContext.DATA_REND_BASE64, (b64.getValue() == null ? "0" : b64.getValue().length))); } else if (type.isPrimitive()) { x.tx(context.getTranslated((PrimitiveType) type)); } else { @@ -1057,7 +1038,7 @@ public class DataRenderer extends Renderer implements CodeResolver { systemName = cs != null ? crPresent(cs) : displaySystem(c.getSystem()); link = getLinkForCode(c.getSystem(), c.getVersion(), c.getCode()); - hint = systemName+": "+display+(c.hasVersion() ? " "+/*!#*/"(version = "+c.getVersion()+")" : ""); + hint = systemName+": "+display+(c.hasVersion() ? " "+ context.formatMessage(RenderingContext.DATA_REND_VERSION, c.getVersion(), ")") : ""); return new CodeResolution(systemName, systemLink, link, display, hint); } @@ -1092,7 +1073,7 @@ public class DataRenderer extends Renderer implements CodeResolver { x.tx(s); } if (c.hasVersion()) { - x.tx(" "+/*!#*/"(version = "+c.getVersion()+")"); + x.tx(" "+context.formatMessage(RenderingContext.DATA_REND_VERSION, c.getVersion(), ")")); } } @@ -1107,7 +1088,7 @@ public class DataRenderer extends Renderer implements CodeResolver { s = c.getCode(); if (showCodeDetails) { - x.addText(s+" "+/*!#*/"(Details: "+displaySystem(c.getSystem())+" code "+c.getCode()+" = '"+lookupCode(c.getSystem(), c.getVersion(), c.getCode())+"', stated as '"+c.getDisplay()+"')"); + x.addText(s+" "+context.formatMessage(RenderingContext.DATA_REND_DETAILS_STATED, displaySystem(c.getSystem()), c.getCode(), " = '", lookupCode(c.getSystem(), c.getVersion(), c.getCode()), c.getDisplay(), "')")); } else x.span(null, "{"+c.getSystem()+" "+c.getCode()+"}").addText(s); } @@ -1227,7 +1208,7 @@ public class DataRenderer extends Renderer implements CodeResolver { } } - x.span(null, /*!#*/"Codes: "+b.toString()).addText(s); + x.span(null, context.formatMessage(RenderingContext.DATA_REND_CODES) +b.toString()).addText(s); } } @@ -1291,7 +1272,7 @@ public class DataRenderer extends Renderer implements CodeResolver { } else { switch (ii.getSystem()) { case "urn:oid:2.51.1.3": - x.ah("https://www.gs1.org/standards/id-keys/gln", /*!#*/"Global Location Number").tx("GLN"); + x.ah("https://www.gs1.org/standards/id-keys/gln", context.formatMessage(RenderingContext.DATA_REND_GLN)).tx("GLN"); break; default: x.code(ii.getSystem()); @@ -1557,8 +1538,8 @@ public class DataRenderer extends Renderer implements CodeResolver { if (system == null) return ""; switch (system) { - case PHONE: return /*!#*/"ph: "; - case FAX: return /*!#*/"fax: "; + case PHONE: return "ph: "; + case FAX: return "fax: "; default: return ""; } @@ -1596,7 +1577,7 @@ public class DataRenderer extends Renderer implements CodeResolver { x.tx("(unit "+q.getCode()+" from "+q.getSystem()+")"); } if (showCodeDetails && q.hasCode()) { - x.span("background: LightGoldenRodYellow", null).tx(" "+/*!#*/"(Details: "+displaySystem(q.getSystem())+" code "+q.getCode()+" = '"+lookupCode(q.getSystem(), null, q.getCode())+"')"); + x.span("background: LightGoldenRodYellow", null).tx(" "+ (context.formatMessage(RenderingContext.DATA_REND_DETAILS, displaySystem(q.getSystem()))) +q.getCode()+" = '"+lookupCode(q.getSystem(), null, q.getCode())+"')"); } } @@ -1640,13 +1621,13 @@ public class DataRenderer extends Renderer implements CodeResolver { public String displayPeriod(Period p) { String s = !p.hasStart() ? "(?)" : displayDateTime(p.getStartElement()); s = s + " --> "; - return s + (!p.hasEnd() ? /*!#*/"(ongoing)" : displayDateTime(p.getEndElement())); + return s + (!p.hasEnd() ? context.formatMessage(RenderingContext.DATA_REND_ONGOING) : displayDateTime(p.getEndElement())); } public void renderPeriod(XhtmlNode x, Period p) { x.addText(!p.hasStart() ? "??" : displayDateTime(p.getStartElement())); x.tx(" --> "); - x.addText(!p.hasEnd() ? /*!#*/"(ongoing)" : displayDateTime(p.getEndElement())); + x.addText(!p.hasEnd() ? context.formatMessage(RenderingContext.DATA_REND_ONGOING) : displayDateTime(p.getEndElement())); } public void renderUsageContext(XhtmlNode x, UsageContext u) throws FHIRFormatError, DefinitionException, IOException { @@ -1856,7 +1837,7 @@ public class DataRenderer extends Renderer implements CodeResolver { st = st + "-"+Integer.toString(rep.getFrequency()); } if (rep.hasPeriod()) { - st = st + " "+/*!#*/"per "+rep.getPeriod().toPlainString(); + st = st + " "+ (context.formatMessage(RenderingContext.DATA_REND_PER))+rep.getPeriod().toPlainString(); if (rep.hasPeriodMax()) st = st + "-"+rep.getPeriodMax().toPlainString(); st = st + " "+displayTimeUnits(rep.getPeriodUnit()); @@ -1961,7 +1942,7 @@ public class DataRenderer extends Renderer implements CodeResolver { XhtmlNode xn; xn = new XhtmlNode(NodeType.Element, "div"); XhtmlNode p = xn.para(); - p.b().tx(/*!#*/"Exception "+function+": "+e.getMessage()); + p.b().tx((context.formatMessage(RenderingContext.DATA_REND_EXCEPTION)) +function+": "+e.getMessage()); p.addComment(getStackTrace(e)); return xn; } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DiagnosticReportRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DiagnosticReportRenderer.java index 2b19ad073..b95c46e77 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DiagnosticReportRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DiagnosticReportRenderer.java @@ -85,7 +85,7 @@ public class DiagnosticReportRenderer extends ResourceRenderer { pw = getProperty(dr, "perfomer"); if (valued(pw)) { tr = tbl.tr(); - tr.td().tx(Utilities.pluralize(/*!#*/ "Performer", pw.getValues().size())); + tr.td().tx(Utilities.pluralize((context.formatMessage(RenderingContext.DIAG_REP_REND_PER)), pw.getValues().size())); XhtmlNode tdr = tr.td(); for (BaseWrapper v : pw.getValues()) { tdr.tx(" "); @@ -95,7 +95,7 @@ public class DiagnosticReportRenderer extends ResourceRenderer { pw = getProperty(dr, "identifier"); if (valued(pw)) { tr = tbl.tr(); - tr.td().tx(Utilities.pluralize(/*!#*/"Identifier", pw.getValues().size())+":"); + tr.td().tx(Utilities.pluralize((context.formatMessage(RenderingContext.DIAG_REP_REND_IDENTIFIER)), pw.getValues().size())+":"); XhtmlNode tdr = tr.td(); for (BaseWrapper v : pw.getValues()) { tdr.tx(" "); @@ -105,7 +105,7 @@ public class DiagnosticReportRenderer extends ResourceRenderer { pw = getProperty(dr, "request"); if (valued(pw)) { tr = tbl.tr(); - tr.td().tx(Utilities.pluralize(/*!#*/"Request", pw.getValues().size())+":"); + tr.td().tx(Utilities.pluralize((context.formatMessage(RenderingContext.DIAG_REP_REND_REQUEST)), pw.getValues().size())+":"); XhtmlNode tdr = tr.td(); for (BaseWrapper v : pw.getValues()) { tdr.tx(" "); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ExampleScenarioRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ExampleScenarioRenderer.java index 7ab02111c..a4d881b8b 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ExampleScenarioRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ExampleScenarioRenderer.java @@ -119,7 +119,7 @@ public class ExampleScenarioRenderer extends TerminologyRenderer { XhtmlNode n = new XhtmlDocument(); renderCanonical(scen, n, step.getWorkflow()); XhtmlNode ref = n.getChildNodes().get(0); - plantUml += noteOver(scen.getActor(), /*!#*/"Step " + trimPrefix(prefix) + " - See scenario\n" + creolLink(ref.getContent(), ref.getAttribute("href"))); + plantUml += noteOver(scen.getActor(), context.formatMessage(RenderingContext.EXAMPLE_SCEN_STEP_SCEN, trimPrefix(prefix), creolLink((ref.getContent()), ref.getAttribute("href")))); } else if (step.hasProcess()) plantUml += toPlantUml(step.getProcess(), prefix, scen, actorKeys); else { @@ -478,7 +478,7 @@ public class ExampleScenarioRenderer extends TerminologyRenderer { } } if (theVersion==null) - throw new FHIRException(/*!#*/"Unable to find referenced version " + instanceRef.getVersionReference() + " within instance " + instanceRef.getInstanceReference()); + throw new FHIRException("Unable to find referenced version " + instanceRef.getVersionReference() + " within instance " + instanceRef.getInstanceReference()); instanceCell.ah("#i_" + instance.getKey() + "v_"+ theVersion.getKey() , theVersion.getDescription()).tx(theVersion.getTitle()); } else diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java index 25c08620a..0623bda9c 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java @@ -107,7 +107,7 @@ public class ProfileDrivenRenderer extends ResourceRenderer { boolean idDone = false; XhtmlNode p = x.para(); if (context.isAddGeneratedNarrativeHeader()) { - p.b().tx(/*!#*/"Generated Narrative: "+r.fhirType()+(context.isContained() ? " #"+r.getId() : "")); + p.b().tx(context.formatMessage(RenderingContext.PROF_DRIV_GEN_NARR, r.fhirType(), (context.isContained() ? " #"+r.getId() : ""))); if (!Utilities.noString(r.getId())) { p.an(r.getId()); p.an("hc"+r.getId()); @@ -133,7 +133,7 @@ public class ProfileDrivenRenderer extends ResourceRenderer { generateByProfile(r, sd, r.root(), sd.getSnapshot().getElement(), ed, context.getProfileUtilities().getChildList(sd, ed), x, r.fhirType(), context.isTechnicalMode(), 0); } } catch (Exception e) { - System.out.println(/*!#*/"Error Generating Narrative for "+r.fhirType()+"/"+r.getId()+": "+e.getMessage()); + System.out.println(context.formatMessage(RenderingContext.PROF_DRIV_ERR_GEN_NARR) +r.fhirType()+"/"+r.getId()+": "+e.getMessage()); e.printStackTrace(); x.para().b().style("color: maroon").tx(context.formatMessage(RenderingContext.PROF_DRIV_EXCP, e.getMessage())+" "); } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireResponseRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireResponseRenderer.java index e1c68fcba..8589632ec 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireResponseRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireResponseRenderer.java @@ -45,7 +45,7 @@ public class QuestionnaireResponseRenderer extends ResourceRenderer { // case DEFNS: return renderDefns(x, q); case TREE: return renderTree(x, q); default: - throw new Error(/*!#*/"Unknown QuestionnaireResponse Renderer Mode"); + throw new Error(context.formatMessage(RenderingContext.QUEST_UNKNOWN_MODE)); } } @@ -57,7 +57,7 @@ public class QuestionnaireResponseRenderer extends ResourceRenderer { // case DEFNS: return renderDefns(x, q); case TREE: return renderTree(x, qr); default: - throw new Error(/*!#*/"Unknown QuestionnaireResponse Renderer Mode"); + throw new Error(context.formatMessage(RenderingContext.QUEST_UNKNOWN_MODE)); } } @@ -71,10 +71,10 @@ public class QuestionnaireResponseRenderer extends ResourceRenderer { model.setDocoImg(Utilities.pathURL(context.getLink(KnownLinkType.SPEC), "help16.png")); } model.setDocoRef(context.getLink(KnownLinkType.SPEC)+"formats.html#table"); - model.getTitles().add(gen.new Title(null, model.getDocoRef(), /*!#*/"LinkId", /*!#*/"The linkId for the item", null, 0)); - model.getTitles().add(gen.new Title(null, model.getDocoRef(), /*!#*/"Text", /*!#*/"Text for the item", null, 0)); - model.getTitles().add(gen.new Title(null, model.getDocoRef(), /*!#*/"Definition", /*!#*/"Minimum and Maximum # of times the the itemcan appear in the instance", null, 0)); - model.getTitles().add(gen.new Title(null, model.getDocoRef(), /*!#*/"Answer", /*!#*/"The type of the item", null, 0)); + model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatMessage(RenderingContext.QUEST_LINKID), context.formatMessage(RenderingContext.QUEST_LINK), null, 0)); + model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatMessage(RenderingContext.QUEST_TEXT), context.formatMessage(RenderingContext.QUEST_TEXTFOR), null, 0)); + model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatMessage(RenderingContext.QUEST_DEFINITION), context.formatMessage(RenderingContext.QUEST_TIMES), null, 0)); + model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatMessage(RenderingContext.QUEST_ANSWER), context.formatMessage(RenderingContext.QUEST_TYPE_ITEM), null, 0)); boolean hasExt = false; // first we add a root for the questionaire itself @@ -98,10 +98,10 @@ public class QuestionnaireResponseRenderer extends ResourceRenderer { model.setDocoImg(Utilities.pathURL(context.getLink(KnownLinkType.SPEC), "help16.png")); } model.setDocoRef(context.getLink(KnownLinkType.SPEC)+"formats.html#table"); - model.getTitles().add(gen.new Title(null, model.getDocoRef(), /*!#*/"LinkId", /*!#*/"The linkId for the item", null, 0)); - model.getTitles().add(gen.new Title(null, model.getDocoRef(), /*!#*/"Text", /*!#*/"Text for the item", null, 0)); - model.getTitles().add(gen.new Title(null, model.getDocoRef(), /*!#*/"Definition", /*!#*/"Minimum and Maximum # of times the the itemcan appear in the instance", null, 0)); - model.getTitles().add(gen.new Title(null, model.getDocoRef(), /*!#*/"Answer", /*!#*/"The type of the item", null, 0)); + model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatMessage(RenderingContext.QUEST_LINKID), context.formatMessage(RenderingContext.QUEST_LINK), null, 0)); + model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatMessage(RenderingContext.QUEST_TEXT), context.formatMessage(RenderingContext.QUEST_TEXTFOR), null, 0)); + model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatMessage(RenderingContext.QUEST_DEFINITION), context.formatMessage(RenderingContext.QUEST_TIMES), null, 0)); + model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatMessage(RenderingContext.QUEST_ANSWER), context.formatMessage(RenderingContext.QUEST_TYPE_ITEM), null, 0)); boolean hasExt = false; // first we add a root for the questionaire itself @@ -120,10 +120,10 @@ public class QuestionnaireResponseRenderer extends ResourceRenderer { Row r = gen.new Row(); rows.add(r); - r.setIcon("icon_q_root.gif", /*!#*/"QuestionnaireResponseRoot"); + r.setIcon("icon_q_root.gif", context.formatMessage(RenderingContext.QUEST_RESP_ROOT)); r.getCells().add(gen.new Cell(null, null, q.getId(), null, null)); r.getCells().add(gen.new Cell(null, null, "", null, null)); - r.getCells().add(gen.new Cell(null, null, /*!#*/"QuestionnaireResponse", null, null)); + r.getCells().add(gen.new Cell(null, null, context.formatMessage(RenderingContext.QUEST_RESP), null, null)); r.getCells().add(gen.new Cell(null, null, "", null, null)); return r; } @@ -136,18 +136,18 @@ public class QuestionnaireResponseRenderer extends ResourceRenderer { String ref = b == null ? null : b.primitiveValue(); Questionnaire q = context.getContext().fetchResource(Questionnaire.class, ref); - r.setIcon("icon_q_root.gif", /*!#*/"QuestionnaireResponseRoot"); + r.setIcon("icon_q_root.gif", context.formatMessage(RenderingContext.QUEST_RESP_ROOT)); r.getCells().add(gen.new Cell(null, null, qr.getId(), null, null)); r.getCells().add(gen.new Cell(null, null, "", null, null)); if (ref == null ) { r.getCells().add(gen.new Cell(null, null, "", null, null)); - r.getCells().add(gen.new Cell(/*!#*/"Questionnaire:", null, /*!#*/"None specified", null, null)); + r.getCells().add(gen.new Cell(context.formatMessage(RenderingContext.QUEST_QUESTION), null, context.formatMessage(RenderingContext.QUEST_NONE_SPEC), null, null)); } else if (q == null || !q.hasWebPath()) { r.getCells().add(gen.new Cell(null, null, "", null, null)); - r.getCells().add(gen.new Cell(/*!#*/"Questionnaire:", null, ref, null, null)); + r.getCells().add(gen.new Cell(context.formatMessage(RenderingContext.QUEST_QUESTION), null, ref, null, null)); } else{ r.getCells().add(gen.new Cell(null, null, "", null, null)); - r.getCells().add(gen.new Cell(/*!#*/"Questionnaire:", q.getWebPath(), q.present(), null, null)); + r.getCells().add(gen.new Cell(context.formatMessage(RenderingContext.QUEST_QUESTION), q.getWebPath(), q.present(), null, null)); } return r; } @@ -168,9 +168,9 @@ public class QuestionnaireResponseRenderer extends ResourceRenderer { } } if (hasItem) { - r.setIcon("icon-q-group.png", /*!#*/"Group"); + r.setIcon("icon-q-group.png", context.formatMessage(RenderingContext.QUEST_GROUP)); } else { - r.setIcon("icon-q-string.png", /*!#*/"Item"); + r.setIcon("icon-q-string.png", context.formatMessage(RenderingContext.QUEST_ITEM)); } String linkId = i.has("linkId") ? i.get("linkId").primitiveValue() : "??"; String text = i.has("text") ? i.get("text").primitiveValue() : ""; @@ -235,9 +235,9 @@ public class QuestionnaireResponseRenderer extends ResourceRenderer { hasItem = a.hasItem(); } if (hasItem) { - r.setIcon("icon-q-group.png", /*!#*/"Group"); + r.setIcon("icon-q-group.png", context.formatMessage(RenderingContext.QUEST_GROUP)); } else { - r.setIcon("icon-q-string.png", /*!#*/"Item"); + r.setIcon("icon-q-string.png", context.formatMessage(RenderingContext.QUEST_ITEM)); } r.getCells().add(gen.new Cell(null, context.getDefinitionsTarget() == null ? "" : context.getDefinitionsTarget()+"#item."+i.getLinkId(), i.getLinkId(), null, null)); r.getCells().add(gen.new Cell(null, null, i.getText(), null, null)); @@ -327,7 +327,7 @@ public class QuestionnaireResponseRenderer extends ResourceRenderer { public boolean renderForm(XhtmlNode x, ResourceWrapper q) throws UnsupportedEncodingException, IOException { boolean hasExt = false; XhtmlNode d = x.div(); - d.tx(/*!#*/"todo"); + d.tx(context.formatMessage(RenderingContext.QUEST_TODO)); // boolean hasPrefix = false; // for (QuestionnaireItemComponent c : q.getItem()) { // hasPrefix = hasPrefix || doesItemHavePrefix(c); @@ -370,7 +370,7 @@ public class QuestionnaireResponseRenderer extends ResourceRenderer { // } // p.span(null, "linkId: "+i.getLinkId()).tx(i.getText()); // if (i.getRequired()) { -// p.span("color: red", /*!#*/"Mandatory").tx("*"); +// p.span("color: red", context.formatMessage(RenderingContext.QUEST_MAND)).tx("*"); // } // // XhtmlNode input = null; @@ -605,16 +605,16 @@ public class QuestionnaireResponseRenderer extends ResourceRenderer { // } // private boolean renderLinks(XhtmlNode x, QuestionnaireResponse q) { - x.para().tx(/*!#*/"Try this QuestionnaireResponse out:"); + x.para().tx(context.formatMessage(RenderingContext.QUEST_TRY_QUEST)); XhtmlNode ul = x.ul(); - ul.li().ah("http://todo.nlm.gov/path?mode=ig&src="+Utilities.pathURL(context.getLink(KnownLinkType.SELF), "package.tgz")+"&q="+q.getId()+".json").tx(/*!#*/"NLM Forms Library"); + ul.li().ah("http://todo.nlm.gov/path?mode=ig&src="+Utilities.pathURL(context.getLink(KnownLinkType.SELF), "package.tgz")+"&q="+q.getId()+".json").tx(context.formatMessage(RenderingContext.QUEST_NLM)); return false; } private boolean renderLinks(XhtmlNode x, ResourceWrapper q) { - x.para().tx(/*!#*/"Try this QuestionnaireResponse out:"); + x.para().tx(context.formatMessage(RenderingContext.QUEST_TRY_QUEST)); XhtmlNode ul = x.ul(); - ul.li().ah("http://todo.nlm.gov/path?mode=ig&src="+Utilities.pathURL(context.getLink(KnownLinkType.SELF), "package.tgz")+"&q="+q.getId()+".json").tx(/*!#*/"NLM Forms Library"); + ul.li().ah("http://todo.nlm.gov/path?mode=ig&src="+Utilities.pathURL(context.getLink(KnownLinkType.SELF), "package.tgz")+"&q="+q.getId()+".json").tx(context.formatMessage(RenderingContext.QUEST_NLM)); return false; } @@ -711,13 +711,13 @@ public class QuestionnaireResponseRenderer extends ResourceRenderer { // } // if (qi.hasAnswerOption()) { // XhtmlNode tr = tbl.tr(); -// tr.td().tx(/*!#*/"Allowed Answers"); +// tr.td().tx(context.formatMessage(RenderingContext.QUEST_ALLOWED)); // XhtmlNode ul = tr.td().ul(); // for (QuestionnaireItemAnswerOptionComponent ans : qi.getAnswerOption()) { // XhtmlNode li = ul.li(); // render(li, ans.getValue()); // if (ans.getInitialSelected()) { -// li.tx(/*!#*/" (initially selected)"); +// li.tx(context.formatMessage(RenderingContext.QUEST_INITIALLY)); // } // } // } @@ -738,7 +738,7 @@ public class QuestionnaireResponseRenderer extends ResourceRenderer { // // appearance // if (qi.hasExtension(" http://hl7.org/fhir/StructureDefinition/QuestionnaireResponse-displayCategory")) { // XhtmlNode tr = tbl.tr(); -// tr.td().ah("http://hl7.org/fhir/StructureDefinition/QuestionnaireResponse-displayCategory").tx(/*!#*/"Display Category"); +// tr.td().ah("http://hl7.org/fhir/StructureDefinition/QuestionnaireResponse-displayCategory").tx(context.formatMessage(RenderingContext.QUEST_DISPLAY_CAT)); // render(tr.td(), qi.getExtensionByUrl("http://hl7.org/fhir/StructureDefinition/QuestionnaireResponse-displayCategory").getValue()); // } // if (ToolingExtensions.readBoolExtension(qi, "http://hl7.org/fhir/StructureDefinition/QuestionnaireResponse-hidden")) { @@ -763,14 +763,14 @@ public class QuestionnaireResponseRenderer extends ResourceRenderer { // } // if (qi.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-observationLinkPeriod")) { // XhtmlNode tr = tbl.tr(); -// tr.td().ah(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-observationLinkPeriod").tx(/*!#*/"Observation Link Period"); +// tr.td().ah(getSDCLink("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-observationLinkPeriod").tx(context.formatMessage(RenderingContext.QUEST_OBSERVATION)); // render(tr.td(), qi.getExtensionByUrl("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-QuestionnaireResponse-observationLinkPeriod").getValue()); // } // // // dynamic management // if (qi.hasEnableWhen()) { // XhtmlNode tr = tbl.tr(); -// tr.td().tx(/*!#*/"Enable When"); +// tr.td().tx(context.formatMessage(RenderingContext.QUEST_ENABLE)); // td = tr.td(); // if (qi.getEnableWhen().size() == 1) { // renderEnableWhen(td, qi.getEnableWhen().get(0)); @@ -876,12 +876,12 @@ public class QuestionnaireResponseRenderer extends ResourceRenderer { @Override public String display(Resource r) throws UnsupportedEncodingException, IOException { - return /*!#*/"todo"; + return context.formatMessage(RenderingContext.QUEST_TODO); } @Override public String display(ResourceWrapper r) throws UnsupportedEncodingException, IOException { - return /*!#*/"Not done yet"; + return context.formatMessage(RenderingContext.QUEST_NOT_DONE); } } \ No newline at end of file diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/Renderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/Renderer.java index f5fbf8b0e..19ff12b9c 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/Renderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/Renderer.java @@ -142,25 +142,25 @@ public class Renderer { XhtmlNode td = tr.td(); XhtmlNode span = td.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", (context.formatMessage(RenderingContext.REND_ROW_SINCE, context.getChangeVersion()))); span.img("icon-change-add.png", "icon"); - span.tx(" "+/*!#*/"Added:"); + span.tx(" "+ context.formatMessage(RenderingContext.REND_ADDED)); XhtmlNode x = new XhtmlNode(NodeType.Element, "holder"); - x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", /*!#*/"This row of content has been added since "+context.getChangeVersion()).tx(" "); + x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", context.formatMessage(RenderingContext.REND_ROW_SINCE, context.getChangeVersion())).tx(" "); tr.styleCells(x); return td; case Changed: td = tr.td(); - span = td.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", /*!#*/"This row of content has been changed since"+context.getChangeVersion()+(vca.getOriginal() != null ? " (was '"+vca.getOriginal()+"')" : "")); + span = td.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", context.formatMessage(RenderingContext.REND_ROW_CHANGED_SINCE_WAS, context.getChangeVersion(), vca.getOriginal())); span.img("icon-change-edit.png", "icon"); - span.tx(" "+/*!#*/"Changed:"); + span.tx(" "+ context.formatMessage(RenderingContext.REND_CHANGED)); return td; case Deleted: tr.style("text-decoration: line-through"); td = tr.td(); - span = td.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", /*!#*/"This content has been removed since "+context.getChangeVersion()); + span = td.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", context.formatMessage(RenderingContext.REND_ROW_REMOVED_SINCE, context.getChangeVersion())); span.img("icon-change-remove.png", "icon"); - span.tx(" "+/*!#*/"Removed:"); + span.tx(" "+ context.formatMessage(RenderingContext.REND_REMOVED)); x = new XhtmlNode(NodeType.Element, "holder"); - x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px; text-decoration: none", /*!#*/"This row of content has been added since "+context.getChangeVersion()).tx(" "); + x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px; text-decoration: none", context.formatMessage(RenderingContext.REND_ROW_SINCE, context.getChangeVersion())).tx(" "); tr.styleCells(x); return td; default: @@ -168,29 +168,30 @@ public class Renderer { } } - public static void renderStatusSummary(Base base, XhtmlNode x, String version, String... metadataFields) { + public static void renderStatusSummary(RenderingContext context, Base base, XhtmlNode x, String version, String... metadataFields) { if (base.hasUserData(VersionComparisonAnnotation.USER_DATA_NAME)) { VersionComparisonAnnotation self = (VersionComparisonAnnotation) base.getUserData(VersionComparisonAnnotation.USER_DATA_NAME); switch (self.getType()) { case Added: - XhtmlNode spanInner = x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", /*!#*/"This content has been added since "+version); + XhtmlNode spanInner = x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", context.formatMessage(RenderingContext.REND_SINCE_ADDED, version)); spanInner.img("icon-change-add.png", "icon"); - spanInner.tx(" "+/*!#*/"Added"); + spanInner.tx(" "+context.formatMessage(RenderingContext.REND_ADDED)); return; case Changed: if (self.getComp().noChangeOtherThanMetadata(metadataFields)) { x.span("color: #eeeeee").tx("n/c"); return; } else { - spanInner = x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", /*!#*/"This content has been changed since "+version+(self.getOriginal() != null ? " (was '"+(self.getOriginal())+"')" : "")); + spanInner = x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", + self.getOriginal() != null ? context.formatMessage(RenderingContext.REND_SINCE_CHANGED_WAS, version, self.getOriginal()) : context.formatMessage(RenderingContext.REND_SINCE_CHANGED, version)); spanInner.img("icon-change-edit.png", "icon"); - spanInner.tx(" "+/*!#*/"Changed"); + spanInner.tx(" "+context.formatMessage(RenderingContext.REND_CHANGED)); } return; case Deleted: - spanInner = x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", /*!#*/"This content has been added since "+version); + spanInner = x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", context.formatMessage(RenderingContext.REND_SINCE_DELETED, version)); spanInner.img("icon-change-remove.png", "icon"); - spanInner.tx(" "+/*!#*/"Removed"); + spanInner.tx(" "+context.formatMessage(RenderingContext.REND_REMOVED)); return; default: x.span("color: #eeeeee").tx("n/c"); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ResourceRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ResourceRenderer.java index f55c11a8c..e7c675c59 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ResourceRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ResourceRenderer.java @@ -232,11 +232,11 @@ public abstract class ResourceRenderer extends DataRenderer { CanonicalResource cr = (CanonicalResource) target; if (url.contains("|")) { if (target.hasWebPath()) { - x.ah(target.getWebPath()).tx(cr.present()+/*!#*/" (version "+cr.getVersion()+")"); + x.ah(target.getWebPath()).tx(cr.present()+ context.formatMessage(RenderingContext.RES_REND_VER) +cr.getVersion()+")"); } else { url = url.substring(0, url.indexOf("|")); x.code().tx(url); - x.tx(": "+cr.present()+/*!#*/" (version "+cr.getVersion()+")"); + x.tx(": "+cr.present()+ context.formatMessage(RenderingContext.RES_REND_VER) +cr.getVersion()+")"); } } else { if (target.hasWebPath()) { @@ -663,28 +663,28 @@ public abstract class ResourceRenderer extends DataRenderer { p.tx("\""+id+"\" "); } if (versionId != null) { - p.tx(/*!#*/"Version \""+versionId+"\" "); + p.tx(context.formatMessage(RenderingContext.RES_REND_VERSION) + "\""+versionId+"\" "); } if (lastUpdated != null) { - p.tx(/*!#*/"Updated \""); + p.tx(context.formatMessage(RenderingContext.RES_REND_UPDATED) + "\""); renderDateTime(p, lastUpdated); p.tx("\" "); } if (lang != null) { - p.tx(/*!#*/" (Language \""+lang+"\") "); + p.tx(" " + context.formatMessage(RenderingContext.RES_REND_LANGUAGE) + "\""+lang+"\") "); } } if (ir != null) { - plateStyle(div.para()).b().tx(/*!#*/"Special rules apply: "+ir+"!"); + plateStyle(div.para()).b().tx(context.formatMessage(RenderingContext.RES_REND_SPEC_RULES) + " "+ir+"!"); } if (source != null) { - plateStyle(div.para()).tx(/*!#*/"Information Source: "+source+"!"); + plateStyle(div.para()).tx(context.formatMessage(RenderingContext.RES_REND_INFO_SOURCE) + " "+source+"!"); } if (meta != null) { PropertyWrapper pl = meta.getChildByName("profile"); if (pl.hasValues()) { XhtmlNode p = plateStyle(div.para()); - p.tx(Utilities.pluralize(/*!#*/"Profile", pl.getValues().size())+": "); + p.tx(Utilities.pluralize(context.formatMessage(RenderingContext.RES_REND_PROFILE), pl.getValues().size())+": "); boolean first = true; for (BaseWrapper bw : pl.getValues()) { if (first) first = false; else p.tx(", "); @@ -694,7 +694,7 @@ public abstract class ResourceRenderer extends DataRenderer { PropertyWrapper tl = meta.getChildByName("tag"); if (tl.hasValues()) { XhtmlNode p = plateStyle(div.para()); - p.tx(Utilities.pluralize(/*!#*/"Tag", tl.getValues().size())+": "); + p.tx(Utilities.pluralize(context.formatMessage(RenderingContext.RES_REND_TAG), tl.getValues().size())+": "); boolean first = true; for (BaseWrapper bw : tl.getValues()) { if (first) first = false; else p.tx(", "); @@ -708,7 +708,7 @@ public abstract class ResourceRenderer extends DataRenderer { PropertyWrapper sl = meta.getChildByName("security"); if (sl.hasValues()) { XhtmlNode p = plateStyle(div.para()); - p.tx(Utilities.pluralize(/*!#*/"Security Label", tl.getValues().size())+": "); + p.tx(Utilities.pluralize(context.formatMessage(RenderingContext.RES_REND_SECURITY_LABEL), tl.getValues().size())+": "); boolean first = true; for (BaseWrapper bw : sl.getValues()) { if (first) first = false; else p.tx(", "); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/SearchParameterRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/SearchParameterRenderer.java index acb40586f..acfeb563f 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/SearchParameterRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/SearchParameterRenderer.java @@ -55,7 +55,7 @@ public class SearchParameterRenderer extends TerminologyRenderer { XhtmlNode tbl = x.table("grid"); XhtmlNode tr = tbl.tr(); - tr.td().tx(Utilities.pluralize(/*!#*/"Resource", spd.getBase().size())); + tr.td().tx(Utilities.pluralize(context.formatMessage(RenderingContext.SEARCH_PAR_REND_RES), spd.getBase().size())); XhtmlNode td = tr.td(); for (Enumeration t : spd.getBase()) { StructureDefinition sd = context.getWorker().fetchTypeDefinition(t.getCode()); @@ -81,7 +81,7 @@ public class SearchParameterRenderer extends TerminologyRenderer { } if (spd.hasTarget()) { tr = tbl.tr(); - tr.td().tx(Utilities.pluralize(/*!#*/"Target Resources", spd.getTarget().size())); + tr.td().tx(Utilities.pluralize(context.formatMessage(RenderingContext.SEARCH_PAR_REND_TARGET), spd.getTarget().size())); td = tr.td(); if (isAllConcreteResources(spd.getTarget())) { td.ah(Utilities.pathURL(context.getLink(KnownLinkType.SPEC), "resourcelist.html")).tx(context.formatMessage(RenderingContext.SEARCH_PAR_RES)); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureDefinitionRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureDefinitionRenderer.java index e534dec18..2c3f76ff4 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureDefinitionRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureDefinitionRenderer.java @@ -86,6 +86,7 @@ import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.i18n.I18nConstants; +import org.hl7.fhir.utilities.i18n.RenderingI18nContext; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator; import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Cell; @@ -491,7 +492,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { if (!url.equals(source.getUrl())) { source = context.getWorker().fetchResource(StructureDefinition.class, url, source); if (source == null) { - throw new FHIRException(/*!#*/"Unable to resolve StructureDefinition "+url+" resolving content reference "+contentReference); + throw new FHIRException(context.formatMessage(RenderingContext.STRUC_DEF_REND_UNABLE_RES, url, contentReference)); } elements = source.getSnapshot().getElement(); } @@ -504,7 +505,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { return new ElementInStructure(source, ed); } } - throw new Error(/*!#*/"getElementByName: can't find "+contentReference+" in "+elements.toString()+" from "+source.getUrl()); + throw new Error(context.formatMessage(RenderingContext.STRUC_DEF_CANT_FIND, contentReference, elements.toString(), source.getUrl())); // return null; } @@ -708,7 +709,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { model.setDocoRef(Utilities.pathURL("https://build.fhir.org/ig/FHIR/ig-guidance", "readingIgs.html#table-views")); model.getTitles().add(gen.new Title(null, model.getDocoRef(), (context.formatMessage(RenderingContext.STRUC_DEF_NAME)), (context.formatMessage(RenderingContext.STRUC_DEF_LOGIC_NAME)), null, 0)); for (Column col : columns) { - model.getTitles().add(gen.new Title(null, model.getDocoRef(), (/*!#*/col.title), (/*!#*/col.hint), null, 0)); + model.getTitles().add(gen.new Title(null, model.getDocoRef(), (col.title), (col.hint), null, 0)); } return model; } @@ -738,52 +739,52 @@ public class StructureDefinitionRenderer extends ResourceRenderer { boolean ext = false; if (tail(element.getPath()).equals("extension") && isExtension(element)) { if (element.hasType() && element.getType().get(0).hasProfile() && extensionIsComplex(element.getType().get(0).getProfile().get(0).getValue())) - row.setIcon("icon_extension_complex.png", HierarchicalTableGenerator.TEXT_ICON_EXTENSION_COMPLEX); + row.setIcon("icon_extension_complex.png", context.formatMessage(RenderingI18nContext.TEXT_ICON_EXTENSION_COMPLEX)); else - row.setIcon("icon_extension_simple.png", HierarchicalTableGenerator.TEXT_ICON_EXTENSION_SIMPLE); + row.setIcon("icon_extension_simple.png", context.formatMessage(RenderingI18nContext.TEXT_ICON_EXTENSION_SIMPLE)); ext = true; } else if (tail(element.getPath()).equals("modifierExtension")) { if (element.hasType() && element.getType().get(0).hasProfile() && extensionIsComplex(element.getType().get(0).getProfile().get(0).getValue())) - row.setIcon("icon_modifier_extension_complex.png", HierarchicalTableGenerator.TEXT_ICON_EXTENSION_COMPLEX); + row.setIcon("icon_modifier_extension_complex.png", context.formatMessage(RenderingI18nContext.TEXT_ICON_EXTENSION_COMPLEX)); else - row.setIcon("icon_modifier_extension_simple.png", HierarchicalTableGenerator.TEXT_ICON_EXTENSION_SIMPLE); + row.setIcon("icon_modifier_extension_simple.png", context.formatMessage(RenderingI18nContext.TEXT_ICON_EXTENSION_SIMPLE)); } else if (!hasDef || element.getType().size() == 0) { if (root && profile != null && context.getWorker().getResourceNames().contains(profile.getType())) { - row.setIcon("icon_resource.png", HierarchicalTableGenerator.TEXT_ICON_RESOURCE); + row.setIcon("icon_resource.png", context.formatMessage(RenderingI18nContext.TEXT_ICON_RESOURCE)); } else if (hasDef && element.hasExtension(ToolingExtensions.EXT_JSON_PROP_KEY)) { - row.setIcon("icon-object-box.png", HierarchicalTableGenerator.TEXT_ICON_OBJECT_BOX); + row.setIcon("icon-object-box.png", context.formatMessage(RenderingI18nContext.TEXT_ICON_OBJECT_BOX)); keyRows.add(element.getId()+"."+ToolingExtensions.readStringExtension(element, ToolingExtensions.EXT_JSON_PROP_KEY)); } else { - row.setIcon("icon_element.gif", HierarchicalTableGenerator.TEXT_ICON_ELEMENT); + row.setIcon("icon_element.gif", context.formatMessage(RenderingI18nContext.TEXT_ICON_ELEMENT)); } } else if (hasDef && element.getType().size() > 1) { if (allAreReference(element.getType())) { - row.setIcon("icon_reference.png", HierarchicalTableGenerator.TEXT_ICON_REFERENCE); + row.setIcon("icon_reference.png", context.formatMessage(RenderingI18nContext.TEXT_ICON_REFERENCE)); } else if (element.hasExtension(ToolingExtensions.EXT_JSON_PRIMITIVE_CHOICE)) { - row.setIcon("icon_choice.gif", HierarchicalTableGenerator.TEXT_ICON_CHOICE); + row.setIcon("icon_choice.gif", context.formatMessage(RenderingI18nContext.TEXT_ICON_CHOICE)); } else { - row.setIcon("icon_choice.gif", HierarchicalTableGenerator.TEXT_ICON_CHOICE); + row.setIcon("icon_choice.gif", context.formatMessage(RenderingI18nContext.TEXT_ICON_CHOICE)); typesRow = row; } } else if (hasDef && element.getType().get(0).getWorkingCode() != null && element.getType().get(0).getWorkingCode().startsWith("@")) { - row.setIcon("icon_reuse.png", HierarchicalTableGenerator.TEXT_ICON_REUSE); + row.setIcon("icon_reuse.png", context.formatMessage(RenderingI18nContext.TEXT_ICON_REUSE)); } else if (hasDef && context.getContext().isPrimitiveType(element.getType().get(0).getWorkingCode())) { if (keyRows.contains(element.getId())) { - row.setIcon("icon-key.png", HierarchicalTableGenerator.TEXT_ICON_KEY); + row.setIcon("icon-key.png", context.formatMessage(RenderingI18nContext.TEXT_ICON_KEY)); } else { - row.setIcon("icon_primitive.png", HierarchicalTableGenerator.TEXT_ICON_PRIMITIVE); + row.setIcon("icon_primitive.png", context.formatMessage(RenderingI18nContext.TEXT_ICON_PRIMITIVE)); } } else if (hasDef && element.getType().get(0).hasTarget()) { - row.setIcon("icon_reference.png", HierarchicalTableGenerator.TEXT_ICON_REFERENCE); + row.setIcon("icon_reference.png", context.formatMessage(RenderingI18nContext.TEXT_ICON_REFERENCE)); } else if (hasDef && context.getContext().isDataType(element.getType().get(0).getWorkingCode())) { - row.setIcon("icon_datatype.gif", HierarchicalTableGenerator.TEXT_ICON_DATATYPE); + row.setIcon("icon_datatype.gif", context.formatMessage(RenderingI18nContext.TEXT_ICON_DATATYPE)); } else if (hasDef && element.hasExtension(ToolingExtensions.EXT_JSON_PROP_KEY)) { - row.setIcon("icon-object-box.png", HierarchicalTableGenerator.TEXT_ICON_OBJECT_BOX); + row.setIcon("icon-object-box.png", context.formatMessage(RenderingI18nContext.TEXT_ICON_OBJECT_BOX)); keyRows.add(element.getId()+"."+ToolingExtensions.readStringExtension(element, ToolingExtensions.EXT_JSON_PROP_KEY)); } else if (hasDef && Utilities.existsInList(element.getType().get(0).getWorkingCode(), "Base", "Element", "BackboneElement")) { - row.setIcon("icon_element.gif", HierarchicalTableGenerator.TEXT_ICON_ELEMENT); + row.setIcon("icon_element.gif", context.formatMessage(RenderingI18nContext.TEXT_ICON_ELEMENT)); } else { - row.setIcon("icon_resource.png", HierarchicalTableGenerator.TEXT_ICON_RESOURCE); + row.setIcon("icon_resource.png", context.formatMessage(RenderingI18nContext.TEXT_ICON_RESOURCE)); } if (element.hasUserData("render.opaque")) { row.setOpacity("0.5"); @@ -823,7 +824,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { showMissing = false; //? slicingRow = row; } else { - row.setIcon("icon_slice.png", HierarchicalTableGenerator.TEXT_ICON_SLICE); + row.setIcon("icon_slice.png", context.formatMessage(RenderingI18nContext.TEXT_ICON_SLICE)); slicingRow = row; for (Cell cell : row.getCells()) for (Piece p : cell.getPieces()) { @@ -831,7 +832,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { } } } else if (element.hasSliceName()) { - row.setIcon("icon_slice_item.png", HierarchicalTableGenerator.TEXT_ICON_SLICE_ITEM); + row.setIcon("icon_slice_item.png", context.formatMessage(RenderingI18nContext.TEXT_ICON_SLICE_ITEM)); } if (used.used || showMissing) rows.add(row); @@ -849,8 +850,8 @@ public class StructureDefinitionRenderer extends ResourceRenderer { hrow.setAnchor(element.getPath()); hrow.setColor(context.getProfileUtilities().getRowColor(element, isConstraintMode)); hrow.setLineColor(1); - hrow.setIcon("icon_element.gif", HierarchicalTableGenerator.TEXT_ICON_ELEMENT); - hrow.getCells().add(gen.new Cell(null, null, sName+/*!#*/":All Slices", "", null)); + hrow.setIcon("icon_element.gif", context.formatMessage(RenderingI18nContext.TEXT_ICON_ELEMENT)); + hrow.getCells().add(gen.new Cell(null, null, sName+ (context.formatMessage(RenderingContext.STRUC_DEF_ALL_SLICES)), "", null)); switch (context.getStructureMode()) { case BINDINGS: case OBLIGATIONS: @@ -875,7 +876,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { hrow.setAnchor(element.getPath()); hrow.setColor(context.getProfileUtilities().getRowColor(element, isConstraintMode)); hrow.setLineColor(1); - hrow.setIcon("icon_element.gif", HierarchicalTableGenerator.TEXT_ICON_ELEMENT); + hrow.setIcon("icon_element.gif", context.formatMessage(RenderingI18nContext.TEXT_ICON_ELEMENT)); hrow.getCells().add(gen.new Cell(null, null, sName+ context.formatMessage(RenderingContext.STRUC_DEF_ALL_TYPES), "", null)); switch (context.getStructureMode()) { case BINDINGS: @@ -908,7 +909,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { parent.setAnchor(child.getPath()); parent.setColor(context.getProfileUtilities().getRowColor(child, isConstraintMode)); parent.setLineColor(1); - parent.setIcon("icon_slice.png", HierarchicalTableGenerator.TEXT_ICON_SLICE); + parent.setIcon("icon_slice.png", context.formatMessage(RenderingI18nContext.TEXT_ICON_SLICE)); parent.getCells().add(gen.new Cell(null, null, "Slices for "+ child.getName(), "", null)); switch (context.getStructureMode()) { case BINDINGS: @@ -1089,13 +1090,13 @@ public class StructureDefinitionRenderer extends ResourceRenderer { } if (element != null && (hasNonBaseConstraints(element.getConstraint()) || hasNonBaseConditions(element.getCondition()))) { Piece p = gc.addText(CONSTRAINT_CHAR); - p.setHint((/*!#*/"This element has or is affected by constraints ("+listConstraintsAndConditions(element)+")")); + p.setHint((context.formatMessage(RenderingContext.STRUC_DEF_ELE_AFFECTED, listConstraintsAndConditions(element), ")"))); p.addStyle(CONSTRAINT_STYLE); p.setReference(Utilities.pathURL(VersionUtilities.getSpecUrl(context.getWorker().getVersion()), "conformance-rules.html#constraints")); } if (element != null && element.hasExtension(ToolingExtensions.EXT_STANDARDS_STATUS)) { StandardsStatus ss = StandardsStatus.fromCode(element.getExtensionString(ToolingExtensions.EXT_STANDARDS_STATUS)); - gc.addStyledText(/*!#*/"Standards Status = "+ss.toDisplay(), ss.getAbbrev(), "black", ss.getColor(), context.getWorker().getSpecUrl()+"versions.html#std-process", true); + gc.addStyledText(context.formatMessage(RenderingContext.STRUC_DEF_STAND_STATUS) +ss.toDisplay(), ss.getAbbrev(), context.formatMessage(RenderingContext.STRUC_DEF_BLACK), ss.getColor(), context.getWorker().getSpecUrl()+"versions.html#std-process", true); } ExtensionContext extDefn = null; @@ -1237,7 +1238,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { row.setAnchor(parent.getPath()+"-"+grp.getName()); row.setColor(context.getProfileUtilities().getRowColor(parent, isConstraintMode)); row.setLineColor(1); - row.setIcon("icon_choice.gif", HierarchicalTableGenerator.TEXT_ICON_CHOICE); + row.setIcon("icon_choice.gif", context.formatMessage(RenderingI18nContext.TEXT_ICON_CHOICE)); row.getCells().add(gen.new Cell(null, null, context.formatMessage(RenderingContext.STRUC_DEF_CHOICE), "", null)); row.getCells().add(gen.new Cell()); row.getCells().add(gen.new Cell(null, null, (grp.isMandatory() ? "1" : "0")+"..1", "", null)); @@ -1316,7 +1317,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { if (root) { if (profile != null && profile.getAbstract()) { if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.addPiece(gen.new Piece(null, /*!#*/"This is an abstract "+(profile.getDerivation() == TypeDerivationRule.CONSTRAINT ? "profile" : "type")+". ", null)); + c.addPiece(gen.new Piece(null, context.formatMessage(RenderingContext.STRUC_DEF_ABSTRACT) +(profile.getDerivation() == TypeDerivationRule.CONSTRAINT ? "profile" : "type")+". ", null)); List children = new ArrayList<>(); for (StructureDefinition sd : context.getWorker().fetchResourcesByType(StructureDefinition.class)) { @@ -1325,7 +1326,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { } } if (!children.isEmpty()) { - c.addPiece(gen.new Piece(null, /*!#*/"Child "+(profile.getDerivation() == TypeDerivationRule.CONSTRAINT ? "profiles" : "types")+": ", null)); + c.addPiece(gen.new Piece(null, context.formatMessage(RenderingContext.STRUC_DEF_CHILD) +(profile.getDerivation() == TypeDerivationRule.CONSTRAINT ? "profiles" : "types")+": ", null)); boolean first = true; for (StructureDefinition sd : children) { if (first) first = false; else c.addPiece(gen.new Piece(null, ", ", null)); @@ -1511,7 +1512,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { if (definition.hasExtension(ToolingExtensions.EXT_JSON_PROP_KEY)) { if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } String code = ToolingExtensions.readStringExtension(definition, ToolingExtensions.EXT_JSON_PROP_KEY); - c.getPieces().add(gen.new Piece(null, /*!#*/"JSON: Represented as a single JSON Object with named properties using the value of the "+code+" child as the key", null)); + c.getPieces().add(gen.new Piece(null, context.formatMessage(RenderingContext.STRUC_DEF_SINGLE_JSON_OBJECTS, code), null)); } if (definition.hasExtension(ToolingExtensions.EXT_TYPE_SPEC)) { for (Extension e : definition.getExtensionsByUrl(ToolingExtensions.EXT_TYPE_SPEC)) { @@ -2117,7 +2118,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { used.used = element.hasType() && element.getType().get(0).hasProfile(); showMissing = false; } else { - row.setIcon("icon_slice.png", HierarchicalTableGenerator.TEXT_ICON_SLICE); + row.setIcon("icon_slice.png", context.formatMessage(RenderingI18nContext.TEXT_ICON_SLICE); row.getCells().get(2).getPieces().clear(); for (Cell cell : row.getCells()) for (Piece p : cell.getPieces()) { @@ -2255,15 +2256,15 @@ public class StructureDefinitionRenderer extends ResourceRenderer { row.getCells().add(c); if (!pattern) { c.addPiece(gen.new Piece(null, "0..0", null)); - row.setIcon("icon_fixed.gif", context.formatMessage(RenderingContext.STRUC_DEF_FIXED_VALUE) /*HierarchicalTableGenerator.TEXT_ICON_FIXED*/); + row.setIcon("icon_fixed.gif", context.formatMessage(RenderingContext.STRUC_DEF_FIXED_VALUE) /*context.formatMessage(RenderingI18nContext.TEXT_ICON_FIXED*/); } else if (context.getContext().isPrimitiveType(t.getTypeCode())) { - row.setIcon("icon_primitive.png", HierarchicalTableGenerator.TEXT_ICON_PRIMITIVE); + row.setIcon("icon_primitive.png", context.formatMessage(RenderingI18nContext.TEXT_ICON_PRIMITIVE)); c.addPiece(gen.new Piece(null, "0.."+(t.getMaxCardinality() == 2147483647 ? "*": Integer.toString(t.getMaxCardinality())), null)); } else if (isReference(t.getTypeCode())) { - row.setIcon("icon_reference.png", HierarchicalTableGenerator.TEXT_ICON_REFERENCE); + row.setIcon("icon_reference.png", context.formatMessage(RenderingI18nContext.TEXT_ICON_REFERENCE)); c.addPiece(gen.new Piece(null, "0.."+(t.getMaxCardinality() == 2147483647 ? "*": Integer.toString(t.getMaxCardinality())), null)); } else { - row.setIcon("icon_datatype.gif", HierarchicalTableGenerator.TEXT_ICON_DATATYPE); + row.setIcon("icon_datatype.gif", context.formatMessage(RenderingI18nContext.TEXT_ICON_DATATYPE)); c.addPiece(gen.new Piece(null, "0.."+(t.getMaxCardinality() == 2147483647 ? "*": Integer.toString(t.getMaxCardinality())), null)); } c = gen.new Cell(); @@ -2290,7 +2291,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { Row row = gen.new Row(); row.setId(ed.getPath()); erow.getSubRows().add(row); - row.setIcon("icon_fixed.gif", context.formatMessage(RenderingContext.STRUC_DEF_FIXED) /*HierarchicalTableGenerator.TEXT_ICON_FIXED*/); + row.setIcon("icon_fixed.gif", context.formatMessage(RenderingContext.STRUC_DEF_FIXED) /*context.formatMessage(RenderingI18nContext.TEXT_ICON_FIXED*/); Cell c = gen.new Cell(); row.getCells().add(c); @@ -2430,12 +2431,12 @@ public class StructureDefinitionRenderer extends ResourceRenderer { if (definition.hasContentReference()) { ElementInStructure ed = getElementByName(profile.getSnapshot().getElement(), definition.getContentReference(), profile); if (ed == null) - c.getPieces().add(gen.new Piece(null, /*!#*/"Unknown reference to "+definition.getContentReference(), null)); + c.getPieces().add(gen.new Piece(null, context.formatMessage(RenderingContext.STRUC_DEF_UNKNOWN_REF, definition.getContentReference()), null)); else { if (ed.getSource() == profile) { - c.getPieces().add(gen.new Piece("#"+ed.getElement().getPath(), /*!#*/"See "+ed.getElement().getPath(), null)); + c.getPieces().add(gen.new Piece("#"+ed.getElement().getPath(), context.formatMessage(RenderingContext.STRUC_DEF_SEE, ed.getElement().getPath()), null)); } else { - c.getPieces().add(gen.new Piece(ed.getSource().getWebPath()+"#"+ed.getElement().getPath(), /*!#*/"See "+ed.getSource().getTypeName()+"."+ed.getElement().getPath(), null)); + c.getPieces().add(gen.new Piece(ed.getSource().getWebPath()+"#"+ed.getElement().getPath(), context.formatMessage(RenderingContext.STRUC_DEF_SEE, ed.getSource().getTypeName()) +"."+ed.getElement().getPath(), null)); } } } @@ -2509,7 +2510,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { } else if (definition.hasExample()) { for (ElementDefinitionExampleComponent ex : definition.getExample()) { if (!c.getPieces().isEmpty()) { c.addPiece(gen.new Piece("br")); } - c.getPieces().add(checkForNoChange(ex, gen.new Piece(null, /*!#*/"Example'"+("".equals("General")? "": " "+ex.getLabel()+"'")+": ", "").addStyle("font-weight:bold"))); + c.getPieces().add(checkForNoChange(ex, gen.new Piece(null, context.formatMessage(RenderingContext.STRUC_DEF_EXAMPLE) +"'"+("".equals("General")? "": " "+ex.getLabel()+"'")+": ", "").addStyle("font-weight:bold"))); c.getPieces().add(checkForNoChange(ex, gen.new Piece(null, buildJson(ex.getValue()), null).addStyle("color: darkgreen"))); } } @@ -2694,7 +2695,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { choicerow.getCells().add(gen.new Cell(null, null, tail(element.getPath()).replace("[x]", Utilities.capitalize(t)), null, null)); choicerow.getCells().add(gen.new Cell()); choicerow.getCells().add(gen.new Cell(null, null, "", null, null)); - choicerow.setIcon("icon_reference.png", HierarchicalTableGenerator.TEXT_ICON_REFERENCE); + choicerow.setIcon("icon_reference.png", context.formatMessage(RenderingI18nContext.TEXT_ICON_REFERENCE)); Cell c = gen.new Cell(); choicerow.getCells().add(c); if (ADD_REFERENCE_TO_TABLE) { @@ -2739,7 +2740,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { choicerow.getCells().add(gen.new Cell(null, null, tail(element.getPath()).replace("[x]", Utilities.capitalize(t)), sd.getDescription(), null)); choicerow.getCells().add(gen.new Cell()); choicerow.getCells().add(gen.new Cell(null, null, "", null, null)); - choicerow.setIcon("icon_primitive.png", HierarchicalTableGenerator.TEXT_ICON_PRIMITIVE); + choicerow.setIcon("icon_primitive.png", context.formatMessage(RenderingI18nContext.TEXT_ICON_PRIMITIVE)); Cell c = gen.new Cell(null, corePath+"datatypes.html#"+t, sd.getTypeName(), null, null); choicerow.getCells().add(c); if (!mustSupportMode && isMustSupport(tr) && element.getMustSupport()) { @@ -2751,7 +2752,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { choicerow.getCells().add(gen.new Cell(null, null, tail(element.getPath()).replace("[x]", Utilities.capitalize(t)), sd.getDescription(), null)); choicerow.getCells().add(gen.new Cell()); choicerow.getCells().add(gen.new Cell(null, null, "", null, null)); - choicerow.setIcon("icon_datatype.gif", HierarchicalTableGenerator.TEXT_ICON_DATATYPE); + choicerow.setIcon("icon_datatype.gif", context.formatMessage(RenderingI18nContext.TEXT_ICON_DATATYPE)); Cell c = gen.new Cell(null, context.getPkp().getLinkFor(corePath, t), sd.getTypeName(), null, null); choicerow.getCells().add(c); if (!mustSupportMode && isMustSupport(tr) && element.getMustSupport()) { @@ -2993,9 +2994,9 @@ public class StructureDefinitionRenderer extends ResourceRenderer { row.setAnchor(span.getId()); //row.setColor(..?); if (span.isProfile()) { - row.setIcon("icon_profile.png", HierarchicalTableGenerator.TEXT_ICON_PROFILE); + row.setIcon("icon_profile.png", context.formatMessage(RenderingI18nContext.TEXT_ICON_PROFILE)); } else { - row.setIcon("icon_resource.png", HierarchicalTableGenerator.TEXT_ICON_RESOURCE); + row.setIcon("icon_resource.png", context.formatMessage(RenderingI18nContext.TEXT_ICON_RESOURCE)); } row.getCells().add(gen.new Cell(null, null, span.getName(), null, null)); @@ -3145,7 +3146,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { if (full || vdeep) { r.getCells().add(gen.new Cell("", "", "Extension", null, null)); - r.setIcon(deep ? "icon_"+m+"extension_complex.png" : "icon_extension_simple.png", deep ? HierarchicalTableGenerator.TEXT_ICON_EXTENSION_COMPLEX : HierarchicalTableGenerator.TEXT_ICON_EXTENSION_SIMPLE); + r.setIcon(deep ? "icon_"+m+"extension_complex.png" : "icon_extension_simple.png", deep ? context.formatMessage(RenderingI18nContext.TEXT_ICON_EXTENSION_COMPLEX) : context.formatMessage(RenderingI18nContext.TEXT_ICON_EXTENSION_SIMPLE)); List children = getChildren(ed.getSnapshot().getElement(), ed.getSnapshot().getElement().get(0)); for (ElementDefinition child : children) if (!child.getPath().endsWith(".id")) { @@ -3161,7 +3162,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { } r.getCells().add(gen.new Cell("", "", "Extension", null, null)); - r.setIcon("icon_"+m+"extension_complex.png", HierarchicalTableGenerator.TEXT_ICON_EXTENSION_COMPLEX); + r.setIcon("icon_"+m+"extension_complex.png", context.formatMessage(RenderingI18nContext.TEXT_ICON_EXTENSION_COMPLEX)); for (ElementDefinition c : children) { ved = getValueFor(ed, c); @@ -3174,7 +3175,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { r1.getCells().add(gen.new Cell()); r1.getCells().add(gen.new Cell(null, null, describeCardinality(c, null, new UnusedTracker()), null, null)); genTypes(gen, r1, ved, defFile, ed, corePath, imagePath, false, false); - r1.setIcon("icon_"+m+"extension_simple.png", HierarchicalTableGenerator.TEXT_ICON_EXTENSION_SIMPLE); + r1.setIcon("icon_"+m+"extension_simple.png", context.formatMessage(RenderingI18nContext.TEXT_ICON_EXTENSION_SIMPLE)); generateDescription(gen, r1, c, null, true, corePath, corePath, ed, corePath, imagePath, false, false, false, ved, false, false, false, rc); } } @@ -3186,7 +3187,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { genTypes(gen, r, ved, defFile, ed, corePath, imagePath, false, false); - r.setIcon("icon_"+m+"extension_simple.png", HierarchicalTableGenerator.TEXT_ICON_EXTENSION_SIMPLE); + r.setIcon("icon_"+m+"extension_simple.png", context.formatMessage(RenderingI18nContext.TEXT_ICON_EXTENSION_SIMPLE)); } Cell c = gen.new Cell("", "", "URL = "+ed.getUrl(), null, null); Piece cc = gen.new Piece(null, ed.getName()+": ", null); @@ -3665,7 +3666,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { tableRow(tbl, context.formatMessage(RenderingContext.STRUC_DEF_CONTROL), "conformance-rules.html#conformance", strikethrough, describeCardinality(d, compare, mode)); tableRow(tbl, context.formatMessage(RenderingContext.STRUC_DEF_BINDING), "terminologies.html", strikethrough, describeBinding(sd, d, d.getPath(), compare, mode)); if (d.hasContentReference()) { - tableRow(tbl, context.formatMessage(RenderingContext.STRUC_DEF_TYPE), null, strikethrough, /*!#*/"See " + d.getContentReference().substring(1)); + tableRow(tbl, context.formatMessage(RenderingContext.STRUC_DEF_TYPE), null, strikethrough, context.formatMessage(RenderingContext.STRUC_DEF_SEE) + d.getContentReference().substring(1)); } else { tableRow(tbl, context.formatMessage(RenderingContext.STRUC_DEF_TYPE), "datatypes.html", strikethrough, describeTypes(d.getType(), false, d, compare, mode, value, compareValue, sd)); } @@ -3673,18 +3674,19 @@ public class StructureDefinitionRenderer extends ResourceRenderer { tableRow(tbl, context.formatMessage(RenderingContext.STRUC_DEF_DEFAULT_TYPE), "datatypes.html", strikethrough, ToolingExtensions.readStringExtension(d, ToolingExtensions.EXT_DEF_TYPE)); } if (d.hasExtension(ToolingExtensions.EXT_TYPE_SPEC)) { - tableRow(tbl, Utilities.pluralize(/*!#*/"Type Specifier", d.getExtensionsByUrl(ToolingExtensions.EXT_TYPE_SPEC).size()), "datatypes.html", strikethrough, formatTypeSpecifiers(d)); + tableRow(tbl, Utilities.pluralize(context.formatMessage(RenderingContext.STRUC_DEF_TYPE_SPEC), d.getExtensionsByUrl(ToolingExtensions.EXT_TYPE_SPEC).size()), "datatypes.html", strikethrough, formatTypeSpecifiers(d)); } if (d.getPath().endsWith("[x]") && !d.prohibited()) { - tableRow(tbl, context.formatMessage(RenderingContext.STRUC_DEF_NOTE_X), null, strikethrough).ahWithText("See ", spec("formats.html#choice"), null, /*!#*/"Choice of Data Types", " for further information about how to use [x]"); + tableRow(tbl, context.formatMessage(RenderingContext.STRUC_DEF_NOTE_X), null, strikethrough).ahWithText(context.formatMessage(RenderingContext.STRUC_DEF_SEE) + , spec("formats.html#choice"), null, context.formatMessage(RenderingContext.STRUC_DEF_CHOICE_DATA_TYPE), context.formatMessage(RenderingContext.STRUC_DEF_FURTHER_INFO)); } tableRow(tbl, context.formatMessage(RenderingContext.STRUC_DEF_MODIFIER), "conformance-rules.html#ismodifier", strikethrough, presentModifier(d, mode, compare)); if (d.getMustHaveValue()) { - tableRow(tbl, context.formatMessage(RenderingContext.STRUC_DEF_PRIMITIVE), "elementdefinition.html#primitives", strikethrough, /*!#*/"This primitive type must have a value (the value must be present, and cannot be replaced by an extension)"); + tableRow(tbl, context.formatMessage(RenderingContext.STRUC_DEF_PRIMITIVE), "elementdefinition.html#primitives", strikethrough, context.formatMessage(RenderingContext.STRUC_DEF_PRIM_TYPE_VALUE)); } else if (d.hasValueAlternatives()) { - tableRow(tbl, context.formatMessage(RenderingContext.STRUC_DEF_PRIMITIVE), "elementdefinition.html#primitives", strikethrough, renderCanonicalList(/*!#*/"This primitive type may be present, or absent if replaced by one of the following extensions: ", d.getValueAlternatives())); + tableRow(tbl, context.formatMessage(RenderingContext.STRUC_DEF_PRIMITIVE), "elementdefinition.html#primitives", strikethrough, renderCanonicalList(context.formatMessage(RenderingContext.STRUC_DEF_PRIM_TYPE_PRESENT), d.getValueAlternatives())); } else if (hasPrimitiveTypes(d)) { - tableRow(tbl, context.formatMessage(RenderingContext.STRUC_DEF_PRIMITIVE), "elementdefinition.html#primitives", strikethrough, /*!#*/"This primitive element may be present, or absent, or replaced by an extension"); + tableRow(tbl, context.formatMessage(RenderingContext.STRUC_DEF_PRIMITIVE), "elementdefinition.html#primitives", strikethrough, context.formatMessage(RenderingContext.STRUC_DEF_PRIM_ELE)); } if (ToolingExtensions.hasAllowedUnits(d)) { tableRow(tbl, context.formatMessage(RenderingContext.STRUC_DEF_ALLOWED), "http://hl7.org/fhir/extensions/StructureDefinition-elementdefinition-allowedUnits.html", strikethrough, describeAllowedUnits(d)); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureMapRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureMapRenderer.java index fae63e3b2..b11bbf6f7 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureMapRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureMapRenderer.java @@ -61,9 +61,6 @@ public class StructureMapRenderer extends TerminologyRenderer { private static final String COLOR_SYNTAX = "navy"; private static final boolean MULTIPLE_TARGETS_ONELINE = true; private static final String COLOR_SPECIAL = "#b36b00"; - private static final String DEFAULT_COMMENT = /*!#*/"This element was not defined prior to R5"; - - private String clauseComment = DEFAULT_COMMENT; public StructureMapRenderer(RenderingContext context) { super(context); @@ -634,7 +631,7 @@ public class StructureMapRenderer extends TerminologyRenderer { } if (isClause) { XhtmlNode s= x.color(COLOR_SPECIAL); - s.setAttribute("title", clauseComment ); + s.setAttribute("title", formatMessage(RenderingContext.MAP_DEFAULT_COMMENT)); s.tx("// "); s.tx(doco.replace("\r\n", " ").replace("\r", " ").replace("\n", " ")); } else { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/TerminologyRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/TerminologyRenderer.java index 292153b3e..40f63e0ce 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/TerminologyRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/TerminologyRenderer.java @@ -329,7 +329,7 @@ public abstract class TerminologyRenderer extends ResourceRenderer { protected void clipboard(XhtmlNode x, String img, String title, String source) { - XhtmlNode span = x.span("cursor: pointer", /*!#*/"Copy "+title+" Format to clipboard"); + XhtmlNode span = x.span("cursor: pointer", formatMessage(RenderingContext.TERM_REND_COPY, title)); span.attribute("onClick", "navigator.clipboard.writeText('"+Utilities.escapeJson(source)+"');"); span.img(img, "btn").setAttribute("width", "24px").setAttribute("height", "16px"); } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/TestPlanRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/TestPlanRenderer.java index 4bd97d560..73fee97a7 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/TestPlanRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/TestPlanRenderer.java @@ -132,7 +132,7 @@ public class TestPlanRenderer extends ResourceRenderer { if (tp.hasTestCase()) { for (TestPlanTestCaseComponent tc : tp.getTestCase()) { - x.h2().addText(/*!#*/"Test Case" + (tc.hasSequence() ? " - Sequence" + tc.getSequence() : "")); + x.h2().addText(tc.hasSequence() ? formatMessage(RenderingContext.TEST_PLAN_CASE) : formatMessage(RenderingContext.TEST_PLAN_CASE_SEQ, tc.getSequence())); if (tc.hasScope()) { if (tc.getScope().size() == 1) { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ValueSetRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ValueSetRenderer.java index a4a8d2552..2e1685c28 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ValueSetRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ValueSetRenderer.java @@ -60,6 +60,7 @@ import org.hl7.fhir.r5.utils.ToolingExtensions; import org.hl7.fhir.utilities.LoincLinker; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.i18n.I18nConstants; +import org.hl7.fhir.utilities.i18n.RenderingI18nContext; import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator; import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Row; import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.TableModel; @@ -78,8 +79,6 @@ public class ValueSetRenderer extends TerminologyRenderer { super(context, rcontext); } - private static final String ABSTRACT_CODE_HINT = /*!#*/"This code is not selectable ('Abstract')"; - private static final int MAX_DESIGNATIONS_IN_LINE = 5; private static final int MAX_BATCH_VALIDATION_SIZE = 1000; @@ -209,7 +208,7 @@ public class ValueSetRenderer extends TerminologyRenderer { if (vs.getExpansion().getContains().isEmpty()) { msg = context.formatMessage(RenderingContext.VALUE_SET_TOO_COSTLY); } else { - msg = /*!#*/"This value set cannot be fully expanded, but a selection ("+countMembership(vs)+" codes) of the whole set of codes is shown here."; + msg = context.formatMessage(RenderingContext.VALUE_SET_CODE_SELEC, countMembership(vs)); } x.para().style("border: maroon 1px solid; background-color: #FFCCCC; font-weight: bold; padding: 8px").addText(msg); } else { @@ -217,9 +216,9 @@ public class ValueSetRenderer extends TerminologyRenderer { if (vs.getExpansion().hasTotal()) { if (count != vs.getExpansion().getTotal()) { x.para().style("border: maroon 1px solid; background-color: #FFCCCC; font-weight: bold; padding: 8px") - .addText(/*!#*/"This value set has "+(hasFragment ? "at least " : "")+vs.getExpansion().getTotal()+" codes in it. In order to keep the publication size manageable, only a selection ("+count+" codes) of the whole set of codes is shown."); + .addText(context.formatMessage(RenderingContext.VALUE_SET_HAS)+(hasFragment ? context.formatMessage(RenderingContext.VALUE_SET_AT_LEAST) : "")+vs.getExpansion().getTotal()+" codes in it. In order to keep the publication size manageable, only a selection ("+count+" codes) of the whole set of codes is shown."); } else { - x.para().tx(/*!#*/"This value set contains "+(hasFragment ? "at least " : "")+vs.getExpansion().getTotal()+" concepts."); + x.para().tx(context.formatMessage(RenderingContext.VALUE_SET_CONTAINS)+(hasFragment ? context.formatMessage(RenderingContext.VALUE_SET_AT_LEAST) : "")+vs.getExpansion().getTotal()+" concepts."); } } else if (count == 1000) { // it's possible that there's exactly 1000 codes, in which case wht we're about to do is wrong @@ -227,7 +226,7 @@ public class ValueSetRenderer extends TerminologyRenderer { String msg = context.formatMessage(RenderingContext.VALUE_SET_SEL); x.para().style("border: maroon 1px solid; background-color: #FFCCCC; font-weight: bold; padding: 8px").addText(msg); } else { - x.para().tx(/*!#*/"This value set expansion contains "+count+" concepts."); + x.para().tx(context.formatMessage(RenderingContext.VALUE_SET_NUMBER_CONCEPTS, count)); } } @@ -514,30 +513,30 @@ public class ValueSetRenderer extends TerminologyRenderer { if (parts.length >= 5) { String m = describeModule(parts[4]); if (parts.length == 7) { - x.tx(/*!#*/"SNOMED CT "+m+" edition "+formatSCTDate(parts[6])); + x.tx(context.formatMessage(RenderingContext.VALUE_SET_SNOMED_ADD, m, formatSCTDate(parts[6]))); } else { - x.tx(/*!#*/"SNOMED CT "+m+" edition"); + x.tx(context.formatMessage(RenderingContext.VALUE_SET_SNOMED, m)); } } else { - x.tx(displaySystem(u)+" "+/*!#*/"version "+v); + x.tx(displaySystem(u)+" "+ context.formatMessage(RenderingContext.VALUE_SET_VERSION) + " " +v); } } else if (u.equals("http://loinc.org")) { String vd = describeLoincVer(v); if (vd != null) { - x.tx(/*!#*/"Loinc v"+v+" ("+vd+")"); + x.tx(context.formatMessage(RenderingContext.VALUE_SET_LOINCV)+v+" ("+vd+")"); } else { - x.tx(/*!#*/"Loinc v"+v); + x.tx(context.formatMessage(RenderingContext.VALUE_SET_LOINCV)+v); } } else if (Utilities.noString(v)) { CanonicalResource cr = (CanonicalResource) getContext().getWorker().fetchResource(Resource.class, u, source); if (cr != null) { if (cr.hasWebPath()) { - x.ah(cr.getWebPath()).tx(t+" "+cr.present()+" "+/*!#*/"(no version) ("+cr.fhirType()+")"); + x.ah(cr.getWebPath()).tx(t+" "+cr.present()+" "+ context.formatMessage(RenderingContext.VALUE_SET_NO_VERSION)+cr.fhirType()+")"); } else { - x.tx(t+" "+displaySystem(u)+" "+/*!#*/"(no version) ("+cr.fhirType()+")"); + x.tx(t+" "+displaySystem(u)+" "+context.formatMessage(RenderingContext.VALUE_SET_NO_VERSION)+cr.fhirType()+")"); } } else { - x.tx(t+" "+displaySystem(u)+" "+/*!#*/"(no version)"); + x.tx(t+" "+displaySystem(u)+" "+ context.formatMessage(RenderingContext.VALUE_SET_NO_VER)); } } else { CanonicalResource cr = (CanonicalResource) getContext().getWorker().fetchResource(Resource.class, u+"|"+v, source); @@ -548,7 +547,7 @@ public class ValueSetRenderer extends TerminologyRenderer { x.tx(t+" "+displaySystem(u)+" v"+v+" ("+cr.fhirType()+")"); } } else { - x.tx(t+" "+displaySystem(u)+" "+/*!#*/"version "+v); + x.tx(t+" "+displaySystem(u)+" "+ context.formatMessage(RenderingContext.VALUE_SET_VERSION)+v); } } } @@ -620,7 +619,7 @@ public class ValueSetRenderer extends TerminologyRenderer { private String describeModule(String module) { if ("900000000000207008".equals(module)) - return /*!#*/context.formatMessage(RenderingContext.VALUE_SET_INT); + return context.formatMessage(RenderingContext.VALUE_SET_INT); if ("731000124108".equals(module)) return context.formatMessage(RenderingContext.VALUE_SET_US); if ("32506021000036107".equals(module)) @@ -897,7 +896,7 @@ public class ValueSetRenderer extends TerminologyRenderer { CodeSystem e = getContext().getWorker().fetchCodeSystem(system); if (e == null || (e.getContent() != org.hl7.fhir.r5.model.Enumerations.CodeSystemContentMode.COMPLETE && e.getContent() != org.hl7.fhir.r5.model.Enumerations.CodeSystemContentMode.FRAGMENT)) { if (isAbstract) - td.i().setAttribute("title", ABSTRACT_CODE_HINT).addText(code); + td.i().setAttribute("title", context.formatMessage(RenderingI18nContext.VS_ABSTRACT_CODE_HINT)).addText(code); else if ("http://snomed.info/sct".equals(system)) { td.ah(sctLink(code)).addText(code); } else if ("http://loinc.org".equals(system)) { @@ -911,7 +910,7 @@ public class ValueSetRenderer extends TerminologyRenderer { else href = href + "#"+e.getId()+"-"+Utilities.nmtokenize(code); if (isAbstract) - td.ah(href).setAttribute("title", ABSTRACT_CODE_HINT).i().addText(code); + td.ah(href).setAttribute("title", context.formatMessage(RenderingI18nContext.VS_ABSTRACT_CODE_HINT)).i().addText(code); else td.ah(href).addText(code); } @@ -1178,14 +1177,14 @@ public class ValueSetRenderer extends TerminologyRenderer { if (inc.hasSystem()) { CodeSystem e = getContext().getWorker().fetchCodeSystem(inc.getSystem()); if (inc.getConcept().size() == 0 && inc.getFilter().size() == 0) { - li.addText(type+" "+/*!#*/"all codes defined in "); + li.addText(type+" "+ context.formatMessage(RenderingContext.VALUE_SET_ALL_CODES_DEF) + " "); addCsRef(inc, li, e); } else { if (inc.getConcept().size() > 0) { - li.addText(type+" "+/*!#*/"these codes as defined in "); + li.addText(type+" "+ context.formatMessage(RenderingContext.VALUE_SET_THESE_CODES_DEF) + " "); addCsRef(inc, li, e); if (inc.hasVersion()) { - li.addText(" "+/*!#*/"version "); + li.addText(" "+ context.formatMessage(RenderingContext.VALUE_SET_VERSION) + " "); li.code(inc.getVersion()); } @@ -1212,14 +1211,14 @@ public class ValueSetRenderer extends TerminologyRenderer { } } if (inc.getFilter().size() > 0) { - li.addText(type+" "+/*!#*/"codes from "); + li.addText(type+" "+ context.formatMessage(RenderingContext.VALUE_SET_CODES_FROM)); addCsRef(inc, li, e); - li.tx(" "+/*!#*/"where "); + li.tx(" "+ context.formatMessage(RenderingContext.VALUE_SET_WHERE)+" "); for (int i = 0; i < inc.getFilter().size(); i++) { ConceptSetFilterComponent f = inc.getFilter().get(i); if (i > 0) { if (i == inc.getFilter().size()-1) { - li.tx(" "+/*!#*/"and "); + li.tx(" "+ context.formatMessage(RenderingContext.VALUE_SET_AND)); } else { li.tx(context.formatMessage(RenderingContext.VALUE_SET_COMMA)+" "); } @@ -1227,9 +1226,9 @@ public class ValueSetRenderer extends TerminologyRenderer { XhtmlNode wli = renderStatus(f, li); if (f.getOp() == FilterOperator.EXISTS) { if (f.getValue().equals("true")) { - wli.tx(f.getProperty()+" "+/*!#*/"exists"); + wli.tx(f.getProperty()+" "+ context.formatMessage(RenderingContext.VALUE_SET_EXISTS)); } else { - wli.tx(f.getProperty()+" "+/*!#*/"doesn't exist"); + wli.tx(f.getProperty()+" "+ context.formatMessage(RenderingContext.VALUE_SET_DOESNT_EXIST)); } } else { wli.tx(f.getProperty()+" "+describe(f.getOp())+" "); @@ -1273,14 +1272,18 @@ public class ValueSetRenderer extends TerminologyRenderer { renderExpansionRules(li, inc, index, definitions); } } else { - li.tx(context.formatMessage(RenderingContext.VALUE_SET_IMPORT)+" "); - if (inc.getValueSet().size() < 4) { - boolean first = true; + li.tx(context.formatMessagePlural(inc.getValueSet().size(), RenderingContext.VALUE_SET_IMPORT)+" "); + if (inc.getValueSet().size() <= 2) { + int i = 0; for (UriType vs : inc.getValueSet()) { - if (first) - first = false; - else - li.tx(", "); + if (i > 0) { + if ( i < inc.getValueSet().size() - 1) { + li.tx(", "); + } else { + li.tx(" and "); + } + } + i++; XhtmlNode wli = renderStatus(vs, li); AddVsRef(vs.asStringValue(), wli, vsRes); } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/client/TerminologyClientManager.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/client/TerminologyClientManager.java index 276bea020..5f060ee7d 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/client/TerminologyClientManager.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/client/TerminologyClientManager.java @@ -185,6 +185,19 @@ public class TerminologyClientManager { } } + for (String sys : systems) { + String uri = sys.contains("|") ? sys.substring(0, sys.indexOf("|")) : sys; + // this list is the list of code systems that have special handling on tx.fhir.org, and might not be resolved above. + // we don't want them to go to secondary servers (e.g. VSAC) by accident (they might go deliberately above) + if (Utilities.existsInList(uri, "http://unitsofmeasure.org", "http://loinc.org", "http://snomed.info/sct", + "http://www.nlm.nih.gov/research/umls/rxnorm", "http://hl7.org/fhir/sid/cvx", "urn:ietf:bcp:13", "urn:ietf:bcp:47", + "urn:ietf:rfc:3986", "http://www.ama-assn.org/go/cpt", "urn:oid:1.2.36.1.2001.1005.17", "urn:iso:std:iso:3166", + "http://varnomen.hgvs.org", "http://unstats.un.org/unsd/methods/m49/m49.htm", "urn:iso:std:iso:4217", + "http://hl7.org/fhir/sid/ndc", "http://fhir.ohdsi.org/CodeSystem/concepts", "http://fdasis.nlm.nih.gov", "https://www.usps.com/")) { + return serverList.get(0); + } + } + // no agreement? Then what we do depends if (vs != null) { if (vs.hasUserData("External.Link")) { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/NPMPackageGenerator.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/NPMPackageGenerator.java index cc682f006..9ba2fab0f 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/NPMPackageGenerator.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/NPMPackageGenerator.java @@ -249,6 +249,10 @@ public class NPMPackageGenerator { npm.add("directories", dir); dir.add("lib", "package"); dir.add("example", "example"); + if (ig.hasJurisdiction() && ig.getJurisdiction().size() == 1 && ig.getJurisdictionFirstRep().getCoding().size() == 1) { + Coding c = ig.getJurisdictionFirstRep().getCodingFirstRep(); + npm.add("jurisdiction", c.getSystem()+"#"+c.getCode()); + } String json = JsonParser.compose(npm, true); try { addFile(Category.RESOURCE, "package.json", json.getBytes("UTF-8")); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ToolingExtensions.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ToolingExtensions.java index 210f42dc2..0231aee97 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ToolingExtensions.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/utils/ToolingExtensions.java @@ -428,6 +428,14 @@ public class ToolingExtensions { } return null; } + + public static String readStringFromExtension(Extension ext) { + if (ext.hasValue() && ext.getValue().isPrimitive()) { + return ext.getValue().primitiveValue(); + } + return null; + } + public static String readStringExtension(Element c, String uri) { Extension ex = ExtensionHelper.getExtension(c, uri); if (ex == null) diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nBase.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nBase.java index 2aaeeaac8..152b10db8 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nBase.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nBase.java @@ -66,7 +66,7 @@ public abstract class I18nBase { if (!messageKeyExistsForLocale(message)) { if (!message.contains(" ")) { if (warnAboutMissingMessages && (hasArgs || !message.contains(" "))) { - System.out.println("Attempting to localize message " + message + ", but no such equivalent message exists for" + + System.out.println("Attempting to localize "+typeOfString()+" " + message + ", but no such equivalent message exists for" + " the locale " + getLocale()); } } @@ -74,6 +74,10 @@ public abstract class I18nBase { return messageKeyExistsForLocale(message); } + protected String typeOfString() { + return "message"; + } + protected boolean messageKeyExistsForLocale(String message) { return messages.containsKey(message); } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java index fc4101e32..da994d076 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/I18nConstants.java @@ -1093,6 +1093,7 @@ public class I18nConstants { public static final String VALUESET_BAD_FILTER_VALUE_DECIMAL = "VALUESET_BAD_FILTER_VALUE_DECIMAL"; public static final String VALUESET_BAD_FILTER_VALUE_INTEGER = "VALUESET_BAD_FILTER_VALUE_INTEGER"; public static final String VALUESET_BAD_FILTER_VALUE_VALID_CODE = "VALUESET_BAD_FILTER_VALUE_VALID_CODE"; + public static final String VALUESET_BAD_FILTER_VALUE_VALID_CODE_CHANGE = "VALUESET_BAD_FILTER_VALUE_VALID_CODE_CHANGE"; public static final String VALUESET_BAD_FILTER_VALUE_CODED = "VALUESET_BAD_FILTER_VALUE_CODED"; public static final String VALUESET_BAD_FILTER_VALUE_CODED_INVALID = "VALUESET_BAD_FILTER_VALUE_CODED_INVALID"; public static final String VALUESET_BAD_FILTER_OP = "VALUESET_BAD_FILTER_OP"; @@ -1104,6 +1105,8 @@ public class I18nConstants { public static final String SD_ELEMENT_REASON_DERIVED = "SD_ELEMENT_REASON_DERIVED"; public static final String SD_ELEMENT_PATTERN_WRONG_TYPE = "SD_ELEMENT_PATTERN_WRONG_TYPE"; public static final String FHIRPATH_REDEFINE_VARIABLE = "FHIRPATH_REDEFINE_VARIABLE"; + public static final String BINDING_ADDITIONAL = "BINDING_ADDITIONAL"; + public static final String BINDING_MAX = "BINDING_MAX"; } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/JsonLangFileProducer.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/JsonLangFileProducer.java index ddd6ce42e..fae406088 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/JsonLangFileProducer.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/JsonLangFileProducer.java @@ -130,6 +130,9 @@ public class JsonLangFileProducer extends LanguageFileProducer { if (tu.getContext1() != null) { entry.add("context", tu.getContext1()); } + if (tu.getOriginal() != null) { + entry.add("original", tu.getOriginal()); + } entry.add("source", tu.getSrcText()); entry.add("target", tu.getTgtText()); } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/LanguageFileProducer.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/LanguageFileProducer.java index 4af92f8ae..1375615c6 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/LanguageFileProducer.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/LanguageFileProducer.java @@ -65,6 +65,7 @@ public abstract class LanguageFileProducer { public static class TranslationUnit extends TextUnit { private String language; + private String original; // for when the source text has been modified since being translated public TranslationUnit(String language, String id, String context, String srcText, String tgtText) { super(id, context, srcText, tgtText); @@ -86,6 +87,16 @@ public abstract class LanguageFileProducer { public void setTgtText(String tgtText) { this.tgtText = tgtText; } + + public String getOriginal() { + return original; + } + + public TranslationUnit setOriginal(String original) { + this.original = original; + return this; + } + } public class Translations { diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/PoGetTextProducer.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/PoGetTextProducer.java index 266417d9e..4b3f67294 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/PoGetTextProducer.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/PoGetTextProducer.java @@ -167,6 +167,9 @@ public class PoGetTextProducer extends LanguageFileProducer { if (tu.getContext1() != null) { ln(po, "#. "+tu.getContext1()); } + if (tu.getOriginal() != null) { + ln(po, "#| "+tu.getOriginal()); + } ln(po, "msgid \""+stripEoln(tu.getSrcText())+"\""); ln(po, "msgstr \""+(tu.getTgtText() == null ? "" : stripEoln(tu.getTgtText()))+"\""); ln(po, ""); diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/RenderingI18nContext.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/RenderingI18nContext.java index 270111184..fa948f400 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/RenderingI18nContext.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/RenderingI18nContext.java @@ -495,6 +495,8 @@ public class RenderingI18nContext extends I18nBase { public static final String REND_CHANGED = "REND_CHANGED"; public static final String REND_REMOVED = "REND_REMOVED"; public static final String REND_ROW_SINCE = "REND_ROW_SINCE"; + public static final String REND_ROW_CHANGED_SINCE = "REND_ROW_CHANGED_SINCE"; + public static final String REND_ROW_REMOVED_SINCE = "REND_ROW_REMOVED_SINCE"; public static final String REQ_ACTOR = "REQ_ACTOR"; public static final String REQ_FOLLOWING_ACTOR = "REQ_FOLLOWING_ACTOR"; public static final String REQ_DERIVE = "REQ_DERIVE"; @@ -864,7 +866,7 @@ public class RenderingI18nContext extends I18nBase { public static final String ADD_BIND_VALID_EXT = "ADD_BIND_VALID_EXT"; public static final String ADD_BIND_NEW_REC = "ADD_BIND_NEW_REC"; public static final String ADD_BIND_RECOM_VALUE_SET = "ADD_BIND_RECOM_VALUE_SET"; - public static final String ADD_BIND_RECOMMENDED = "ADD_BIND_RECOMMENDED"; + public static final String ADD_BIND_PREFERRED = "ADD_BIND_PREFERRED"; public static final String ADD_BIND_REQUIRED = "ADD_BIND_REQUIRED"; public static final String ADD_BIND_GIVEN_CONT = "ADD_BIND_GIVEN_CONT"; public static final String ADD_BIND_UI_BIND = "ADD_BIND_UI_BIND"; @@ -905,9 +907,169 @@ public class RenderingI18nContext extends I18nBase { public static final String CAPABILITY_SEARCH_PARS = "CAPABILITY_SEARCH_PARS"; public static final String CAPABILITY_COMB_SEARCH_PAR = "CAPABILITY_COMB_SEARCH_PAR"; public static final String CODE_SYS_IN_A_HIERARCHY = "CODE_SYS_IN_A_HIERARCHY"; - + public static final String CODE_SYS_REPLACED_BY = "CODE_SYS_REPLACED_BY"; + public static final String DATA_REND_ONGOING = "DATA_REND_ONGOING"; + public static final String EXAMPLE_SCEN_UNABLE_TO_FIND = "EXAMPLE_SCEN_UNABLE_TO_FIND"; + public static final String EXAMPLE_SCEN_STEP_SCEN = "EXAMPLE_SCEN_STEP_SCEN"; + public static final String DATA_REND_DETAILS_STATED = "DATA_REND_DETAILS_STATED"; + public static final String DATA_REND_VERSION = "DATA_REND_VERSION"; + public static final String DATA_REND_BASE64 = "DATA_REND_BASE64"; + public static final String DATA_REND_CODES = "DATA_REND_CODES"; + public static final String DATA_REND_GLN = "DATA_REND_GLN"; + public static final String DATA_REND_DETAILS = "DATA_REND_DETAILS"; + public static final String DATA_REND_PER = "DATA_REND_PER"; + public static final String DATA_REND_EXCEPTION = "DATA_REND_EXCEPTION"; + public static final String DIAG_REP_REND_PER = "DIAG_REP_REND_PER"; + public static final String DIAG_REP_REND_IDENTIFIER = "DIAG_REP_REND_IDENTIFIER"; + public static final String DIAG_REP_REND_REQUEST = "DIAG_REP_REND_REQUEST"; + public static final String PROF_DRIV_GEN_NARR = "PROF_DRIV_GEN_NARR"; + public static final String PROF_DRIV_ERR_GEN_NARR = "PROF_DRIV_ERR_GEN_NARR"; + public static final String QUEST_UNKNOWN_MODE = "QUEST_UNKNOWN_MODE"; + public static final String QUEST_ANSWER = "QUEST_ANSWER"; + public static final String QUEST_RESP_ROOT = "QUEST_RESP_ROOT"; + public static final String QUEST_RESP = "QUEST_RESP"; + public static final String QUEST_QUESTION = "QUEST_QUESTION"; + public static final String QUEST_NONE_SPEC = "QUEST_NONE_SPEC"; + public static final String QUEST_GROUP = "QUEST_GROUP"; + public static final String QUEST_ITEM = "QUEST_ITEM"; + public static final String QUEST_TRY_QUEST = "QUEST_TRY_QUEST"; + public static final String QUEST_DISPLAY_CAT = "QUEST_DISPLAY_CAT"; + public static final String QUEST_NOT_DONE = "QUEST_NOT_DONE"; + public static final String RES_REND_VER = "RES_REND_VER"; + public static final String RES_REND_VERSION = "RES_REND_VERSION"; + public static final String RES_REND_UPDATED = "RES_REND_UPDATED"; + public static final String RES_REND_LANGUAGE = "RES_REND_LANGUAGE"; + public static final String RES_REND_SPEC_RULES = "RES_REND_SPEC_RULES"; + public static final String RES_REND_INFO_SOURCE = "RES_REND_INFO_SOURCE"; + public static final String RES_REND_PROFILE = "RES_REND_PROFILE"; + public static final String RES_REND_SECURITY_LABEL = "RES_REND_SECURITY_LABEL"; + public static final String SEARCH_PAR_REND_RES = "SEARCH_PAR_REND_RES"; + public static final String SEARCH_PAR_REND_TARGET = "SEARCH_PAR_REND_TARGET"; + public static final String STRUC_DEF_REND_UNABLE_RES = "STRUC_DEF_REND_UNABLE_RES"; + public static final String STRUC_DEF_CANT_FIND = "STRUC_DEF_CANT_FIND"; + public static final String STRUC_DEF_ALL_SLICES = "STRUC_DEF_ALL_SLICES"; + public static final String STRUC_DEF_ELE_AFFECTED = "STRUC_DEF_ELE_AFFECTED"; + public static final String STRUC_DEF_STAND_STATUS = "STRUC_DEF_STAND_STATUS"; + public static final String STRUC_DEF_BLACK = "STRUC_DEF_BLACK"; + public static final String STRUC_DEF_ABSTRACT = "STRUC_DEF_ABSTRACT"; + public static final String STRUC_DEF_CHILD = "STRUC_DEF_CHILD"; + public static final String STRUC_DEF_SINGLE_JSON_OBJECTS = "STRUC_DEF_SINGLE_JSON_OBJECTS"; + public static final String STRUC_DEF_TYPE_SPEC = "STRUC_DEF_TYPE_SPEC"; + public static final String STRUC_DEF_CHOICE_DATA_TYPE = "STRUC_DEF_CHOICE_DATA_TYPE"; + public static final String STRUC_DEF_FURTHER_INFO = "STRUC_DEF_FURTHER_INFO"; + public static final String STRUC_DEF_PRIM_TYPE_VALUE = "STRUC_DEF_PRIM_TYPE_VALUE"; + public static final String STRUC_DEF_PRIM_TYPE_PRESENT = "STRUC_DEF_PRIM_TYPE_PRESENT"; + public static final String STRUC_DEF_PRIM_ELE = "STRUC_DEF_PRIM_ELE"; + public static final String VALUE_SET_CODE_SELEC = "VALUE_SET_CODE_SELEC"; + public static final String VALUE_SET_HAS = "VALUE_SET_HAS"; + public static final String VALUE_SET_CONTAINS = "VALUE_SET_CONTAINS"; + public static final String VALUE_SET_AT_LEAST = "VALUE_SET_AT_LEAST"; + public static final String VALUE_SET_NUMBER_CONCEPTS = "VALUE_SET_NUMBER_CONCEPTS"; + public static final String VALUE_SET_VERSION = "VALUE_SET_VERSION"; + public static final String VALUE_SET_NO_VERSION = "VALUE_SET_NO_VERSION"; + public static final String VALUE_SET_NO_VER = "VALUE_SET_NO_VER"; + public static final String VALUE_SET_THESE_CODES_DEF = "VALUE_SET_THESE_CODES_DEF"; + public static final String VALUE_SET_ALL_CODES_DEF = "VALUE_SET_ALL_CODES_DEF"; + public static final String VALUE_SET_CODES_FROM = "VALUE_SET_CODES_FROM"; + public static final String VALUE_SET_WHERE = "VALUE_SET_WHERE"; + public static final String VALUE_SET_AND = "VALUE_SET_AND"; + public static final String VALUE_SET_DOESNT_EXIST = "VALUE_SET_DOESNT_EXIST"; + public static final String VALUE_SET_SNOMED_ADD = "VALUE_SET_SNOMED_ADD"; + public static final String VALUE_SET_SNOMED = "VALUE_SET_SNOMED"; + public static final String VALUE_SET_LOINCV = "VALUE_SET_LOINCV"; + public static final String CANON_REND_URL = "CANON_REND_URL"; + public static final String CANON_REND_VER = "CANON_REND_VER"; + public static final String CANON_REND_NAME = "CANON_REND_NAME"; + public static final String CANON_REND_TITLE = "CANON_REND_TITLE"; + public static final String CANON_REND_STATUS = "CANON_REND_STATUS"; + public static final String CANON_REND_DEFINITION = "CANON_REND_DEFINITION"; + public static final String CANON_REND_PUBLISHER = "CANON_REND_PUBLISHER"; + public static final String CANON_REND_COMMITTEE = "CANON_REND_COMMITTEE"; + public static final String CANON_REND_COPYRIGHT = "CANON_REND_COPYRIGHT"; + public static final String CANON_REND_MATURITY = "CANON_REND_MATURITY"; + public static final String CANON_REND_SOURCE_RES = "CANON_REND_SOURCE_RES"; + public static final String CANON_REND_XML = "CANON_REND_XML"; + public static final String CANON_REND_JSON = "CANON_REND_JSON"; + public static final String CANON_REND_TURTLE = "CANON_REND_TURTLE"; + public static final String CODE_SYS_CONTENT = "CODE_SYS_CONTENT"; + public static final String CODE_SYS_OID = "CODE_SYS_OID"; + public static final String CODE_SYS_VALUE_SET = "CODE_SYS_VALUE_SET"; + public static final String CODE_SYS_COMPLETE = "CODE_SYS_COMPLETE"; + public static final String CODE_SYS_NOTPRESENT = "CODE_SYS_NOTPRESENT"; + public static final String CODE_SYS_EXAMPLE = "CODE_SYS_EXAMPLE"; + public static final String CODE_SYS_FRAGMENT = "CODE_SYS_FRAGMENT"; + public static final String CODE_SYS_SUPPLEMENT = "CODE_SYS_SUPPLEMENT"; + public static final String CODE_SYS_CODE_NOT_HERE = "CODE_SYS_CODE_NOT_HERE"; + public static final String CODE_SYS_FOR_OID = "CODE_SYS_FOR_OID"; + public static final String CODE_SYS_THE_VALUE_SET = "CODE_SYS_THE_VALUE_SET"; + public static final String STRUC_DEF_NO_SUMMARY = "STRUC_DEF_NO_SUMMARY"; + public static final String STRUC_DEF_ELEMENT = "STRUC_DEF_ELEMENT"; + public static final String STRUC_DEF_STRUCTURES = "STRUC_DEF_STRUCTURES"; + public static final String STRUC_DEF_EXTENSIONS = "STRUC_DEF_EXTENSIONS"; + public static final String STRUC_DEF_SLIC = "STRUC_DEF_SLIC"; + public static final String STRUC_DEF_THIS_REFERS = "STRUC_DEF_THIS_REFERS"; + public static final String STRUC_DEF_REFERS_EXT = "STRUC_DEF_REFERS_EXT"; + public static final String STRUC_DEF_MATURITY = "STRUC_DEF_MATURITY"; + public static final String STRUC_DEF_MODIF = "STRUC_DEF_MODIF"; + public static final String STRUC_DEF_SNOMED_CT = "STRUC_DEF_SNOMED_CT"; + public static final String STRUC_DEF_TERM_BIND = "STRUC_DEF_TERM_BIND"; + public static final String STRUC_DEF_PATH = "STRUC_DEF_PATH"; + public static final String STRUC_DEF_TERM_BINDS = "STRUC_DEF_TERM_BINDS"; + public static final String STRUC_DEF_URI = "STRUC_DEF_URI"; + public static final String STRUC_DEF_MISSING_LINK = "STRUC_DEF_MISSING_LINK"; + public static final String STRUC_DEF_CONSTRAINTS = "STRUC_DEF_CONSTRAINTS"; + public static final String STRUC_DEF_GRADE = "STRUC_DEF_GRADE"; + public static final String STRUC_DEF_NO_MAPPINGS = "STRUC_DEF_NO_MAPPINGS"; + public static final String STRUC_DEF_ALL_MAP_KEY = "STRUC_DEF_ALL_MAP_KEY"; + public static final String STRUC_DEF_PROFILE_BUILDS = "STRUC_DEF_PROFILE_BUILDS"; + public static final String STRUC_DEF_DERIVED_PROFILE = "STRUC_DEF_DERIVED_PROFILE"; + public static final String STRUC_DEF_REFER_PROFILE = "STRUC_DEF_REFER_PROFILE"; + public static final String STRUC_DEF_MOD_ELEMENT = "STRUC_DEF_MOD_ELEMENT"; + public static final String STRUC_DEF_ELE_MUST_SUPP = "STRUC_DEF_ELE_MUST_SUPP"; + public static final String STRUC_DEF_ELE_INCLUDED = "STRUC_DEF_ELE_INCLUDED"; + public static final String STRUC_DEF_AFFECT_CONSTRAINTS = "STRUC_DEF_AFFECT_CONSTRAINTS"; + public static final String STRUC_DEF_CONFORMANCE = "STRUC_DEF_CONFORMANCE"; + public static final String STRUC_DEF_VALUESET_CODE = "STRUC_DEF_VALUESET_CODE"; + public static final String STRUC_DEF_VALUESET = "STRUC_DEF_VALUESET"; + public static final String STRUC_DEF_ID = "STRUC_DEF_ID"; + public static final String STRUC_DEF_PATHS = "STRUC_DEF_PATHS"; + public static final String STRUC_DEF_DETAILS = "STRUC_DEF_DETAILS"; + public static final String VALUE_SET_OID = "VALUE_SET_OID"; + public static final String VALUE_SET_OID_TERM_SYS = "VALUE_SET_OID_TERM_SYS"; + public static final String VALUE_SET_INCLUDED_INTO = "VALUE_SET_INCLUDED_INTO"; + public static final String VALUE_SET_EXCLUDED_FROM = "VALUE_SET_EXCLUDED_FROM"; + public static final String VALUE_SET_USED_ELSEWHERE = "VALUE_SET_USED_ELSEWHERE"; + public static final String TEXT_ICON_REFERENCE = "TEXT_ICON_REFERENCE"; + public static final String TEXT_ICON_PRIMITIVE = "TEXT_ICON_PRIMITIVE"; + public static final String TEXT_ICON_KEY = "TEXT_ICON_KEY"; + public static final String TEXT_ICON_DATATYPE = "TEXT_ICON_DATATYPE"; + public static final String TEXT_ICON_RESOURCE = "TEXT_ICON_RESOURCE"; + public static final String TEXT_ICON_ELEMENT = "TEXT_ICON_ELEMENT"; + public static final String TEXT_ICON_OBJECT_BOX = "TEXT_ICON_OBJECT_BOX"; + public static final String TEXT_ICON_REUSE = "TEXT_ICON_REUSE"; + public static final String TEXT_ICON_EXTENSION = "TEXT_ICON_EXTENSION"; + public static final String TEXT_ICON_CHOICE = "TEXT_ICON_CHOICE"; + public static final String TEXT_ICON_SLICE = "TEXT_ICON_SLICE"; + public static final String TEXT_ICON_SLICE_ITEM = "TEXT_ICON_SLICE_ITEM"; + public static final String TEXT_ICON_FIXED = "TEXT_ICON_FIXED"; + public static final String TEXT_ICON_EXTENSION_SIMPLE = "TEXT_ICON_EXTENSION_SIMPLE"; + public static final String TEXT_ICON_PROFILE = "TEXT_ICON_PROFILE"; + public static final String TEXT_ICON_EXTENSION_COMPLEX = "TEXT_ICON_EXTENSION_COMPLEX"; + public static final String MAP_DEFAULT_COMMENT = "MAP_DEFAULT_COMMENT"; + public static final String VS_ABSTRACT_CODE_HINT = "VS_ABSTRACT_CODE_HINT"; + public static final String REND_ROW_CHANGED_SINCE_WAS = "REND_ROW_CHANGED_SINCE_WAS"; + public static final String TERM_REND_COPY = "TERM_REND_COPY"; + public static final String TEST_PLAN_CASE = "TEST_PLAN_CASE"; + public static final String TEST_PLAN_CASE_SEQ = "TEST_PLAN_CASE_SEQ"; protected String getMessagesSourceFileName() { return "rendering-phrases"; } + +@Override + protected String typeOfString() { + return "phrase"; + } + + } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/HierarchicalTableGenerator.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/HierarchicalTableGenerator.java index 3aca67f43..7bd58dc38 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/HierarchicalTableGenerator.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/HierarchicalTableGenerator.java @@ -95,22 +95,22 @@ public class HierarchicalTableGenerator { XML, XHTML } - /*!#*/public static final String TEXT_ICON_REFERENCE = "Reference to another Resource"; - /*!#*/public static final String TEXT_ICON_PRIMITIVE = "Primitive Data Type"; - /*!#*/public static final String TEXT_ICON_KEY = "JSON Key Value"; - /*!#*/public static final String TEXT_ICON_DATATYPE = "Data Type"; - /*!#*/public static final String TEXT_ICON_RESOURCE = "Resource"; - /*!#*/public static final String TEXT_ICON_ELEMENT = "Element"; - /*!#*/public static final String TEXT_ICON_OBJECT_BOX = "Object"; - /*!#*/public static final String TEXT_ICON_REUSE = "Reference to another Element"; - /*!#*/public static final String TEXT_ICON_EXTENSION = "Extension"; - /*!#*/public static final String TEXT_ICON_CHOICE = "Choice of Types"; - /*!#*/public static final String TEXT_ICON_SLICE = "Slice Definition"; - /*!#*/public static final String TEXT_ICON_SLICE_ITEM = "Slice Item"; - /*!#*/public static final String TEXT_ICON_FIXED = "Fixed Value"; - /*!#*/public static final String TEXT_ICON_EXTENSION_SIMPLE = "Simple Extension"; - /*!#*/public static final String TEXT_ICON_PROFILE = "Profile"; - /*!#*/public static final String TEXT_ICON_EXTENSION_COMPLEX = "Complex Extension"; + public static final String TEXT_ICON_REFERENCE = "Reference to another Resource"; + public static final String TEXT_ICON_PRIMITIVE = "Primitive Data Type"; + public static final String TEXT_ICON_KEY = "JSON Key Value"; + public static final String TEXT_ICON_DATATYPE = "Data Type"; + public static final String TEXT_ICON_RESOURCE = "Resource"; + public static final String TEXT_ICON_ELEMENT = "Element"; + public static final String TEXT_ICON_OBJECT_BOX = "Object"; + public static final String TEXT_ICON_REUSE = "Reference to another Element"; + public static final String TEXT_ICON_EXTENSION = "Extension"; + public static final String TEXT_ICON_CHOICE = "Choice of Types"; + public static final String TEXT_ICON_SLICE = "Slice Definition"; + public static final String TEXT_ICON_SLICE_ITEM = "Slice Item"; + public static final String TEXT_ICON_FIXED = "Fixed Value"; + public static final String TEXT_ICON_EXTENSION_SIMPLE = "Simple Extension"; + public static final String TEXT_ICON_PROFILE = "Profile"; + public static final String TEXT_ICON_EXTENSION_COMPLEX = "Complex Extension"; public static final int NEW_REGULAR = 0; public static final int CONTINUE_REGULAR = 1; diff --git a/org.hl7.fhir.utilities/src/main/resources/Messages.properties b/org.hl7.fhir.utilities/src/main/resources/Messages.properties index ea7bc7cc9..8ccfd2e54 100644 --- a/org.hl7.fhir.utilities/src/main/resources/Messages.properties +++ b/org.hl7.fhir.utilities/src/main/resources/Messages.properties @@ -1120,7 +1120,7 @@ CODESYSTEM_PROPERTY_UNKNOWN_CODE = This property has only a code (''{0}'') and n CODESYSTEM_PROPERTY_KNOWN_CODE_SUGGESTIVE = This property has only the standard code (''{0}'') but not the standard URI ''{1}'', so it has no clearly defined meaning in the terminology ecosystem CODESYSTEM_PROPERTY_CODE_TYPE_MISMATCH = Wrong type ''{2}'': The code ''{0}'' identifies a property that has the type ''{1}'' CODESYSTEM_PROPERTY_UNDEFINED = The property ''{0}'' has no definition in CodeSystem.property. Many terminology tools won''t know what to do with it -CODESYSTEM_PROPERTY_NO_VALUE = The property ''{0}'' has no value, and cannot be understoof +CODESYSTEM_PROPERTY_NO_VALUE = The property ''{0}'' has no value, and cannot be understood CODESYSTEM_PROPERTY_WRONG_TYPE = The property ''{0}'' has the invalid type ''{1}'', when it is defined to have the type ''{2}'' CODESYSTEM_DESIGNATION_DISP_CLASH_NO_LANG = The designation ''{0}'' has no use and no language, so is not differentiated from the base display (''{1}'') CODESYSTEM_DESIGNATION_DISP_CLASH_LANG = The designation ''{0}'' has no use and is in the same language (''{2}''), so is not differentiated from the base display (''{1}'') @@ -1132,9 +1132,10 @@ VALUESET_BAD_FILTER_VALUE_DATETIME = The value for a filter based on property '' VALUESET_BAD_FILTER_VALUE_DECIMAL = The value for a filter based on property ''{0}'' must be a decimal value, not ''{1}'' VALUESET_BAD_FILTER_VALUE_INTEGER = The value for a filter based on property ''{0}'' must be integer value, not ''{1}'' VALUESET_BAD_FILTER_VALUE_VALID_CODE = The value for a filter based on property ''{0}'' must be a valid code from the system ''{2}'', and ''{1}'' is not ({3}) +VALUESET_BAD_FILTER_VALUE_VALID_CODE_CHANGE = The value for a filter based on property ''{0}'' must be a valid code from the system ''{2}'', and ''{1}'' is not ({3}). Note that this is change from the past; terminology servers are expected to still continue to support this filter VALUESET_BAD_FILTER_VALUE_CODED = The value for a filter based on property ''{0}'' must be in the format system(|version)#code, not ''{1}'' VALUESET_BAD_FILTER_VALUE_CODED_INVALID = The value for a filter based on property ''{0}'' is ''{1}'' which is not a valid code ({2}) -VALUESET_BAD_FILTER_OP = The operation ''{0}'' is not allowed for property ''{1}''. Allowed ops: {2} +VALUESET_BAD_FILTER_OP = The operation ''{0}'' is not allowed for property ''{1}'' in system ''{3}''. Allowed ops: {2} VALUESET_BAD_FILTER_VALUE_HAS_COMMA = The filter value has a comma, but the operation is different to 'in' and 'not-in', so the comma will be interpreted as part of the {0} value VALUESET_BAD_FILTER_VALUE_VALID_REGEX = The value for a filter based on property ''{0}'' should be a valid regex, not ''{1}'' (err = ''{2}'') VALUESET_BAD_PROPERTY_NO_REGEX = Cannot apply a regex filter to the property ''{0}'' (usually regex filters are applied to the codes, or a named property of the code system) @@ -1142,4 +1143,5 @@ CODESYSTEM_PROPERTY_CODE_WARNING = If the type is ''code'', then the valueSet pr SD_ELEMENT_FIXED_WRONG_TYPE = The base element has a fixed type of ''{0}'', so this element must have a fixed value of the same type, not ''{1}'' SD_ELEMENT_REASON_DERIVED = , because the value must match the fixed value define in ''{0}'' SD_ELEMENT_PATTERN_WRONG_TYPE = The base element has a pattern type of ''{0}'', so this element must have a pattern value of the same type, not ''{1}'' - +BINDING_ADDITIONAL = {0} specified in an additional binding +BINDING_MAX = {0} specified in the max binding diff --git a/org.hl7.fhir.utilities/src/main/resources/rendering-phrases.properties b/org.hl7.fhir.utilities/src/main/resources/rendering-phrases.properties index 6eeb52c2b..ffb4bc525 100644 --- a/org.hl7.fhir.utilities/src/main/resources/rendering-phrases.properties +++ b/org.hl7.fhir.utilities/src/main/resources/rendering-phrases.properties @@ -502,6 +502,9 @@ REND_ADDED = Added: REND_CHANGED = Changed: REND_REMOVED = Removed: REND_ROW_SINCE = This row of content has been added since {0} +REND_ROW_CHANGED_SINCE = This row of content has been changed since {0} +REND_ROW_CHANGED_SINCE_WAS = This row of content has been changed since {0} (was ''{1}'') +REND_ROW_REMOVED_SINCE = This content has been removed since {0} REQ_ACTOR = These requirements apply to the actor REQ_FOLLOWING_ACTOR = These requirements apply to the following actors: REQ_DERIVE = These requirements derive from @@ -620,7 +623,8 @@ VALUE_SET_SPEC_NAME = Fully specified name VALUE_SET_SYNONYM = Synonym VALUE_SET_COMMA = , VALUE_SET_WHERE_CODES = , where the codes are contained in -VALUE_SET_IMPORT = Import all the codes that are contained in +VALUE_SET_IMPORT_one = Import all the codes that are contained in +VALUE_SET_IMPORT_other = Import all the codes that are contained in the intersection of VALUE_SET_NOTE = Note: {0} VALUE_SET_ERROR = Error Expanding ValueSet: {0} VALUE_SET_NULL = null @@ -869,7 +873,7 @@ ADD_BIND_VALID_REQ = Validators will check this binding (strength = required) ADD_BIND_VALID_EXT = Validators will check this binding (strength = extensible) ADD_BIND_NEW_REC = New records are required to use this value set, but legacy records may use other codes ADD_BIND_RECOM_VALUE_SET = This is the value set that is recommended (documentation should explain why) -ADD_BIND_RECOMMENDED = Recommended +ADD_BIND_PREFERRED = Preferred ADD_BIND_REQUIRED = Required ADD_BIND_GIVEN_CONT = This value set is provided to user look up in a given context ADD_BIND_UI_BIND = UI Binding @@ -907,3 +911,156 @@ CAPABILITY_INT_SUMM = Interaction summary CAPABILITY_SEARCH_PARS = Search Parameters CAPABILITY_COMB_SEARCH_PARS = Combined Search Parameters CODE_SYS_IN_A_HIERARCHY = in a {0} hierarchy +CODE_SYS_REPLACED_BY = (replaced by +DATA_REND_ONGOING = (ongoing) +EXAMPLE_SCEN_UNABLE_TO_FIND = Unable to find referenced version {0} within instance {1} +EXAMPLE_SCEN_STEP_SCEN = Step {0} - See scenario\n {1} +DATA_REND_DETAILS_STATED = (Details: {0} code {1} {2} {3} ', stated as ' {4} {5} +DATA_REND_VERSION = (version = {0} {1} +DATA_REND_BASE64 = (base64 data - {0} bytes) +DATA_REND_CODES = Codes: +DATA_REND_GLN = Global Location Number +DATA_REND_DETAILS = (Details: {0} code +DATA_REND_PER = per +DATA_REND_EXCEPTION = Exception +DIAG_REP_REND_PER = Performer +DIAG_REP_REND_IDENTIFIER = Identifier +DIAG_REP_REND_REQUEST = Request +PROF_DRIV_GEN_NARR = Generated Narrative: {0} {1} +PROF_DRIV_ERR_GEN_NARR = Error Generating Narrative for +QUEST_UNKNOWN_MODE = Unknown QuestionnaireResponse Renderer Mode +QUEST_ANSWER = Answer +QUEST_RESP_ROOT = QuestionnaireResponseRoot +QUEST_RESP = QuestionnaireResponse +QUEST_QUESTION = Questionnaire: +QUEST_NONE_SPEC = None specified +QUEST_GROUP = Group +QUEST_ITEM = Item +QUEST_TRY_QUEST = Try this QuestionnaireResponse out: +QUEST_DISPLAY_CAT = Display Category +QUEST_NOT_DONE = Not done yet +RES_REND_VER = (version +RES_REND_VERSION = Version +RES_REND_UPDATED = Updated +RES_REND_LANGUAGE = (Language +RES_REND_SPEC_RULES = Special rules apply: +RES_REND_INFO_SOURCE = Information Source: +RES_REND_PROFILE = Profile +RES_REND_SECURITY_LABEL = Security Label +SEARCH_PAR_REND_RES = Resource +SEARCH_PAR_REND_TARGET = Target Resources +STRUC_DEF_REND_UNABLE_RES = Unable to resolve StructureDefinition {0} resolving content reference {1} +STRUC_DEF_CANT_FIND = getElementByName: can't find {0} in {1} from {2} +STRUC_DEF_ALL_SLICES = :All Slices +STRUC_DEF_ELE_AFFECTED = This element has or is affected by constraints ( {0} {1} +STRUC_DEF_STAND_STATUS = Standards Status = +STRUC_DEF_BLACK = black +STRUC_DEF_ABSTRACT = This is an abstract +STRUC_DEF_CHILD = Child +STRUC_DEF_SINGLE_JSON_OBJECTS = JSON: Represented as a single JSON Object with named properties using the value of the {0} child as the key +STRUC_DEF_TYPE_SPEC = Type Specifier +STRUC_DEF_CHOICE_DATA_TYPE = Choice of Data Types +STRUC_DEF_FURTHER_INFO = for further information about how to use [x] +STRUC_DEF_PRIM_TYPE_VALUE = This primitive type must have a value (the value must be present, and cannot be replaced by an extension) +STRUC_DEF_PRIM_TYPE_PRESENT = This primitive type may be present, or absent if replaced by one of the following extensions: +STRUC_DEF_PRIM_ELE = This primitive element may be present, or absent, or replaced by an extension +VALUE_SET_CODE_SELEC = This value set cannot be fully expanded, but a selection ( {0} codes) of the whole set of codes is shown here. +VALUE_SET_HAS = This value set has +VALUE_SET_CONTAINS = This value set contains +VALUE_SET_AT_LEAST = at least +VALUE_SET_NUMBER_CONCEPTS = This value set expansion contains {0} concepts. +VALUE_SET_VERSION = version +VALUE_SET_NO_VERSION = (no version) ( +VALUE_SET_NO_VER = (no version) +VALUE_SET_ALL_CODES_DEF = all codes defined in +VALUE_SET_THESE_CODES_DEF = these codes as defined in +VALUE_SET_CODES_FROM = codes from +VALUE_SET_WHERE = where +VALUE_SET_AND = and +VALUE_SET_DOESNT_EXIST = doesn't exist +VALUE_SET_SNOMED_ADD = SNOMED CT {0} edition {1} +VALUE_SET_SNOMED = SNOMED CT {0} edition +VALUE_SET_LOINCV = Loinc v +CANON_REND_URL = Defining URL +CANON_REND_VER = Version +CANON_REND_NAME = Name +CANON_REND_TITLE = Title +CANON_REND_STATUS = Status +CANON_REND_DEFINITION = Definition +CANON_REND_PUBLISHER = Publisher +CANON_REND_COMMITTEE = Committee +CANON_REND_COPYRIGHT = Copyright +CANON_REND_MATURITY = Maturity +CANON_REND_SOURCE_RES = Source Resource +CANON_REND_XML = XML +CANON_REND_JSON = JSON +CANON_REND_TURTLE = Turtle +CODE_SYS_CONTENT = Content +CODE_SYS_OID = OID +CODE_SYS_VALUE_SET = Value Set +CODE_SYS_COMPLETE = All the concepts defined by the code system are included in the code system resource +CODE_SYS_NOTPRESENT = None of the concepts defined by the code system are included in the code system resource +CODE_SYS_EXAMPLE = A few representative concepts are included in the code system resource +CODE_SYS_FRAGMENT = A subset of the code system concepts are included in the code system resource +CODE_SYS_SUPPLEMENT = This code system resource is a supplement to +CODE_SYS_CODE_NOT_HERE = This CodeSystem is not used here; it may be used elsewhere (e.g. specifications and/or implementations that use this content) +CODE_SYS_FOR_OID = for OID based terminology systems +CODE_SYS_THE_VALUE_SET = is the value set for all codes in this code system +STRUC_DEF_NO_SUMMARY = No Summary, as this profile has no differential +STRUC_DEF_ELEMENT = element +STRUC_DEF_STRUCTURES = Structures +STRUC_DEF_EXTENSIONS = Extensions +STRUC_DEF_SLIC = Slices +STRUC_DEF_THIS_REFERS = This structure refers to these other structures +STRUC_DEF_REFERS_EXT = This structure refers to these extensions +STRUC_DEF_MATURITY = Maturity +STRUC_DEF_MODIF = Modifier +STRUC_DEF_SNOMED_CT = SNOMED CT +STRUC_DEF_TERM_BIND = Terminology Bindings (Differential) +STRUC_DEF_PATH = Path +STRUC_DEF_TERM_BINDS = Terminology Bindings +STRUC_DEF_URI = URI +STRUC_DEF_MISSING_LINK = missing link +STRUC_DEF_CONSTRAINTS = Constraints +STRUC_DEF_GRADE = Grade +STRUC_DEF_NO_MAPPINGS = No Mappings +STRUC_DEF_ALL_MAP_KEY = All Mappings are Empty +STRUC_DEF_PROFILE_BUILDS = This profile builds on +STRUC_DEF_DERIVED_PROFILE = In this IG, the following structures are derived from this profile: +STRUC_DEF_REFER_PROFILE = In this IG, the following structures refer to this profile: +STRUC_DEF_MOD_ELEMENT = This element is a modifier element +STRUC_DEF_ELE_MUST_SUPP = This element must be supported +STRUC_DEF_ELE_INCLUDED = This element is included in summaries +STRUC_DEF_AFFECT_CONSTRAINTS = "This element has or is affected by constraints ( +STRUC_DEF_CONFORMANCE = Conformance +STRUC_DEF_VALUESET_CODE = ValueSet / Code +STRUC_DEF_VALUESET = ValueSet +STRUC_DEF_ID = Id +STRUC_DEF_PATHS = Path(s) +STRUC_DEF_DETAILS = Details +VALUE_SET_OID = OID +VALUE_SET_OID_TERM_SYS = for OID based terminology systems +VALUE_SET_INCLUDED_INTO = Included into +VALUE_SET_EXCLUDED_FROM = Excluded from +VALUE_SET_USED_ELSEWHERE = This value set is not used here; it may be used elsewhere (e.g. specifications and/or implementations that use this content) +TEXT_ICON_REFERENCE = Reference to another Resource +TEXT_ICON_PRIMITIVE = Primitive Data Type +TEXT_ICON_KEY = JSON Key Value +TEXT_ICON_DATATYPE = Data Type +TEXT_ICON_RESOURCE = Resource +TEXT_ICON_ELEMENT = Element +TEXT_ICON_OBJECT_BOX = Object +TEXT_ICON_REUSE = Reference to another Element +TEXT_ICON_EXTENSION = Extension +TEXT_ICON_CHOICE = Choice of Types +TEXT_ICON_SLICE = Slice Definition +TEXT_ICON_SLICE_ITEM = Slice Item +TEXT_ICON_FIXED = Fixed Value +TEXT_ICON_EXTENSION_SIMPLE = Simple Extension +TEXT_ICON_PROFILE = Profile +TEXT_ICON_EXTENSION_COMPLEX = Complex Extension +MAP_DEFAULT_COMMENT = This element was not defined prior to R5 +VS_ABSTRACT_CODE_HINT = This code is not selectable ('Abstract') +TERM_REND_COPY = Copy {0} Format to clipboard +TEST_PLAN_CASE = Test Case +TEST_PLAN_CASE_SEQ = Test Case - Sequence {0} diff --git a/org.hl7.fhir.utilities/src/main/resources/rendering-phrases_fr.properties b/org.hl7.fhir.utilities/src/main/resources/rendering-phrases_fr.properties deleted file mode 100644 index 8ef8c925f..000000000 --- a/org.hl7.fhir.utilities/src/main/resources/rendering-phrases_fr.properties +++ /dev/null @@ -1,149 +0,0 @@ -# Rendering -BUNDLE_HEADER_ROOT = XXXX -BUNDLE_HEADER_ENTRY = XXXX -BUNDLE_HEADER_ENTRY_URL = XXXX -BUNDLE_RESOURCE = XXXX -BUNDLE_SEARCH = XXXX -BUNDLE_SEARCH_MODE = XXXX -BUNDLE_SEARCH_SCORE = XXXX -BUNDLE_RESPONSE = XXXX -BUNDLE_LOCATION = XXXX -BUNDLE_ETAG = XXXX -BUNDLE_LAST_MOD = XXXX -BUNDLE_REQUEST = XXXX -BUNDLE_IF_NON_MATCH = XXXX -BUNDLE_IF_MOD = XXXX -BUNDLE_IF_MATCH = XXXX -BUNDLE_IF_NONE = XXXX -CODEPROP_CODE = XXXX -CODESYSTEM_PROPS = XXXX -CODESYSTEM_CONCEPTS = XXXX -CODESYSTEM_DEPRECATED = XXXX -CODESYSTEM_DESC = XXXX -CODESYSTEM_FILTERS = XXXX -CODESYSTEM_FILTER_CODE = XXXX -CODESYSTEM_FILTER_OP = XXXX -CODESYSTEM_FILTER_VALUE = XXXX -CODESYSTEM_PROP_CODE = XXXX -CODESYSTEM_PROP_NAME = XXXX -CODESYSTEM_PROP_URI = XXXX -CODESYSTEM_PROP_DESC = XXXX -CODESYSTEM_PROP_TYPE = XXXX -CODESYSTEM_PROPS_DESC = XXXX -CODESYSTEM_CONTENT_COMPLETE ThXXXX -CODESYSTEM_CONTENT_EXAMPLE = XXXX -CODESYSTEM_CONTENT_FRAGMENT = XXXX -CODESYSTEM_CONTENT_NOTPRESENT = XXXX -CODESYSTEM_CONTENT_SUPPLEMENT = XXXX -RESOURCE_COPYRIGHT = XXXX -SD_COMP_HEAD_CARD_L = XXXX -SD_COMP_HEAD_CARD_L_DESC =XXXX -SD_COMP_HEAD_CARD_R = XXXX -SD_COMP_HEAD_CARD_R_DESC =XXXX -SD_COMP_HEAD_COMP = XXXX -SD_COMP_HEAD_COMP_DESC = XXXX -SD_COMP_HEAD_DESC_L = XXXX -SD_COMP_HEAD_DESC_L_DESC =XXXX -SD_COMP_HEAD_DESC_R = XXXX -SD_COMP_HEAD_DESC_R_DESC =XXXX -SD_COMP_HEAD_FLAGS_L = XXXX -SD_COMP_HEAD_FLAGS_L_DESC =XXXX -SD_COMP_HEAD_FLAGS_R = XXXX -SD_COMP_HEAD_FLAGS_R_DESC =XXXX -SD_COMP_HEAD_NAME = XXXX -SD_COMP_HEAD_NAME_DESC = XXXX -SD_COMP_HEAD_TYPE_L = XXXX -SD_COMP_HEAD_TYPE_L_DESC =XXXX -SD_COMP_HEAD_TYPE_R = XXXX -SD_COMP_HEAD_TYPE_R_DESC =XXXX -SD_DOCO = XXXX -SD_GRID_HEAD_CARD = XXXX -SD_GRID_HEAD_CARD_DESC = XXXX -SD_GRID_HEAD_DESC = XXXX -SD_GRID_HEAD_DESC_DESC = XXXX -SD_GRID_HEAD_NAME = XXXX -SD_GRID_HEAD_NAME_DESC = XXXX -SD_GRID_HEAD_TYPE = XXXX -SD_GRID_HEAD_TYPE_DESC = XXXX -SD_HEAD_CARD = XXXX -SD_HEAD_CARD_DESC = XXXX -SD_HEAD_DESC = XXXX -SD_HEAD_DESC_DESC = XXXX -SD_HEAD_FLAGS_DESC = XXXX -SD_HEAD_NAME = XXXX -SD_HEAD_SC = XXXX -SD_HEAD_TYPE = XXXX -SD_HEAD_TYPE_DESC = XXXX -SD_LEGEND = XXXX -SD_SUMMARY = XXXX -SD_SUMMARY_MAPPINGS = XXXX -SD_SUMMARY_MISSING_EXTENSION = XXXX -SD_SUMMARY_MISSING_PROFILE = XXXX -SD_SUMMARY_PUBLICATION = XXXX -SD_SUMMARY_SLICES = XXXX -SD_SUMMARY_SLICE_NONE = XXXX -SD_SUMMARY_SLICE_one = XXXX -SD_SUMMARY_SLICE_other = XXXX -SD_SUMMARY_MANDATORY = XXXX -SD_SUMMARY_MUST_SUPPORT = XXXX -SD_SUMMARY_FIXED = XXXX -SD_SUMMARY_INFO = XXXX -SD_SUMMARY_PROHIBITED = XXXX -SD_SUMMARY_NESTED_MANDATORY = XXXX -TX_CODE = XXXX -TX_COMMENTS = XXXX -TX_DEFINITION = XXXX -TX_DEPRECATED = XXXX -TX_DISPLAY = XXXX -TX_VERSION = XXXX -PAT_NO_GENDER = XXXX -PAT_GENDER = XXXX -PAT_NO_DOB = XXXX -PAT_DOB = XXXX -PAT_NO_NAME = XXXX -PAT_CONTAINED_one = XXXX -PAT_CONTAINED_other = XXXX -PAT_OTHER_ID_one = XXXX -PAT_OTHER_ID_other = XXXX -PAT_OTHER_ID_HINT_one = XXXX -PAT_OTHER_ID_HINT_other = XXXX -PAT_LANG_one = XXXX -PAT_LANG_other = XXXX -PAT_LANG_HINT_one = XXXX -PAT_LANG_HINT_other = XXXX -PAT_LANG_PREFERRED = XXXX -PAT_GP = XXXX -PAT_MO = XXXX -PAT_LINKS = XXXX -PAT_LINKS_HINT = XXXX -PAT_LINK_REPLBY = XXXX -PAT_LINK_REPL = XXXX -PAT_LINK_REFER = XXXX -PAT_LINK_SEE = XXXX -PAT_NOM_CONTACT = XXXX -PAT_NOK_CONTACT = XXXX -PAT_NOK_CONTACT_HINT = XXXX -PAT_RELN = XXXX -PAT_ORG = XXXX -PAT_PERIOD = XXXX -PAT_ALT_NAME = XXXX -PAT_ALT_NAME_HINT = XXXX -PAT_CONTACT = XXXX -PAT_CONTACT_HINT = XXXX -PAT_ACTIVE = XXXX -PAT_ACTIVE_HINT = XXXX -PAT_DECEASED = XXXX -PAT_DECEASED_HINT = XXXX -PAT_MARITAL = XXXX -PAT_MARITAL_HINT = XXXX -PAT_MUL_BIRTH = XXXX -PAT_MUL_BIRTH_HINT = XXXX -PAT_PHOTO = XXXX -SD_HEAD_NAME_DESC = XXXX -SD_HEAD_FLAGS = XXXX -SD_SLICING_INFO = XXX -BUNDLE_DOCUMENT_CONTENT = XXXX -BUNDLE_HEADER_DOC_ENTRY_URD = XXXX -BUNDLE_HEADER_DOC_ENTRY_U = XXXX -BUNDLE_HEADER_DOC_ENTRY_RD = XXXX - \ No newline at end of file diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java index 9e88c6b4c..1701bc162 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/BaseValidator.java @@ -109,6 +109,9 @@ public class BaseValidator implements IValidationContextResourceLoader { public void see(boolean ok) { value = value && ok; } + public void set(boolean value) { + this.value = value; + } } @@ -1614,4 +1617,39 @@ public class BaseValidator implements IValidationContextResourceLoader { } + protected boolean isKnownUsage(UsageContext usage) { + for (UsageContext t : usageContexts) { + if (usagesMatch(usage, t)) { + return true; + } + } + return false; + } + + private boolean usagesMatch(UsageContext usage, UsageContext t) { + if (usage.hasCode() && t.hasCode() && usage.hasValue() && t.hasValue()) { + if (usage.getCode().matches(t.getCode())) { + if (usage.getValue().fhirType().equals(t.getValue().fhirType())) { + switch (usage.getValue().fhirType()) { + case "CodeableConcept": + for (Coding uc : usage.getValueCodeableConcept().getCoding()) { + for (Coding tc : t.getValueCodeableConcept().getCoding()) { + if (uc.matches(tc)) { + return true; + } + } + } + case "Quantity": + return false; // for now + case "Range": + return false; // for now + case "Reference": + return false; // for now + } + } + } + } + return false; + } + } \ No newline at end of file diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/BCP47Checker.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/BCP47Checker.java new file mode 100644 index 000000000..9049f4544 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/BCP47Checker.java @@ -0,0 +1,39 @@ +package org.hl7.fhir.validation.codesystem; + +import java.util.EnumSet; +import java.util.List; + +import org.hl7.fhir.r5.context.IWorkerContext; +import org.hl7.fhir.r5.utils.XVerExtensionManager; +import org.hl7.fhir.utilities.validation.ValidationMessage; +import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyOperation; +import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyValidationRules; + +public class BCP47Checker extends CodeSystemChecker { + + public BCP47Checker(IWorkerContext context, XVerExtensionManager xverManager, boolean debug, List errors) { + super(context, xverManager, debug, errors); + } + + + @Override + public void listPropertyNames(List knownNames) { + super.listPropertyNames(knownNames); + addName(knownNames, "language"); + addName(knownNames, "region"); + addName(knownNames, "script"); + addName(knownNames, "variant"); + addName(knownNames, "extension"); + addName(knownNames, "ext-lang"); + addName(knownNames, "private-use"); + } + + + @Override + public PropertyValidationRules rulesForFilter(String property, EnumSet ops) { + // TODO Auto-generated method stub + return super.rulesForFilter(property, ops); + } + + +} diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/CPTChecker.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/CPTChecker.java new file mode 100644 index 000000000..07a0d9235 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/CPTChecker.java @@ -0,0 +1,46 @@ +package org.hl7.fhir.validation.codesystem; + +import java.util.EnumSet; +import java.util.List; + +import org.hl7.fhir.r5.context.IWorkerContext; +import org.hl7.fhir.r5.model.CodeSystem.CodeSystemFilterComponent; +import org.hl7.fhir.r5.model.CodeSystem.PropertyComponent; +import org.hl7.fhir.r5.utils.XVerExtensionManager; +import org.hl7.fhir.utilities.validation.ValidationMessage; +import org.hl7.fhir.validation.instance.type.ValueSetValidator.CodeValidationRule; +import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyFilterType; +import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyOperation; +import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyValidationRules; + +public class CPTChecker extends CodeSystemChecker { + + public CPTChecker(IWorkerContext context, XVerExtensionManager xverManager, boolean debug, List errors) { + super(context, xverManager, debug, errors); + } + + @Override + public void listPropertyNames(List knownNames) { + super.listPropertyNames(knownNames); + addName(knownNames, "modifier"); + addName(knownNames, "kind"); + addName(knownNames, "modified"); + addName(knownNames, "code"); + addName(knownNames, "telemedicine"); + addName(knownNames, "orthopox"); + } + + @Override + public PropertyValidationRules rulesForFilter(String property, EnumSet ops) { + switch (property) { + case "modifier": return new PropertyValidationRules(PropertyFilterType.Boolean, null, ops); + case "kind" : return new PropertyValidationRules(PropertyFilterType.Code, CodeValidationRule.None, ops); // for now + case "modified": return new PropertyValidationRules(PropertyFilterType.Boolean, null, ops); + case "code" : return null; + case "telemedicine": return new PropertyValidationRules(PropertyFilterType.Boolean, null, ops); + case "orthopox" : return new PropertyValidationRules(PropertyFilterType.Boolean,null, ops); + } + return null; + } + +} diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/CodeSystemBasedChecker.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/CodeSystemBasedChecker.java new file mode 100644 index 000000000..a55bf7048 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/CodeSystemBasedChecker.java @@ -0,0 +1,97 @@ +package org.hl7.fhir.validation.codesystem; + +import java.util.EnumSet; +import java.util.List; + +import org.hl7.fhir.r5.context.IWorkerContext; +import org.hl7.fhir.r5.model.CodeSystem; +import org.hl7.fhir.r5.model.Enumeration; +import org.hl7.fhir.r5.model.CodeSystem.CodeSystemFilterComponent; +import org.hl7.fhir.r5.model.CodeSystem.PropertyComponent; +import org.hl7.fhir.r5.model.Enumerations.FilterOperator; +import org.hl7.fhir.r5.utils.XVerExtensionManager; +import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.utilities.validation.ValidationMessage; +import org.hl7.fhir.validation.instance.type.ValueSetValidator.CodeValidationRule; +import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyFilterType; +import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyOperation; +import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyValidationRules; + +public class CodeSystemBasedChecker extends CodeSystemChecker { + + private CodeSystem cs; + + public CodeSystemBasedChecker(IWorkerContext context, XVerExtensionManager xverManager, boolean debug, List errors, CodeSystem cs) { + super(context, xverManager, debug, errors); + this.cs = cs; + } + + @Override + public void listPropertyNames(List knownNames) { + super.listPropertyNames(knownNames); + if (cs.hasHierarchyMeaning()) { + knownNames.add("parent"); + knownNames.add("child"); + knownNames.add("partOf"); + } + for (CodeSystemFilterComponent f : cs.getFilter()) { + addName(knownNames, f.getCode()); + } + for (PropertyComponent p : cs.getProperty()) { + addName(knownNames, p.getCode()); + } + } + + @Override + public PropertyValidationRules rulesForFilter(String property, EnumSet ops) { + + for (CodeSystemFilterComponent f : cs.getFilter()) { + if (property.equals(f.getCode())) { + for (Enumeration op : f.getOperator()) { + ops.add(toOp(op)); + } + } + } + + for (PropertyComponent p : cs.getProperty()) { + if (property.equals(p.getCode())) { + if (p.getType() != null) { + switch (p.getType()) { + case BOOLEAN: return new PropertyValidationRules(PropertyFilterType.Boolean, null, ops); + case CODE: + // the definitions say " a code that identifies a concept defined in the code system" -> ValidCode. + // but many people have ignored that and defined a property as 'code' because it's from a list of values that are otherwise undefined + boolean external = !forPublication || cs.getWebPath() == null || Utilities.isAbsoluteUrl(cs.getWebPath()); + return new PropertyValidationRules(PropertyFilterType.Code, external ? CodeValidationRule.Warning : CodeValidationRule.Error, ops); // valid code... the definitions say that, but people were missing that in the pastm + case CODING: return new PropertyValidationRules(PropertyFilterType.Coding, null, ops); + case DATETIME: return new PropertyValidationRules(PropertyFilterType.DateTime, null, ops); + case DECIMAL: return new PropertyValidationRules(PropertyFilterType.Decimal, null, ops); + case INTEGER: return new PropertyValidationRules(PropertyFilterType.Integer, null, ops); + case STRING: return null; + } + } + } + } + + return super.rulesForFilter(property, ops); + } + + + private PropertyOperation toOp(Enumeration op) { + switch (op.getValue()) { + case CHILDOF: return PropertyOperation.ChildOf; + case DESCENDENTLEAF: return PropertyOperation.DescendentLeaf; + case DESCENDENTOF: return PropertyOperation.DescendentOf; + case EQUAL: return PropertyOperation.Equals; + case EXISTS: return PropertyOperation.Exists; + case GENERALIZES: return PropertyOperation.Generalizes; + case IN: return PropertyOperation.In; + case ISA: return PropertyOperation.IsA; + case ISNOTA: return PropertyOperation.IsNotA; + case NOTIN: return PropertyOperation.NotIn; + case REGEX: return PropertyOperation.RegEx; + default: return null; + } + } + +} diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/CodeSystemChecker.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/CodeSystemChecker.java index 9417547bb..9508896c3 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/CodeSystemChecker.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/CodeSystemChecker.java @@ -1,5 +1,6 @@ package org.hl7.fhir.validation.codesystem; +import java.util.EnumSet; import java.util.List; import org.hl7.fhir.r5.context.IWorkerContext; @@ -10,9 +11,13 @@ import org.hl7.fhir.utilities.i18n.I18nConstants; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; import org.hl7.fhir.validation.BaseValidator; +import org.hl7.fhir.validation.instance.type.ValueSetValidator.CodeValidationRule; +import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyFilterType; +import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyOperation; +import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyValidationRules; import org.hl7.fhir.validation.instance.utils.NodeStack; -public class CodeSystemChecker extends BaseValidator { +public abstract class CodeSystemChecker extends BaseValidator { private boolean noDisplay = false; private boolean hasDisplay = false; @@ -33,6 +38,59 @@ public class CodeSystemChecker extends BaseValidator { public void finish(Element inc, NodeStack stack) { hint(errors, "2023-07-21", IssueType.BUSINESSRULE, inc.line(), inc.col(), stack.getLiteralPath(), !(noDisplay && hasDisplay), I18nConstants.VALUESET_CONCEPT_DISPLAY_PRESENCE_MIXED); + } + + /** + * these are true in all code systems + * + * @param knownNames + */ + public void listPropertyNames(List knownNames) { + knownNames.add("concept"); + knownNames.add("code"); + knownNames.add("status"); + knownNames.add("inactive"); + knownNames.add("effectiveDate"); + knownNames.add("deprecationDate"); + knownNames.add("retirementDate"); + knownNames.add("notSelectable"); + knownNames.add("synonym"); + knownNames.add("comment"); + knownNames.add("itemWeight"); } + + protected void addName(List knownNames, String code) { + if (code != null && !knownNames.contains(code)) { + knownNames.add(code); + } + } + + protected EnumSet addToOps(EnumSet set, PropertyOperation... ops) { + for (PropertyOperation op : ops) { + set.add(op); + } + return set; + } + + public PropertyValidationRules rulesForFilter(String property, EnumSet ops) { + switch (property) { + case "concept" : return new PropertyValidationRules(PropertyFilterType.Code, CodeValidationRule.Error, addToOps(ops, PropertyOperation.Equals, PropertyOperation.In, PropertyOperation.IsA, PropertyOperation.DescendentOf, PropertyOperation.DescendentLeaf, PropertyOperation.IsNotA, PropertyOperation.NotIn)); + case "code" : return new PropertyValidationRules(PropertyFilterType.Code, CodeValidationRule.Error, addToOps(ops, PropertyOperation.Equals, PropertyOperation.RegEx)); + case "status" : return new PropertyValidationRules(PropertyFilterType.Code, CodeValidationRule.None, ops); + case "inactive" : return new PropertyValidationRules(PropertyFilterType.Boolean,null, ops); + case "effectiveDate" : return new PropertyValidationRules(PropertyFilterType.DateTime, null, ops); + case "deprecationDate" : return new PropertyValidationRules(PropertyFilterType.DateTime, null, ops); + case "retirementDate" : return new PropertyValidationRules(PropertyFilterType.DateTime, null, ops); + case "notSelectable" : return new PropertyValidationRules(PropertyFilterType.Boolean, null, ops); + case "parent" : return new PropertyValidationRules(PropertyFilterType.Code, CodeValidationRule.Error, ops); + case "child" : return new PropertyValidationRules(PropertyFilterType.Code, CodeValidationRule.Error, ops); + case "partOf" : return new PropertyValidationRules(PropertyFilterType.Code, CodeValidationRule.Error, ops); + case "synonym" : return new PropertyValidationRules(PropertyFilterType.Code, CodeValidationRule.None, ops); // ? none? + case "comment" : return null; + case "itemWeight" : return new PropertyValidationRules(PropertyFilterType.Decimal, null, ops); + } + return null; + } + } \ No newline at end of file diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/GeneralCodeSystemChecker.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/GeneralCodeSystemChecker.java index d8ea86f15..a314eea22 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/GeneralCodeSystemChecker.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/GeneralCodeSystemChecker.java @@ -8,8 +8,7 @@ import org.hl7.fhir.utilities.validation.ValidationMessage; public class GeneralCodeSystemChecker extends CodeSystemChecker { - public GeneralCodeSystemChecker(IWorkerContext context, XVerExtensionManager xverManager, boolean debug, - List errors) { + public GeneralCodeSystemChecker(IWorkerContext context, XVerExtensionManager xverManager, boolean debug, List errors) { super(context, xverManager, debug, errors); // TODO Auto-generated constructor stub } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/LoincChecker.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/LoincChecker.java new file mode 100644 index 000000000..0618af6b2 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/LoincChecker.java @@ -0,0 +1,220 @@ +package org.hl7.fhir.validation.codesystem; + +import java.util.EnumSet; +import java.util.List; + +import org.hl7.fhir.r5.context.IWorkerContext; +import org.hl7.fhir.r5.utils.XVerExtensionManager; +import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.utilities.validation.ValidationMessage; +import org.hl7.fhir.validation.instance.type.ValueSetValidator.CodeValidationRule; +import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyFilterType; +import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyOperation; +import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyValidationRules; + +public class LoincChecker extends CodeSystemChecker { + + public LoincChecker(IWorkerContext context, XVerExtensionManager xverManager, boolean debug, List errors) { + super(context, xverManager, debug, errors); + } + + + @Override + public void listPropertyNames(List knownNames) { + super.listPropertyNames(knownNames); + addName(knownNames, "concept"); + addName(knownNames, "ancestor"); + addName(knownNames, "descendent"); + addName(knownNames, "parent"); + addName(knownNames, "child"); + addName(knownNames, "COMPONENT"); + addName(knownNames, "PROPERTY"); + addName(knownNames, "TIME_ASPCT"); + addName(knownNames, "SYSTEM"); + addName(knownNames, "SCALE_TYP"); + addName(knownNames, "METHOD_TYP"); + addName(knownNames, "CLASS"); + addName(knownNames, "VersionLastChanged"); + addName(knownNames, "CHNG_TYPE"); + addName(knownNames, "DefinitionDescription"); + addName(knownNames, "STATUS"); + addName(knownNames, "CLASSTYPE"); + addName(knownNames, "FORMULA"); + addName(knownNames, "EXMPL_ANSWERS"); + addName(knownNames, "SURVEY_QUEST_TEXT"); + addName(knownNames, "SURVEY_QUEST_SRC"); + addName(knownNames, "UNITSREQUIRED"); + addName(knownNames, "ORDER_OBS"); + addName(knownNames, "HL7_FIELD_SUBFIELD_ID"); + addName(knownNames, "EXTERNAL_COPYRIGHT_NOTICE"); + addName(knownNames, "EXAMPLE_UNITS"); + addName(knownNames, "EXAMPLE_UCUM_UNITS"); + addName(knownNames, "STATUS_REASON"); + addName(knownNames, "STATUS_TEXT"); + addName(knownNames, "CHANGE_REASON_PUBLIC"); + addName(knownNames, "COMMON_TEST_RANK"); + addName(knownNames, "COMMON_ORDER_RANK"); + addName(knownNames, "HL7_ATTACHMENT_STRUCTURE"); + addName(knownNames, "EXTERNAL_COPYRIGHT_LINK"); + addName(knownNames, "PanelType"); + addName(knownNames, "AskAtOrderEntry"); + addName(knownNames, "AssociatedObservations"); + addName(knownNames, "VersionFirstReleased"); + addName(knownNames, "ValidHL7AttachmentRequest"); + addName(knownNames, "answer-list"); + addName(knownNames, "MAP_TO"); + addName(knownNames, "analyte"); + addName(knownNames, "analyte-core"); + addName(knownNames, "analyte-suffix"); + addName(knownNames, "analyte-numerator"); + addName(knownNames, "analyte-divisor"); + addName(knownNames, "analyte-divisor-suffix"); + addName(knownNames, "challenge"); + addName(knownNames, "adjustment"); + addName(knownNames, "count"); + addName(knownNames, "time-core"); + addName(knownNames, "time-modifier"); + addName(knownNames, "system-core"); + addName(knownNames, "super-system"); + addName(knownNames, "analyte-gene"); + addName(knownNames, "category"); + addName(knownNames, "search"); + addName(knownNames, "rad-modality-modality-type"); + addName(knownNames, "rad-modality-modality-subtype"); + addName(knownNames, "rad-anatomic-location-region-imaged"); + addName(knownNames, "rad-anatomic-location-imaging-focus"); + addName(knownNames, "rad-anatomic-location-laterality-presence"); + addName(knownNames, "rad-anatomic-location-laterality"); + addName(knownNames, "rad-view-aggregation"); + addName(knownNames, "rad-view-view-type"); + addName(knownNames, "rad-maneuver-maneuver-type"); + addName(knownNames, "rad-timing"); + addName(knownNames, "rad-pharmaceutical-substance-given"); + addName(knownNames, "rad-pharmaceutical-route"); + addName(knownNames, "rad-reason-for-exam"); + addName(knownNames, "rad-guidance-for-presence"); + addName(knownNames, "rad-guidance-for-approach"); + addName(knownNames, "rad-guidance-for-action"); + addName(knownNames, "rad-guidance-for-object"); + addName(knownNames, "rad-subject"); + addName(knownNames, "document-kind"); + addName(knownNames, "document-role"); + addName(knownNames, "document-setting"); + addName(knownNames, "document-subject-matter-domain"); + addName(knownNames, "document-type-of-service"); + addName(knownNames, "answers-for"); + addName(knownNames, "answer"); + addName(knownNames, "answer-list"); + + } + + @Override + public PropertyValidationRules rulesForFilter(String property, EnumSet ops) { + if (Utilities.existsInList(property, + "ancestor", + "descendent", + "parent", + "child", + "COMPONENT", + "PROPERTY", + "TIME_ASPCT", + "SYSTEM", + "SCALE_TYP", + "METHOD_TYP", + "CLASS", + "answer-list", + "MAP_TO", + "analyte", + "analyte-core", + "analyte-suffix", + "analyte-numerator", + "analyte-divisor", + "analyte-divisor-suffix", + "challenge", + "adjustment", + "count", + "time-core", + "time-modifier", + "system-core", + "super-system", + "analyte-gene", + "category", + "search", + "rad-modality-modality-type", + "rad-modality-modality-subtype", + "rad-anatomic-location-region-imaged", + "rad-anatomic-location-imaging-focus", + "rad-anatomic-location-laterality-presence", + "rad-anatomic-location-laterality", + "rad-view-aggregation", + "rad-view-view-type", + "rad-maneuver-maneuver-type", + "rad-timing", + "rad-pharmaceutical-substance-given", + "rad-pharmaceutical-route", + "rad-reason-for-exam", + "rad-guidance-for-presence", + "rad-guidance-for-approach", + "rad-guidance-for-action", + "rad-guidance-for-object", + "rad-subject", + "document-kind", + "document-role", + "document-setting", + "document-subject-matter-domain", + "document-type-of-service", + "answers-for", + "answer", + "answer-list")) { + return new PropertyValidationRules(PropertyFilterType.Code, CodeValidationRule.Error, addToOps(ops, PropertyOperation.Equals, PropertyOperation.Exists, PropertyOperation.RegEx, PropertyOperation.In, PropertyOperation.NotIn)).setChange(true); + } + + if (Utilities.existsInList(property, + "VersionLastChanged", + "CHNG_TYPE", + "DefinitionDescription", + "STATUS", + "CLASSTYPE", + "FORMULA", + "EXMPL_ANSWERS", + "SURVEY_QUEST_TEXT", + "SURVEY_QUEST_SRC", + "UNITSREQUIRED", + "ORDER_OBS", + "HL7_FIELD_SUBFIELD_ID", + "EXTERNAL_COPYRIGHT_NOTICE", + "EXAMPLE_UNITS", + "EXAMPLE_UCUM_UNITS", + "STATUS_REASON", + "STATUS_TEXT", + "CHANGE_REASON_PUBLIC", + "COMMON_TEST_RANK", + "COMMON_ORDER_RANK", + "HL7_ATTACHMENT_STRUCTURE", + "EXTERNAL_COPYRIGHT_LINK", + "PanelType", + "AskAtOrderEntry", + "AssociatedObservations", + "VersionFirstReleased", + "ValidHL7AttachmentRequest")) { + return new PropertyValidationRules(PropertyFilterType.String, CodeValidationRule.None, addToOps(ops, PropertyOperation.Equals, PropertyOperation.Exists, PropertyOperation.RegEx, PropertyOperation.In, PropertyOperation.NotIn)); + } + + if (Utilities.existsInList(property, + "STATUS")) { + return new PropertyValidationRules(PropertyFilterType.CodeList, CodeValidationRule.None, addToOps(ops, PropertyOperation.Equals, PropertyOperation.RegEx, PropertyOperation.In, PropertyOperation.NotIn)) + .setCodes("ACTIVE", "TRIAL", "DISCOURAGED", "DEPRECATED"); + } + + if (Utilities.existsInList(property, + "copyright")) { + return new PropertyValidationRules(PropertyFilterType.CodeList, CodeValidationRule.None, addToOps(ops, PropertyOperation.Equals, PropertyOperation.RegEx, PropertyOperation.In, PropertyOperation.NotIn)).setCodes("LOINC", "3rdParty"); + } + + if (Utilities.existsInList(property, + "concept")) { + return new PropertyValidationRules(PropertyFilterType.Code, CodeValidationRule.None, addToOps(ops, PropertyOperation.IsA)); + } + return null; + } +} diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/RxNormChecker.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/RxNormChecker.java new file mode 100644 index 000000000..9de081831 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/RxNormChecker.java @@ -0,0 +1,61 @@ +package org.hl7.fhir.validation.codesystem; + +import java.util.EnumSet; +import java.util.List; + +import org.hl7.fhir.r5.context.IWorkerContext; +import org.hl7.fhir.r5.utils.XVerExtensionManager; +import org.hl7.fhir.utilities.validation.ValidationMessage; +import org.hl7.fhir.validation.instance.type.ValueSetValidator.CodeValidationRule; +import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyFilterType; +import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyOperation; +import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyValidationRules; + +public class RxNormChecker extends CodeSystemChecker { + + public RxNormChecker(IWorkerContext context, XVerExtensionManager xverManager, boolean debug, List errors) { + super(context, xverManager, debug, errors); + } + + + @Override + public void listPropertyNames(List knownNames) { + super.listPropertyNames(knownNames); + addName(knownNames, "STY"); + addName(knownNames, "SAB"); + addName(knownNames, "TTY"); + addName(knownNames, "SY"); + addName(knownNames, "SIB"); + addName(knownNames, "RN"); + addName(knownNames, "PAR"); + addName(knownNames, "CHD"); + addName(knownNames, "RB"); + addName(knownNames, "RO"); + addName(knownNames, "IN"); + addName(knownNames, "PIN"); + addName(knownNames, "MIN"); + addName(knownNames, "BN"); + addName(knownNames, "SCD"); + addName(knownNames, "SBD"); + addName(knownNames, "GPCK"); + addName(knownNames, "BPCK"); + addName(knownNames, "SCDC"); + addName(knownNames, "SCDF"); + addName(knownNames, "SCDFP"); + addName(knownNames, "SCDG"); + addName(knownNames, "SCDGP"); + addName(knownNames, "SBDC"); + addName(knownNames, "SBDF"); + addName(knownNames, "SBDFP"); + addName(knownNames, "SBDG"); + addName(knownNames, "DF"); + addName(knownNames, "DFG"); + + } + + @Override + public PropertyValidationRules rulesForFilter(String property, EnumSet ops) { + return new PropertyValidationRules(PropertyFilterType.Code, CodeValidationRule.None, ops); + } + +} diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/SnomedCTChecker.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/SnomedCTChecker.java index 235ce5320..048f906d5 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/SnomedCTChecker.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/SnomedCTChecker.java @@ -1,6 +1,7 @@ package org.hl7.fhir.validation.codesystem; import java.util.ArrayList; +import java.util.EnumSet; import java.util.List; import org.hl7.fhir.r5.context.IWorkerContext; @@ -10,6 +11,10 @@ import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.i18n.I18nConstants; import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; +import org.hl7.fhir.validation.instance.type.ValueSetValidator.CodeValidationRule; +import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyFilterType; +import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyOperation; +import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyValidationRules; import org.hl7.fhir.validation.instance.utils.NodeStack; public class SnomedCTChecker extends CodeSystemChecker { @@ -45,4 +50,161 @@ public class SnomedCTChecker extends CodeSystemChecker { super.finish(inc, stack); hint(errors, "2023-07-21", IssueType.BUSINESSRULE, inc.line(), inc.col(), stack.getLiteralPath(), !(noTag && hasTag), I18nConstants.VALUESET_CONCEPT_DISPLAY_SCT_TAG_MIXED, tags.toString(), noTags.toString()); } + + @Override + public void listPropertyNames(List knownNames) { + // list from http://tx.fhir.org/r4/ValueSet/$expand?url=http://snomed.info/sct?fhir_vs=isa/410662002 + addName(knownNames, "concept"); + addName(knownNames, "constraint"); + addName(knownNames, "expressions"); + addName(knownNames, "410662002"); + addName(knownNames, "42752001"); + addName(knownNames, "47429007"); + addName(knownNames, "116676008"); + addName(knownNames, "116686009"); + addName(knownNames, "118168003"); + addName(knownNames, "118169006"); + addName(knownNames, "118170007"); + addName(knownNames, "118171006"); + addName(knownNames, "127489000"); + addName(knownNames, "131195008"); + addName(knownNames, "246075003"); + addName(knownNames, "246090004"); + addName(knownNames, "246093002"); + addName(knownNames, "246112005"); + addName(knownNames, "246454002"); + addName(knownNames, "246456000"); + addName(knownNames, "246501002"); + addName(knownNames, "246513007"); + addName(knownNames, "246514001"); + addName(knownNames, "255234002"); + addName(knownNames, "260507000"); + addName(knownNames, "260686004"); + addName(knownNames, "260870009"); + addName(knownNames, "263502005"); + addName(knownNames, "272741003"); + addName(knownNames, "288556008"); + addName(knownNames, "363589002"); + addName(knownNames, "363698007"); + addName(knownNames, "363699004"); + addName(knownNames, "363700003"); + addName(knownNames, "363701004"); + addName(knownNames, "363702006"); + addName(knownNames, "363703001"); + addName(knownNames, "363704007"); + addName(knownNames, "363705008"); + addName(knownNames, "363709002"); + addName(knownNames, "363710007"); + addName(knownNames, "363713009"); + addName(knownNames, "363714003"); + addName(knownNames, "370129005"); + addName(knownNames, "370130000"); + addName(knownNames, "370131001"); + addName(knownNames, "370132008"); + addName(knownNames, "370133003"); + addName(knownNames, "370134009"); + addName(knownNames, "370135005"); + addName(knownNames, "371881003"); + addName(knownNames, "405813007"); + addName(knownNames, "405814001"); + addName(knownNames, "405815000"); + addName(knownNames, "405816004"); + addName(knownNames, "408729009"); + addName(knownNames, "408730004"); + addName(knownNames, "408731000"); + addName(knownNames, "408732007"); + addName(knownNames, "410675002"); + addName(knownNames, "411116001"); + addName(knownNames, "418775008"); + addName(knownNames, "419066007"); + addName(knownNames, "424226004"); + addName(knownNames, "424244007"); + addName(knownNames, "424361007"); + addName(knownNames, "424876005"); + addName(knownNames, "425391005"); + addName(knownNames, "609096000"); + addName(knownNames, "704319004"); + addName(knownNames, "704320005"); + addName(knownNames, "704321009"); + addName(knownNames, "704322002"); + addName(knownNames, "704323007"); + addName(knownNames, "704324001"); + addName(knownNames, "704325000"); + addName(knownNames, "704326004"); + addName(knownNames, "704327008"); + addName(knownNames, "704346009"); + addName(knownNames, "704347000"); + addName(knownNames, "704647008"); + addName(knownNames, "718497002"); + addName(knownNames, "719715003"); + addName(knownNames, "719722006"); + addName(knownNames, "726542003"); + addName(knownNames, "726633004"); + addName(knownNames, "732943007"); + addName(knownNames, "732945000"); + addName(knownNames, "732947008"); + addName(knownNames, "733722007"); + addName(knownNames, "733725009"); + addName(knownNames, "733928003"); + addName(knownNames, "733930001"); + addName(knownNames, "733931002"); + addName(knownNames, "733932009"); + addName(knownNames, "733933004"); + addName(knownNames, "734136001"); + addName(knownNames, "734137005"); + addName(knownNames, "736472000"); + addName(knownNames, "736473005"); + addName(knownNames, "736474004"); + addName(knownNames, "736475003"); + addName(knownNames, "736476002"); + addName(knownNames, "736518005"); + addName(knownNames, "738774007"); + addName(knownNames, "762705008"); + addName(knownNames, "762706009"); + addName(knownNames, "762949000"); + addName(knownNames, "762951001"); + addName(knownNames, "763032000"); + addName(knownNames, "766939001"); + addName(knownNames, "774081006"); + addName(knownNames, "774158006"); + addName(knownNames, "774159003"); + addName(knownNames, "774160008"); + addName(knownNames, "774163005"); + addName(knownNames, "827081001"); + addName(knownNames, "836358009"); + addName(knownNames, "840560000"); + addName(knownNames, "860779006"); + addName(knownNames, "860781008"); + addName(knownNames, "1003703000"); + addName(knownNames, "1003735000"); + addName(knownNames, "1142135004"); + addName(knownNames, "1142136003"); + addName(knownNames, "1142137007"); + addName(knownNames, "1142138002"); + addName(knownNames, "1142139005"); + addName(knownNames, "1142140007"); + addName(knownNames, "1142141006"); + addName(knownNames, "1142142004"); + addName(knownNames, "1142143009"); + addName(knownNames, "1148793005"); + addName(knownNames, "1148965004"); + addName(knownNames, "1148967007"); + addName(knownNames, "1148968002"); + addName(knownNames, "1148969005"); + addName(knownNames, "1149366004"); + addName(knownNames, "1149367008"); + addName(knownNames, "1230370004"); + addName(knownNames, "320091000221107"); + } + + @Override + public PropertyValidationRules rulesForFilter(String property, EnumSet ops) { + switch (property) { + case "constraint": return null; // for now + case "expressions": return new PropertyValidationRules(PropertyFilterType.Boolean, null, addToOps(ops, PropertyOperation.Equals, PropertyOperation.In)); + case "concept": return new PropertyValidationRules(PropertyFilterType.Code, CodeValidationRule.Error, addToOps(ops, PropertyOperation.IsA, PropertyOperation.IsNotA, PropertyOperation.In, PropertyOperation.DescendentOf, PropertyOperation.DescendentLeaf)); + default: + return new PropertyValidationRules(PropertyFilterType.Code, CodeValidationRule.Error, addToOps(ops, PropertyOperation.Equals, PropertyOperation.In)); + } + } } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/UcumChecker.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/UcumChecker.java new file mode 100644 index 000000000..e18cf56f7 --- /dev/null +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/codesystem/UcumChecker.java @@ -0,0 +1,32 @@ +package org.hl7.fhir.validation.codesystem; + +import java.util.EnumSet; +import java.util.List; + +import org.hl7.fhir.r5.context.IWorkerContext; +import org.hl7.fhir.r5.utils.XVerExtensionManager; +import org.hl7.fhir.utilities.validation.ValidationMessage; +import org.hl7.fhir.validation.instance.type.ValueSetValidator.CodeValidationRule; +import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyFilterType; +import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyOperation; +import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyValidationRules; + +public class UcumChecker extends CodeSystemChecker { + + public UcumChecker(IWorkerContext context, XVerExtensionManager xverManager, boolean debug, List errors) { + super(context, xverManager, debug, errors); + } + + + @Override + public void listPropertyNames(List knownNames) { + super.listPropertyNames(knownNames); + addName(knownNames, "property"); + addName(knownNames, "canonical"); + } + + @Override + public PropertyValidationRules rulesForFilter(String property, EnumSet ops) { + return new PropertyValidationRules(PropertyFilterType.Code, CodeValidationRule.None, ops); + } +} 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 b690d2c31..365f4f039 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 @@ -114,9 +114,11 @@ import org.hl7.fhir.r5.model.DateTimeType; import org.hl7.fhir.r5.model.DateType; import org.hl7.fhir.r5.model.DecimalType; import org.hl7.fhir.r5.model.ElementDefinition; +import org.hl7.fhir.r5.model.ElementDefinition.AdditionalBindingPurposeVS; import org.hl7.fhir.r5.model.ElementDefinition.AggregationMode; import org.hl7.fhir.r5.model.ElementDefinition.ConstraintSeverity; import org.hl7.fhir.r5.model.ElementDefinition.DiscriminatorType; +import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingAdditionalComponent; import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent; import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionConstraintComponent; import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionMappingComponent; @@ -212,6 +214,7 @@ import org.hl7.fhir.validation.BaseValidator; import org.hl7.fhir.validation.cli.model.HtmlInMarkdownCheck; import org.hl7.fhir.validation.cli.utils.QuestionnaireMode; import org.hl7.fhir.validation.codesystem.CodingsObserver; +import org.hl7.fhir.validation.instance.InstanceValidator.BindingContext; import org.hl7.fhir.validation.instance.type.BundleValidator; import org.hl7.fhir.validation.instance.type.CodeSystemValidator; import org.hl7.fhir.validation.instance.type.ConceptMapValidator; @@ -255,6 +258,11 @@ import org.w3c.dom.Document; public class InstanceValidator extends BaseValidator implements IResourceValidator { + public enum BindingContext { + BASE, MAXVS, ADDITIONAL + + } + private static final String EXECUTED_CONSTRAINT_LIST = "validator.executed.invariant.list"; private static final String EXECUTION_ID = "validator.execution.id"; private static final String HTML_FRAGMENT_REGEX = "[a-zA-Z]\\w*(((\\s+)(\\S)*)*)"; @@ -1346,129 +1354,40 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private boolean checkCodeableConcept(List errors, String path, Element element, StructureDefinition profile, ElementDefinition theElementCntext, NodeStack stack, BooleanHolder bh) { boolean checkDisp = true; - boolean checked = false; + BooleanHolder checked = new BooleanHolder(false); if (!noTerminologyChecks && theElementCntext != null && theElementCntext.hasBinding()) { ElementDefinitionBindingComponent binding = theElementCntext.getBinding(); if (warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, binding != null, I18nConstants.TERMINOLOGY_TX_BINDING_MISSING, path)) { - if (binding.hasValueSet()) { - ValueSet valueset = resolveBindingReference(profile, binding.getValueSet(), profile.getUrl(), profile); - if (valueset == null) { - CodeSystem cs = context.fetchCodeSystem(binding.getValueSet()); - if (rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, cs == null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND_CS, describeReference(binding.getValueSet()))) { - warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, valueset != null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND, describeReference(binding.getValueSet())); - } else { - bh.fail(); - } - } else { - try { - CodeableConcept cc = ObjectConverter.readAsCodeableConcept(element); - if (!cc.hasCoding()) { - if (binding.getStrength() == BindingStrength.REQUIRED) - bh.see(rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CODE_VALUESET, describeReference(binding.getValueSet(), valueset))); - else if (binding.getStrength() == BindingStrength.EXTENSIBLE) { - if (binding.hasExtension(ToolingExtensions.EXT_MAX_VALUESET)) - bh.see(rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CODE_VALUESETMAX, describeReference(ToolingExtensions.readStringExtension(binding, ToolingExtensions.EXT_MAX_VALUESET)), valueset.getVersionedUrl())); - else - warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CODE_VALUESET_EXT, describeReference(binding.getValueSet(), valueset)); - } - } else { - long t = System.nanoTime(); - - // Check whether the codes are appropriate for the type of binding we have - boolean bindingsOk = true; - if (binding.getStrength() != BindingStrength.EXAMPLE) { - if (binding.getStrength() == BindingStrength.REQUIRED) { - removeTrackedMessagesForLocation(errors, element, path); - } - boolean atLeastOneSystemIsSupported = false; - for (Coding nextCoding : cc.getCoding()) { - String nextSystem = nextCoding.getSystem(); - if (isNotBlank(nextSystem) && context.supportsSystem(nextSystem, baseOptions.getFhirVersion())) { - atLeastOneSystemIsSupported = true; - break; - } - } - - if (!atLeastOneSystemIsSupported && binding.getStrength() == BindingStrength.EXAMPLE) { - // ignore this since we can't validate but it doesn't matter.. - } else { - checked = true; - ValidationResult vr = checkCodeOnServer(stack, valueset, cc); - bh.see(processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(binding), false, binding.getValueSet())); - if (!vr.isOk()) { - bindingsOk = false; - if (vr.getErrorClass() != null && vr.getErrorClass() == TerminologyServiceErrorClass.NOSERVICE) { - if (binding.getStrength() == BindingStrength.REQUIRED || (binding.getStrength() == BindingStrength.EXTENSIBLE && binding.hasExtension(ToolingExtensions.EXT_MAX_VALUESET))) { - txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOSVC_BOUND_REQ, describeReference(binding.getValueSet())); - } else if (binding.getStrength() == BindingStrength.EXTENSIBLE) { - txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOSVC_BOUND_EXT, describeReference(binding.getValueSet())); - } - } else if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure()) { - if (binding.getStrength() == BindingStrength.REQUIRED) - txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_1_CC, describeReference(binding.getValueSet()), vr.getErrorClass().toString()); - else if (binding.getStrength() == BindingStrength.EXTENSIBLE) { - if (binding.hasExtension(ToolingExtensions.EXT_MAX_VALUESET)) - bh.see(checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, ToolingExtensions.EXT_MAX_VALUESET), cc, stack)); - else if (!noExtensibleWarnings) - txWarningForLaterRemoval(element, errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_2_CC, describeReference(binding.getValueSet()), vr.getErrorClass().toString()); - } else if (binding.getStrength() == BindingStrength.PREFERRED) { - if (baseOnly) { - txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_3_CC, describeReference(binding.getValueSet()), vr.getErrorClass().toString()); - } - } - } else { - if (binding.getStrength() == BindingStrength.REQUIRED) { - bh.see(txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_1_CC, describeReference(binding.getValueSet(), valueset), ccSummary(cc))); - } else if (binding.getStrength() == BindingStrength.EXTENSIBLE) { - if (binding.hasExtension(ToolingExtensions.EXT_MAX_VALUESET)) - bh.see(checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, ToolingExtensions.EXT_MAX_VALUESET), cc, stack)); - if (!noExtensibleWarnings) - txWarningForLaterRemoval(element, errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_2_CC, describeReference(binding.getValueSet(), valueset), ccSummary(cc)); - } else if (binding.getStrength() == BindingStrength.PREFERRED) { - if (baseOnly) { - txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_3_CC, describeReference(binding.getValueSet(), valueset), ccSummary(cc)); - } - } - } - } else if (vr.getMessage() != null) { - if (vr.getTrimmedMessage() != null) { - if (vr.getSeverity() == IssueSeverity.INFORMATION) { - txHint(errors, "2023-07-03", vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, vr.getMessage()); - } else { - checkDisp = false; - txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, vr.getTrimmedMessage()); - } - } - } else { - if (binding.getStrength() == BindingStrength.EXTENSIBLE) { - removeTrackedMessagesForLocation(errors, element, path); - } - checkDisp = false; - } - } - // Then, for any codes that are in code systems we are able - // to validate, we'll validate that the codes actually exist - if (bindingsOk) { - for (Coding nextCoding : cc.getCoding()) { - bh.see(checkBindings(errors, path, element, stack, valueset, nextCoding)); - } - } - timeTracker.tx(t, "vc "+cc.toString()); - } - } - } catch (CheckCodeOnServerException e) { - if (STACK_TRACE) e.getCause().printStackTrace(); - warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_ERROR_CODEABLECONCEPT, e.getCause().getMessage()); + try { + CodeableConcept cc = ObjectConverter.readAsCodeableConcept(element); + if (binding.hasValueSet()) { + String vsRef = binding.getValueSet(); + ValueSet valueset = resolveBindingReference(profile, vsRef, profile.getUrl(), profile); + BindingStrength strength = binding.getStrength(); + Extension maxVS = binding.getExtensionByUrl(ToolingExtensions.EXT_MAX_VALUESET); + + checkDisp = validateBindingCodeableConcept(errors, path, element, profile, stack, bh, checkDisp, checked, cc, vsRef, valueset, strength, maxVS, true); +// } else if (binding.hasValueSet()) { +// hint(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_CANTCHECK); + } else if (!noBindingMsgSuppressed) { + hint(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_NOSOURCE, path); + } + for (ElementDefinitionBindingAdditionalComponent ab : binding.getAdditional()) { + if (isTestableBinding(ab) && isInScope(ab)) { + String vsRef = ab.getValueSet(); + ValueSet valueset = resolveBindingReference(profile, vsRef, profile.getUrl(), profile); + BindingStrength strength = convertPurposeToStrength(ab.getPurpose()); + + checkDisp = validateBindingCodeableConcept(errors, path, element, profile, stack, bh, checkDisp, checked, cc, vsRef, valueset, strength, null, false) && checkDisp; } } - } else if (binding.hasValueSet()) { - hint(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_CANTCHECK); - } else if (!noBindingMsgSuppressed) { - hint(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_NOSOURCE, path); + } catch (CheckCodeOnServerException e) { + if (STACK_TRACE) e.getCause().printStackTrace(); + warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_ERROR_CODEABLECONCEPT, e.getCause().getMessage()); } } } - if (!noTerminologyChecks && theElementCntext != null && !checked) { // no binding check, so we just check the CodeableConcept generally + if (!noTerminologyChecks && theElementCntext != null && !checked.ok()) { // no binding check, so we just check the CodeableConcept generally try { CodeableConcept cc = ObjectConverter.readAsCodeableConcept(element); if (cc.hasCoding()) { @@ -1485,6 +1404,144 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return checkDisp; } + private boolean isInScope(ElementDefinitionBindingAdditionalComponent ab) { + for (UsageContext usage : ab.getUsage()) { + if (isInScope(usage)) { + return true; + } + } + return ab.getUsage().isEmpty(); + } + + private boolean isInScope(UsageContext usage) { + if (isKnownUsage(usage)) { + return true; + } + return false; + } + + private BindingStrength convertPurposeToStrength(AdditionalBindingPurposeVS purpose) { + switch (purpose) { + case MAXIMUM: return BindingStrength.REQUIRED; + case PREFERRED: return BindingStrength.PREFERRED; + case REQUIRED: return BindingStrength.REQUIRED; + default: return null; + } + } + + private boolean isTestableBinding(ElementDefinitionBindingAdditionalComponent ab) { + return ab.hasValueSet() && convertPurposeToStrength(ab.getPurpose()) != null; + } + + private boolean validateBindingCodeableConcept(List errors, String path, Element element, StructureDefinition profile, NodeStack stack, BooleanHolder bh, boolean checkDisp, BooleanHolder checked, + CodeableConcept cc, String vsRef, ValueSet valueset, BindingStrength strength, Extension maxVS, boolean base) throws CheckCodeOnServerException { + if (valueset == null) { + CodeSystem cs = context.fetchCodeSystem(vsRef); + if (rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, cs == null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND_CS, describeReference(vsRef))) { + warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, valueset != null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND, describeReference(vsRef)); + } else { + bh.fail(); + } + } else { + BindingContext bc = base ? BindingContext.BASE : BindingContext.ADDITIONAL; + if (!cc.hasCoding()) { + if (strength == BindingStrength.REQUIRED) + bh.see(rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CODE_VALUESET, describeReference(vsRef, valueset, bc))); + else if (strength == BindingStrength.EXTENSIBLE) { + if (maxVS != null) + bh.see(rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CODE_VALUESETMAX, describeReference(ToolingExtensions.readStringFromExtension(maxVS)), valueset.getVersionedUrl())); + else + warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CODE_VALUESET_EXT, describeReference(vsRef, valueset, bc)); + } + } else { + long t = System.nanoTime(); + + // Check whether the codes are appropriate for the type of binding we have + boolean bindingsOk = true; + if (strength != BindingStrength.EXAMPLE) { + if (strength == BindingStrength.REQUIRED) { + removeTrackedMessagesForLocation(errors, element, path); + } + boolean atLeastOneSystemIsSupported = false; + for (Coding nextCoding : cc.getCoding()) { + String nextSystem = nextCoding.getSystem(); + if (isNotBlank(nextSystem) && context.supportsSystem(nextSystem, baseOptions.getFhirVersion())) { + atLeastOneSystemIsSupported = true; + break; + } + } + + if (!atLeastOneSystemIsSupported && strength == BindingStrength.EXAMPLE) { + // ignore this since we can't validate but it doesn't matter.. + } else { + checked.set(true); + ValidationResult vr = checkCodeOnServer(stack, valueset, cc); + bh.see(processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(strength), false, vsRef)); + if (!vr.isOk()) { + bindingsOk = false; + if (vr.getErrorClass() != null && vr.getErrorClass() == TerminologyServiceErrorClass.NOSERVICE) { + if (strength == BindingStrength.REQUIRED || (strength == BindingStrength.EXTENSIBLE && maxVS != null)) { + txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOSVC_BOUND_REQ, describeReference(vsRef)); + } else if (strength == BindingStrength.EXTENSIBLE) { + txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOSVC_BOUND_EXT, describeReference(vsRef)); + } + } else if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure()) { + if (strength == BindingStrength.REQUIRED) + txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_1_CC, describeReference(vsRef), vr.getErrorClass().toString()); + else if (strength == BindingStrength.EXTENSIBLE) { + if (maxVS != null) + bh.see(checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringFromExtension(maxVS), cc, stack)); + else if (!noExtensibleWarnings) + txWarningForLaterRemoval(element, errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_2_CC, describeReference(vsRef), vr.getErrorClass().toString()); + } else if (strength == BindingStrength.PREFERRED) { + if (baseOnly) { + txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_3_CC, describeReference(vsRef), vr.getErrorClass().toString()); + } + } + } else { + if (strength == BindingStrength.REQUIRED) { + bh.see(txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_1_CC, describeReference(vsRef, valueset, bc), ccSummary(cc))); + } else if (strength == BindingStrength.EXTENSIBLE) { + if (maxVS != null) + bh.see(checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringFromExtension(maxVS), cc, stack)); + if (!noExtensibleWarnings) + txWarningForLaterRemoval(element, errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_2_CC, describeReference(vsRef, valueset, bc), ccSummary(cc)); + } else if (strength == BindingStrength.PREFERRED) { + if (baseOnly) { + txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_3_CC, describeReference(vsRef, valueset, bc), ccSummary(cc)); + } + } + } + } else if (vr.getMessage() != null) { + if (vr.getTrimmedMessage() != null) { + if (vr.getSeverity() == IssueSeverity.INFORMATION) { + txHint(errors, "2023-07-03", vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, vr.getMessage()); + } else { + checkDisp = false; + txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, vr.getTrimmedMessage()); + } + } + } else { + if (strength == BindingStrength.EXTENSIBLE) { + removeTrackedMessagesForLocation(errors, element, path); + } + checkDisp = false; + } + } + // Then, for any codes that are in code systems we are able + // to validate, we'll validate that the codes actually exist + if (bindingsOk) { + for (Coding nextCoding : cc.getCoding()) { + bh.see(checkBindings(errors, path, element, stack, valueset, nextCoding)); + } + } + timeTracker.tx(t, "vc "+cc.toString()); + } + } + } + return checkDisp; + } + /** * The terminology server will report an error for an unknown code system or version, or a dependent valueset * @@ -1492,10 +1549,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat * @param binding * @return */ - private org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity notFoundSeverityForBinding(ElementDefinitionBindingComponent binding) { - if (binding.getStrength() == BindingStrength.REQUIRED) { + private org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity notFoundSeverityForBinding(BindingStrength strength) { + if (strength == BindingStrength.REQUIRED) { return org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.ERROR; - } else if (binding.getStrength() == BindingStrength.EXTENSIBLE) { + } else if (strength == BindingStrength.EXTENSIBLE) { return org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.WARNING; } else { return org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity.INFORMATION; @@ -1550,131 +1607,45 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private boolean checkCDACodeableConcept(List errors, String path, Element element, StructureDefinition profile, ElementDefinition theElementCntext, NodeStack stack, StructureDefinition logical) { - boolean ok = true; + BooleanHolder ok = new BooleanHolder(true); if (!noTerminologyChecks && theElementCntext != null && theElementCntext.hasBinding()) { - ElementDefinitionBindingComponent binding = theElementCntext.getBinding(); - if (warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, binding != null, I18nConstants.TERMINOLOGY_TX_BINDING_MISSING, path)) { - if (binding.hasValueSet()) { - ValueSet valueset = resolveBindingReference(profile, binding.getValueSet(), profile.getUrl(), profile); - if (valueset == null) { - CodeSystem cs = context.fetchCodeSystem(binding.getValueSet()); - if (rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, cs == null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND_CS, describeReference(binding.getValueSet()))) { - warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, valueset != null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND, describeReference(binding.getValueSet())); - } else { - ok = false; - } - } else { - try { - CodeableConcept cc = new CodeableConcept(); - ok = convertCDACodeToCodeableConcept(errors, path, element, logical, cc) && ok; - if (!cc.hasCoding()) { - if (binding.getStrength() == BindingStrength.REQUIRED) - ok = rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, "No code provided, and a code is required from the value set " + describeReference(binding.getValueSet()) + " (" + valueset.getVersionedUrl()) && ok; - else if (binding.getStrength() == BindingStrength.EXTENSIBLE) { - if (binding.hasExtension(ToolingExtensions.EXT_MAX_VALUESET)) - ok = rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CODE_VALUESETMAX, describeReference(ToolingExtensions.readStringExtension(binding, ToolingExtensions.EXT_MAX_VALUESET)), valueset.getVersionedUrl()) && ok; - else - warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CODE_VALUESET_EXT, describeReference(binding.getValueSet(), valueset)); - } - } else { - long t = System.nanoTime(); + try { + CodeableConcept cc = new CodeableConcept(); + ok.see(convertCDACodeToCodeableConcept(errors, path, element, logical, cc)); + ElementDefinitionBindingComponent binding = theElementCntext.getBinding(); + if (warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, binding != null, I18nConstants.TERMINOLOGY_TX_BINDING_MISSING, path)) { + if (binding.hasValueSet()) { + String vsRef = binding.getValueSet(); + ValueSet valueset = resolveBindingReference(profile, vsRef, profile.getUrl(), profile); + BindingStrength strength = binding.getStrength(); + Extension vsMax = binding.getExtensionByUrl(ToolingExtensions.EXT_MAX_VALUESET); + + validateBindingCodeableConcept(errors, path, element, profile, stack, ok, false, new BooleanHolder(), cc, vsRef, valueset, strength, vsMax, true); - // Check whether the codes are appropriate for the type of binding we have - boolean bindingsOk = true; - if (binding.getStrength() != BindingStrength.EXAMPLE) { - if (binding.getStrength() == BindingStrength.REQUIRED) { - removeTrackedMessagesForLocation(errors, element, path); - } - - boolean atLeastOneSystemIsSupported = false; - for (Coding nextCoding : cc.getCoding()) { - String nextSystem = nextCoding.getSystem(); - if (isNotBlank(nextSystem) && context.supportsSystem(nextSystem, baseOptions.getFhirVersion())) { - atLeastOneSystemIsSupported = true; - break; - } - } - - if (!atLeastOneSystemIsSupported && binding.getStrength() == BindingStrength.EXAMPLE) { - // ignore this since we can't validate but it doesn't matter.. - } else { - ValidationResult vr = checkCodeOnServer(stack, valueset, cc); - ok = processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(binding), false, binding.getValueSet()) && ok; - if (!vr.isOk()) { - bindingsOk = false; - if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure()) { - if (binding.getStrength() == BindingStrength.REQUIRED) - txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_1_CC, describeReference(binding.getValueSet()), vr.getErrorClass().toString()); - else if (binding.getStrength() == BindingStrength.EXTENSIBLE) { - if (binding.hasExtension(ToolingExtensions.EXT_MAX_VALUESET)) - ok = checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, ToolingExtensions.EXT_MAX_VALUESET), cc, stack) && ok; - else if (!noExtensibleWarnings) - txWarningForLaterRemoval(element, errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_2_CC, describeReference(binding.getValueSet()), vr.getErrorClass().toString()); - } else if (binding.getStrength() == BindingStrength.PREFERRED) { - if (baseOnly) { - txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_3_CC, describeReference(binding.getValueSet()), vr.getErrorClass().toString()); - } - } - } else { - if (binding.getStrength() == BindingStrength.REQUIRED) - ok = txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_1_CC, describeReference(binding.getValueSet()), valueset, ccSummary(cc)) && ok; - else if (binding.getStrength() == BindingStrength.EXTENSIBLE) { - if (binding.hasExtension(ToolingExtensions.EXT_MAX_VALUESET)) - ok = checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, ToolingExtensions.EXT_MAX_VALUESET), cc, stack) && ok; - if (!noExtensibleWarnings) - txWarningForLaterRemoval(element, errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_2_CC, describeReference(binding.getValueSet(), valueset), ccSummary(cc)); - } else if (binding.getStrength() == BindingStrength.PREFERRED) { - if (baseOnly) { - txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_3_CC, describeReference(binding.getValueSet(), valueset), ccSummary(cc)); - } - } - } - } else if (vr.getMessage() != null) { - if (vr.getSeverity() == IssueSeverity.INFORMATION) { - txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, vr.getMessage()); - } else { - txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, vr.getMessage()); - } - } else { - ok = true; - } - } - // Then, for any codes that are in code systems we are able - // to validate, we'll validate that the codes actually exist - if (bindingsOk) { - for (Coding nextCoding : cc.getCoding()) { - String nextCode = nextCoding.getCode(); - String nextSystem = nextCoding.getSystem(); - String nextVersion = nextCoding.getVersion(); - if (isNotBlank(nextCode) && isNotBlank(nextSystem) && context.supportsSystem(nextSystem, baseOptions.getFhirVersion())) { - ValidationResult vr = checkCodeOnServer(stack, nextCode, nextSystem, nextVersion, null, false); - ok = (processTxIssues(errors, vr, element, path, null, false, null)) && ok; - if (!vr.isOk()) { - txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CODE_NOTVALID, nextCode, nextSystem); - } - } - } - } - timeTracker.tx(t, DataRenderer.display(context, cc)); - } - } - } catch (CheckCodeOnServerException e) { - if (STACK_TRACE) e.getCause().printStackTrace(); - warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_ERROR_CODEABLECONCEPT, e.getCause().getMessage()); - } // special case: if the logical model has both CodeableConcept and Coding mappings, we'll also check the first coding. if (getMapping("http://hl7.org/fhir/terminology-pattern", logical, logical.getSnapshot().getElementFirstRep()).contains("Coding")) { - ok = checkTerminologyCoding(errors, path, element, profile, theElementCntext, true, true, stack, logical) && ok; + ok.see(checkTerminologyCoding(errors, path, element, profile, theElementCntext, true, true, stack, logical)); + } +// } else if (binding.hasValueSet()) { +// hint(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_CANTCHECK); + } else if (!noBindingMsgSuppressed) { + hint(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_NOSOURCE, path); + } + for (ElementDefinitionBindingAdditionalComponent ab : binding.getAdditional()) { + if (isTestableBinding(ab) && isInScope(ab)) { + String vsRef = ab.getValueSet(); + ValueSet valueset = resolveBindingReference(profile, vsRef, profile.getUrl(), profile); + BindingStrength strength = convertPurposeToStrength(ab.getPurpose()); + validateBindingCodeableConcept(errors, path, element, profile, stack, ok, false, new BooleanHolder(), cc, vsRef, valueset, strength, null, false); } } - } else if (binding.hasValueSet()) { - hint(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_CANTCHECK); - } else if (!noBindingMsgSuppressed) { - hint(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_NOSOURCE, path); } + } catch (CheckCodeOnServerException e) { + if (STACK_TRACE) e.getCause().printStackTrace(); + warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_ERROR_CODEABLECONCEPT, e.getCause().getMessage()); } } - return ok; + return ok.ok(); } private boolean checkTerminologyCoding(List errors, String path, Element element, StructureDefinition profile, ElementDefinition theElementCntext, boolean inCodeableConcept, boolean checkDisplay, NodeStack stack, StructureDefinition logical) { @@ -1694,71 +1665,25 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat ElementDefinitionBindingComponent binding = theElementCntext.getBinding(); if (warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, binding != null, I18nConstants.TERMINOLOGY_TX_BINDING_MISSING2, path)) { if (binding.hasValueSet()) { - ValueSet valueset = resolveBindingReference(profile, binding.getValueSet(), profile.getUrl(), profile); - if (valueset == null) { - CodeSystem cs = context.fetchCodeSystem(binding.getValueSet()); - if (rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, cs == null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND_CS, describeReference(binding.getValueSet()))) { - warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, valueset != null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND, describeReference(binding.getValueSet())); - } else { - ok = false; - } - } else { - try { - long t = System.nanoTime(); - ValidationResult vr = null; - if (binding.getStrength() != BindingStrength.EXAMPLE) { - vr = checkCodeOnServer(stack, valueset, c); - } - if (binding.getStrength() == BindingStrength.REQUIRED) { - removeTrackedMessagesForLocation(errors, element, path); - } - ok = processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(binding), false, binding.getValueSet()) && ok; - timeTracker.tx(t, "vc "+system+"#"+code+" '"+display+"'"); - if (vr != null && !vr.isOk()) { - if (vr.IsNoService()) - txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_NOSERVER, system+"#"+code); - else if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure()) { - if (binding.getStrength() == BindingStrength.REQUIRED) - txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_4a, describeReference(binding.getValueSet(), valueset), vr.getMessage(), system+"#"+code); - else if (binding.getStrength() == BindingStrength.EXTENSIBLE) { - if (binding.hasExtension(ToolingExtensions.EXT_MAX_VALUESET)) - checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, ToolingExtensions.EXT_MAX_VALUESET), c, stack); - else if (!noExtensibleWarnings) - txWarningForLaterRemoval(element, errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_5, describeReference(binding.getValueSet(), valueset)); - } else if (binding.getStrength() == BindingStrength.PREFERRED) { - if (baseOnly) { - txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_6, describeReference(binding.getValueSet(), valueset)); - } - } - } else if (binding.getStrength() == BindingStrength.REQUIRED) - ok= txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_4, describeReference(binding.getValueSet(), valueset), (vr.getMessage() != null ? " (error message = " + vr.getMessage() + ")" : ""), system+"#"+code) && ok; - else if (binding.getStrength() == BindingStrength.EXTENSIBLE) { - if (binding.hasExtension(ToolingExtensions.EXT_MAX_VALUESET)) - ok = checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, ToolingExtensions.EXT_MAX_VALUESET), c, stack) && ok; - else - txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_5, describeReference(binding.getValueSet(), valueset), (vr.getMessage() != null ? " (error message = " + vr.getMessage() + ")" : ""), system+"#"+code); - } else if (binding.getStrength() == BindingStrength.PREFERRED) { - if (baseOnly) { - txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_6, describeReference(binding.getValueSet(), valueset), (vr.getMessage() != null ? " (error message = " + vr.getMessage() + ")" : ""), system+"#"+code); - } - } - } else if (vr != null && vr.getMessage() != null){ - if (vr.getSeverity() == IssueSeverity.INFORMATION) { - txHint(errors, "2023-07-04", vr.getTxLink(), IssueType.INFORMATIONAL, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_HINT, code, vr.getMessage()); - } else { - txWarning(errors, "2023-07-04", vr.getTxLink(), IssueType.INFORMATIONAL, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_WARNING, code, vr.getMessage()); - } - } - } catch (Exception e) { - if (STACK_TRACE) e.printStackTrace(); - warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_ERROR_CODING1, e.getMessage()); - } - } + String vsRef = binding.getValueSet(); + ValueSet valueset = resolveBindingReference(profile, vsRef, profile.getUrl(), profile); + BindingStrength strength = binding.getStrength(); + Extension vsMax = binding.getExtensionByUrl(ToolingExtensions.EXT_MAX_VALUESET); + + ok = validateBindingTerminologyCoding(errors, path, element, profile, stack, ok, c, code, system, display, vsRef, valueset, strength, vsMax, true); } else if (binding.hasValueSet()) { hint(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_CANTCHECK); } else if (!inCodeableConcept && !noBindingMsgSuppressed) { hint(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_NOSOURCE, path); } + for (ElementDefinitionBindingAdditionalComponent ab : binding.getAdditional()) { + if (isTestableBinding(ab) && isInScope(ab)) { + String vsRef = ab.getValueSet(); + ValueSet valueset = resolveBindingReference(profile, vsRef, profile.getUrl(), profile); + BindingStrength strength = convertPurposeToStrength(ab.getPurpose()); + ok = validateBindingTerminologyCoding(errors, path, element, profile, stack, ok, c, code, system, display, vsRef, valueset, strength, null, true) && ok; + } + } } } } else { @@ -1773,6 +1698,72 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return ok; } + private boolean validateBindingTerminologyCoding(List errors, String path, Element element, + StructureDefinition profile, NodeStack stack, boolean ok, Coding c, String code, String system, String display, + String vsRef, ValueSet valueset, BindingStrength strength, Extension vsMax, boolean base) { + if (valueset == null) { + CodeSystem cs = context.fetchCodeSystem(vsRef); + if (rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, cs == null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND_CS, describeReference(vsRef))) { + warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, valueset != null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND, describeReference(vsRef)); + } else { + ok = false; + } + } else { + BindingContext bc = base ? BindingContext.BASE : BindingContext.ADDITIONAL; + try { + long t = System.nanoTime(); + ValidationResult vr = null; + if (strength != BindingStrength.EXAMPLE) { + vr = checkCodeOnServer(stack, valueset, c); + } + if (strength == BindingStrength.REQUIRED) { + removeTrackedMessagesForLocation(errors, element, path); + } + ok = processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(strength), false, vsRef) && ok; + timeTracker.tx(t, "vc "+system+"#"+code+" '"+display+"'"); + if (vr != null && !vr.isOk()) { + if (vr.IsNoService()) + txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_NOSERVER, system+"#"+code); + else if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure()) { + if (strength == BindingStrength.REQUIRED) + txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_4a, describeReference(vsRef, valueset, bc), vr.getMessage(), system+"#"+code); + else if (strength == BindingStrength.EXTENSIBLE) { + if (vsMax != null) + checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringFromExtension(vsMax), c, stack); + else if (!noExtensibleWarnings) + txWarningForLaterRemoval(element, errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_5, describeReference(vsRef, valueset, bc)); + } else if (strength == BindingStrength.PREFERRED) { + if (baseOnly) { + txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_6, describeReference(vsRef, valueset, bc)); + } + } + } else if (strength == BindingStrength.REQUIRED) + ok= txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_4, describeReference(vsRef, valueset, bc), (vr.getMessage() != null ? " (error message = " + vr.getMessage() + ")" : ""), system+"#"+code) && ok; + else if (strength == BindingStrength.EXTENSIBLE) { + if (vsMax != null) + ok = checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringFromExtension(vsMax), c, stack) && ok; + else + txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_5, describeReference(vsRef, valueset, bc), (vr.getMessage() != null ? " (error message = " + vr.getMessage() + ")" : ""), system+"#"+code); + } else if (strength == BindingStrength.PREFERRED) { + if (baseOnly) { + txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_6, describeReference(vsRef, valueset, bc), (vr.getMessage() != null ? " (error message = " + vr.getMessage() + ")" : ""), system+"#"+code); + } + } + } else if (vr != null && vr.getMessage() != null){ + if (vr.getSeverity() == IssueSeverity.INFORMATION) { + txHint(errors, "2023-07-04", vr.getTxLink(), IssueType.INFORMATIONAL, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_HINT, code, vr.getMessage()); + } else { + txWarning(errors, "2023-07-04", vr.getTxLink(), IssueType.INFORMATIONAL, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_WARNING, code, vr.getMessage()); + } + } + } catch (Exception e) { + if (STACK_TRACE) e.printStackTrace(); + warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_ERROR_CODING1, e.getMessage()); + } + } + return ok; + } + private boolean convertCDACodeToCodeableConcept(List errors, String path, Element element, StructureDefinition logical, CodeableConcept cc) { boolean ok = true; cc.setText(element.getNamedChildValue("originalText", false)); @@ -1862,9 +1853,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat timeTracker.tx(t, "vc "+cc.toString()); if (!vr.isOk()) { if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure()) - txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_7, describeReference(maxVSUrl, valueset), vr.getMessage()); + txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_7, describeReference(maxVSUrl, valueset, BindingContext.MAXVS), vr.getMessage()); else - ok = txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_8, describeReference(maxVSUrl, valueset), ccSummary(cc)) && ok; + ok = txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_8, describeReference(maxVSUrl, valueset, BindingContext.MAXVS), ccSummary(cc)) && ok; } } catch (CheckCodeOnServerException e) { if (STACK_TRACE) e.getCause().printStackTrace(); @@ -1902,9 +1893,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat timeTracker.tx(t, "vc "+c.getSystem()+"#"+c.getCode()+" '"+c.getDisplay()+"'"); if (!vr.isOk()) { if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure()) - txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_9, describeReference(maxVSUrl, valueset), vr.getMessage(), c.getSystem()+"#"+c.getCode()); + txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_9, describeReference(maxVSUrl, valueset, BindingContext.MAXVS), vr.getMessage(), c.getSystem()+"#"+c.getCode()); else - ok = txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_10, describeReference(maxVSUrl, valueset), c.getSystem(), c.getCode()) && ok; + ok = txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_10, describeReference(maxVSUrl, valueset, BindingContext.MAXVS), c.getSystem(), c.getCode()) && ok; } } catch (Exception e) { if (STACK_TRACE) e.printStackTrace(); @@ -1932,9 +1923,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat timeTracker.tx(t, "vc "+value); if (!vr.isOk()) { if (vr.getErrorClass() != null && vr.getErrorClass().isInfrastructure()) - txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_9, describeReference(maxVSUrl, valueset), vr.getMessage(), value); + txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_9, describeReference(maxVSUrl, valueset, BindingContext.BASE), vr.getMessage(), value); else { - ok = txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_11, describeReference(maxVSUrl, valueset), vr.getMessage()) && ok; + ok = txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_11, describeReference(maxVSUrl, valueset, BindingContext.BASE), vr.getMessage()) && ok; } } } catch (Exception e) { @@ -1980,83 +1971,41 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat private boolean checkCodedElement(List errors, String path, Element element, StructureDefinition profile, ElementDefinition theElementCntext, boolean inCodeableConcept, boolean checkDisplay, NodeStack stack, String theCode, String theSystem, String theVersion, String theDisplay) { boolean ok = true; - boolean checked = false; + BooleanHolder checked = new BooleanHolder(false); if (theSystem != null && theCode != null && !noTerminologyChecks) { try { if (theElementCntext != null && theElementCntext.hasBinding()) { ElementDefinitionBindingComponent binding = theElementCntext.getBinding(); if (warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, binding != null, I18nConstants.TERMINOLOGY_TX_BINDING_MISSING2, path)) { - if (binding.hasValueSet()) { - ValueSet valueset = resolveBindingReference(profile, binding.getValueSet(), profile.getUrl(), profile); - if (valueset == null) { - CodeSystem cs = context.fetchCodeSystem(binding.getValueSet()); - if (rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, cs == null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND_CS, describeReference(binding.getValueSet()))) { - warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, valueset != null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND, describeReference(binding.getValueSet())); - } else { - ok = false; - } - } else { - try { - Coding c = ObjectConverter.readAsCoding(element); - long t = System.nanoTime(); - ValidationResult vr = null; - if (binding.getStrength() != BindingStrength.EXAMPLE) { - checked = true; - vr = checkCodeOnServer(stack, valueset, c); - } - ok = processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(binding), binding.getStrength() == BindingStrength.EXTENSIBLE, binding.getValueSet()) && ok; + try { + Coding c = ObjectConverter.readAsCoding(element); + if (binding.hasValueSet()) { + String vsRef = binding.getValueSet(); + ValueSet valueset = resolveBindingReference(profile, vsRef, profile.getUrl(), profile); + BindingStrength strength = binding.getStrength(); + Extension vsMax = binding.getExtensionByUrl(ToolingExtensions.EXT_MAX_VALUESET); + + ok = validateBindingCodedElement(errors, path, element, profile, stack, theCode, theSystem, ok, checked, c, vsRef, valueset, strength, vsMax, true); +// } else if (binding.hasValueSet()) { +// hint(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_CANTCHECK); + + } else if (!inCodeableConcept && !noBindingMsgSuppressed) { + hint(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_NOSOURCE, path); + } - timeTracker.tx(t, "vc "+c.getSystem()+"#"+c.getCode()+" '"+c.getDisplay()+"'"); - if (binding.getStrength() == BindingStrength.REQUIRED) { - removeTrackedMessagesForLocation(errors, element, path); - } - - if (vr != null && !vr.isOk()) { - if (vr.IsNoService()) - txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_NOSERVER, theSystem+"#"+theCode); - else if (vr.getErrorClass() != null && !vr.getErrorClass().isInfrastructure()) { - if (binding.getStrength() == BindingStrength.REQUIRED) - ok = txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_4a, describeReference(binding.getValueSet(), valueset), vr.getMessage(), theSystem+"#"+theCode) && ok; - else if (binding.getStrength() == BindingStrength.EXTENSIBLE) { - if (binding.hasExtension(ToolingExtensions.EXT_MAX_VALUESET)) - checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, ToolingExtensions.EXT_MAX_VALUESET), c, stack); - else if (!noExtensibleWarnings) - txWarningForLaterRemoval(element, errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_5, describeReference(binding.getValueSet(), valueset), theSystem+"#"+theCode); - } else if (binding.getStrength() == BindingStrength.PREFERRED) { - if (baseOnly) { - txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_6, describeReference(binding.getValueSet(), valueset), theSystem+"#"+theCode); - } - } - } else if (binding.getStrength() == BindingStrength.REQUIRED) - ok = txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_12, describeReference(binding.getValueSet(), valueset), getErrorMessage(vr.getMessage()), theSystem+"#"+theCode) && ok; - else if (binding.getStrength() == BindingStrength.EXTENSIBLE) { - if (binding.hasExtension(ToolingExtensions.EXT_MAX_VALUESET)) - ok = checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, ToolingExtensions.EXT_MAX_VALUESET), c, stack) && ok; - else if (!noExtensibleWarnings) { - txWarningForLaterRemoval(element, errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_13, describeReference(binding.getValueSet(), valueset), getErrorMessage(vr.getMessage()), c.getSystem()+"#"+c.getCode()); - } - } else if (binding.getStrength() == BindingStrength.PREFERRED) { - if (baseOnly) { - txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_14, describeReference(binding.getValueSet(), valueset), getErrorMessage(vr.getMessage()), theSystem+"#"+theCode); - } - } - } else if (vr != null && vr.getMessage() != null) { - if (vr.getSeverity() == IssueSeverity.INFORMATION) { - txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, vr.getMessage()); - } else { - txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, vr.getMessage()); - } - } - } catch (Exception e) { - if (STACK_TRACE) e.printStackTrace(); - warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_ERROR_CODING1, e.getMessage()); + for (ElementDefinitionBindingAdditionalComponent ab : binding.getAdditional()) { + if (isTestableBinding(ab) && isInScope(ab)) { + String vsRef = ab.getValueSet(); + ValueSet valueset = resolveBindingReference(profile, vsRef, profile.getUrl(), profile); + BindingStrength strength = convertPurposeToStrength(ab.getPurpose()); + + ok = validateBindingCodedElement(errors, path, element, profile, stack, theCode, theSystem, ok, checked, c, vsRef, valueset, strength, null, false) && ok; } } - } else if (binding.hasValueSet()) { - hint(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_CANTCHECK); - } else if (!inCodeableConcept && !noBindingMsgSuppressed) { - hint(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_NOSOURCE, path); + } catch (Exception e) { + if (STACK_TRACE) e.printStackTrace(); + warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_ERROR_CODING1, e.getMessage()); } } } @@ -2065,7 +2014,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_ERROR_CODING2, e.getMessage(), e.toString()); ok = false; } - if (!checked) { + if (!checked.ok()) { ok = rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, theSystem == null || isCodeSystemReferenceValid(theSystem), I18nConstants.TERMINOLOGY_TX_SYSTEM_RELATIVE) && ok; ok = rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, !isValueSet(theSystem), I18nConstants.TERMINOLOGY_TX_SYSTEM_VALUESET2, theSystem) && ok; if (ok) { @@ -2076,6 +2025,71 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return ok; } + private boolean validateBindingCodedElement(List errors, String path, Element element, + StructureDefinition profile, NodeStack stack, String theCode, String theSystem, boolean ok, BooleanHolder checked, + Coding c, String vsRef, ValueSet valueset, BindingStrength strength, Extension vsMax, boolean base) { + if (valueset == null) { + CodeSystem cs = context.fetchCodeSystem(vsRef); + if (rule(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, cs == null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND_CS, describeReference(vsRef))) { + warning(errors, NO_RULE_DATE, IssueType.CODEINVALID, element.line(), element.col(), path, valueset != null, I18nConstants.TERMINOLOGY_TX_VALUESET_NOTFOUND, describeReference(vsRef)); + } else { + ok = false; + } + } else { + BindingContext bc = base ? BindingContext.BASE : BindingContext.ADDITIONAL; + long t = System.nanoTime(); + ValidationResult vr = null; + if (strength != BindingStrength.EXAMPLE) { + checked.set(true); + vr = checkCodeOnServer(stack, valueset, c); + } + ok = processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(strength), strength == BindingStrength.EXTENSIBLE, vsRef) && ok; + + timeTracker.tx(t, "vc "+c.getSystem()+"#"+c.getCode()+" '"+c.getDisplay()+"'"); + if (strength == BindingStrength.REQUIRED) { + removeTrackedMessagesForLocation(errors, element, path); + } + + if (vr != null && !vr.isOk()) { + if (vr.IsNoService()) + txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_BINDING_NOSERVER, theSystem+"#"+theCode); + else if (vr.getErrorClass() != null && !vr.getErrorClass().isInfrastructure()) { + if (strength == BindingStrength.REQUIRED) + ok = txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_4a, describeReference(vsRef, valueset, bc), vr.getMessage(), theSystem+"#"+theCode) && ok; + else if (strength == BindingStrength.EXTENSIBLE) { + if (vsMax != null) + checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringFromExtension(vsMax), c, stack); + else if (!noExtensibleWarnings) + txWarningForLaterRemoval(element, errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_5, describeReference(vsRef, valueset, bc), theSystem+"#"+theCode); + } else if (strength == BindingStrength.PREFERRED) { + if (baseOnly) { + txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_CONFIRM_6, describeReference(vsRef, valueset, bc), theSystem+"#"+theCode); + } + } + } else if (strength == BindingStrength.REQUIRED) + ok = txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_12, describeReference(vsRef, valueset, bc), getErrorMessage(vr.getMessage()), theSystem+"#"+theCode) && ok; + else if (strength == BindingStrength.EXTENSIBLE) { + if (vsMax != null) + ok = checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringFromExtension(vsMax), c, stack) && ok; + else if (!noExtensibleWarnings) { + txWarningForLaterRemoval(element, errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_13, describeReference(vsRef, valueset, bc), getErrorMessage(vr.getMessage()), c.getSystem()+"#"+c.getCode()); + } + } else if (strength == BindingStrength.PREFERRED) { + if (baseOnly) { + txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_14, describeReference(vsRef, valueset, bc), getErrorMessage(vr.getMessage()), theSystem+"#"+theCode); + } + } + } else if (vr != null && vr.getMessage() != null) { + if (vr.getSeverity() == IssueSeverity.INFORMATION) { + txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, vr.getMessage()); + } else { + txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, vr.getMessage()); + } + } + } + return ok; + } + private boolean isValueSet(String url) { try { ValueSet vs = context.fetchResourceWithException(ValueSet.class, url); @@ -3579,7 +3593,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } vr = checkCodeOnServer(stack, vs, value, options); } - ok = processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(binding), binding.getStrength() != BindingStrength.REQUIRED, binding.getValueSet()) && ok; + ok = processTxIssues(errors, vr, element, path, notFoundSeverityForBinding(binding.getStrength()), binding.getStrength() != BindingStrength.REQUIRED, binding.getValueSet()) && ok; timeTracker.tx(t, "vc "+value+""); if (binding.getStrength() == BindingStrength.REQUIRED) { @@ -3591,15 +3605,15 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat } else if (vr.getErrorClass() != null && vr.getErrorClass() == TerminologyServiceErrorClass.CODESYSTEM_UNSUPPORTED) { txWarning(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, vr.getMessage()); } else if (binding.getStrength() == BindingStrength.REQUIRED) { - ok = txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_16, value, describeReference(binding.getValueSet(), vs), getErrorMessage(vr.getMessage())) && ok; + ok = txRule(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_16, value, describeReference(binding.getValueSet(), vs, BindingContext.BASE), getErrorMessage(vr.getMessage())) && ok; } else if (binding.getStrength() == BindingStrength.EXTENSIBLE) { if (binding.hasExtension(ToolingExtensions.EXT_MAX_VALUESET)) ok = checkMaxValueSet(errors, path, element, profile, ToolingExtensions.readStringExtension(binding, ToolingExtensions.EXT_MAX_VALUESET), value, stack) && ok; else if (!noExtensibleWarnings && !isOkExtension(value, vs)) - txWarningForLaterRemoval(element, errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_17, value, describeReference(binding.getValueSet(), vs), getErrorMessage(vr.getMessage())); + txWarningForLaterRemoval(element, errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_17, value, describeReference(binding.getValueSet(), vs, BindingContext.BASE), getErrorMessage(vr.getMessage())); } else if (binding.getStrength() == BindingStrength.PREFERRED) { if (baseOnly) { - txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_18, value, describeReference(binding.getValueSet(), vs), getErrorMessage(vr.getMessage())); + txHint(errors, NO_RULE_DATE, vr.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, false, I18nConstants.TERMINOLOGY_TX_NOVALID_18, value, describeReference(binding.getValueSet(), vs, BindingContext.BASE), getErrorMessage(vr.getMessage())); } } } else if (vr != null && vr.getMessage() != null){ @@ -4311,21 +4325,28 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat return false; } - private String describeReference(String reference, CanonicalResource target) { + private String describeReference(String reference, CanonicalResource target, BindingContext ctxt) { if (reference == null && target == null) return "null"; + String res = null; if (reference == null) { - return target.getVersionedUrl(); + res = target.getVersionedUrl(); + } else if (target == null) { + res = reference; + } else { + String uref = reference.contains("|") ? reference.substring(0, reference.lastIndexOf("|")) : reference; + String vref = reference.contains("|") ? reference.substring(reference.lastIndexOf("|")+1) : null; + if (uref.equals(target.getUrl()) && (vref == null || vref.equals(target.getVersion()))) { + res = "'"+target.present()+"' ("+target.getVersionedUrl()+")"; + } else { + res = reference + "(which actually refers to '"+target.present()+"' (" + target.getVersionedUrl() + "))"; + } } - if (target == null) { - return reference; + switch (ctxt) { + case ADDITIONAL: return context.formatMessage(I18nConstants.BINDING_ADDITIONAL, res); + case MAXVS: return context.formatMessage(I18nConstants.BINDING_MAX, res); + default: return res; } - String uref = reference.contains("|") ? reference.substring(0, reference.lastIndexOf("|")) : reference; - String vref = reference.contains("|") ? reference.substring(reference.lastIndexOf("|")+1) : null; - if (uref.equals(target.getUrl()) && (vref == null || vref.equals(target.getVersion()))) { - return "'"+target.present()+"' ("+target.getVersionedUrl()+")"; - } - return reference + "(which actually refers to '"+target.present()+"' (" + target.getVersionedUrl() + "))"; } private String describeTypes(List types) { diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ValueSetValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ValueSetValidator.java index 981ea9c17..f5d570598 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ValueSetValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/type/ValueSetValidator.java @@ -29,9 +29,15 @@ import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; import org.hl7.fhir.utilities.validation.ValidationOptions; import org.hl7.fhir.validation.BaseValidator; +import org.hl7.fhir.validation.codesystem.BCP47Checker; +import org.hl7.fhir.validation.codesystem.CPTChecker; +import org.hl7.fhir.validation.codesystem.CodeSystemBasedChecker; import org.hl7.fhir.validation.codesystem.CodeSystemChecker; import org.hl7.fhir.validation.codesystem.GeneralCodeSystemChecker; +import org.hl7.fhir.validation.codesystem.LoincChecker; +import org.hl7.fhir.validation.codesystem.RxNormChecker; import org.hl7.fhir.validation.codesystem.SnomedCTChecker; +import org.hl7.fhir.validation.codesystem.UcumChecker; import org.hl7.fhir.validation.instance.InstanceValidator; import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyOperation; import org.hl7.fhir.validation.instance.type.ValueSetValidator.PropertyValidationRules; @@ -66,10 +72,12 @@ public class ValueSetValidator extends BaseValidator { } - public class PropertyValidationRules { + public static class PropertyValidationRules { private PropertyFilterType type; private CodeValidationRule codeValidation; private EnumSet ops; + private List codeList = new ArrayList<>(); + private boolean change; protected PropertyValidationRules(PropertyFilterType type, CodeValidationRule codeValidation, PropertyOperation... ops) { super(); @@ -96,11 +104,27 @@ public class ValueSetValidator extends BaseValidator { public CodeValidationRule getCodeValidation() { return codeValidation; } + public List getCodeList() { + return codeList; + } + public PropertyValidationRules setCodes(String... values) { + for (String v : values) { + codeList.add(v); + } + return this; + } + public boolean isChange() { + return change; + } + public PropertyValidationRules setChange(boolean change) { + this.change = change; + return this; + } } public enum PropertyFilterType { - Boolean, Integer, Decimal, Code, DateTime, Coding + Boolean, Integer, Decimal, Code, DateTime, Coding, CodeList, String } private static final int TOO_MANY_CODES_TO_VALIDATE = 1000; @@ -111,7 +135,18 @@ public class ValueSetValidator extends BaseValidator { } switch (system) { case "http://snomed.info/sct" :return new SnomedCTChecker(context, xverManager, debug, errors); - default: return new GeneralCodeSystemChecker(context, xverManager, debug, errors); + case "http://loinc.org": return new LoincChecker(context, xverManager, debug, errors); + case "http://www.nlm.nih.gov/research/umls/rxnorm": return new RxNormChecker(context, xverManager, debug, errors); + case "http://unitsofmeasure.org": return new UcumChecker(context, xverManager, debug, errors); + case "http://www.ama-assn.org/go/cpt": return new CPTChecker(context, xverManager, debug, errors); + case "urn:ietf:bcp:47": return new BCP47Checker(context, xverManager, debug, errors); + default: + CodeSystem cs = context.fetchCodeSystem(system); + if (cs != null) { + return new CodeSystemBasedChecker(context, xverManager, debug, errors, cs); + } else { + return new GeneralCodeSystemChecker(context, xverManager, debug, errors); + } } } @@ -252,7 +287,7 @@ public class ValueSetValidator extends BaseValidator { List concepts = include.getChildrenByName("concept"); List filters = include.getChildrenByName("filter"); - CodeSystemChecker slv = getSystemValidator(system, errors); + CodeSystemChecker csChecker = getSystemValidator(system, errors); CodeSystem cs = null; if (!Utilities.noString(system)) { cs = context.fetchCodeSystem(system, version); @@ -283,10 +318,10 @@ public class ValueSetValidator extends BaseValidator { for (Element concept : concepts) { // we treat the first differently because we want to know if the system is worth validating. if it is, then we batch the rest if (first) { - systemOk = validateValueSetIncludeConcept(errors, concept, stack, stack.push(concept, cc, null, null), system, version, slv); + systemOk = validateValueSetIncludeConcept(errors, concept, stack, stack.push(concept, cc, null, null), system, version, csChecker); first = false; } else if (systemOk) { - batch.add(prepareValidateValueSetIncludeConcept(errors, concept, stack.push(concept, cc, null, null), system, version, slv)); + batch.add(prepareValidateValueSetIncludeConcept(errors, concept, stack.push(concept, cc, null, null), system, version, csChecker)); } cc++; } @@ -320,10 +355,10 @@ public class ValueSetValidator extends BaseValidator { int cf = 0; for (Element filter : filters) { - ok = validateValueSetIncludeFilter(errors, filter, stack.push(filter, cf, null, null), system, version, cs, slv) & ok; + ok = validateValueSetIncludeFilter(errors, filter, stack.push(filter, cf, null, null), system, version, cs, csChecker) & ok; cf++; } - slv.finish(include, stack); + csChecker.finish(include, stack); } else { warning(errors, NO_RULE_DATE, IssueType.BUSINESSRULE, stack, filters.size() == 0 && concepts.size() == 0, I18nConstants.VALUESET_NO_SYSTEM_WARNING); } @@ -384,41 +419,16 @@ public class ValueSetValidator extends BaseValidator { return new VSCodingValidationRequest(stack, c); } - private boolean validateValueSetIncludeFilter(List errors, Element filter, NodeStack stack, String system, String version, CodeSystem cs, CodeSystemChecker slv) { + private boolean validateValueSetIncludeFilter(List errors, Element filter, NodeStack stack, String system, String version, CodeSystem cs, CodeSystemChecker csChecker) { boolean ok = true; String property = filter.getChildValue("property"); String op = filter.getChildValue("op"); String value = filter.getChildValue("value"); - + if (property != null) { - List knownNames = new ArrayList<>(); - knownNames.add("concept"); - knownNames.add("code"); - knownNames.add("status"); - knownNames.add("inactive"); - knownNames.add("effectiveDate"); - knownNames.add("deprecationDate"); - knownNames.add("retirementDate"); - knownNames.add("notSelectable"); - if (cs == null || cs.hasHierarchyMeaning()) { - knownNames.add("parent"); - knownNames.add("child"); - knownNames.add("partOf"); - } - knownNames.add("synonym"); - knownNames.add("comment"); - knownNames.add("itemWeight"); - if (cs != null) { - for (CodeSystemFilterComponent f : cs.getFilter()) { - addName(knownNames, f.getCode()); - } - for (PropertyComponent p : cs.getProperty()) { - addName(knownNames, p.getCode()); - } - } - for (String s : getSystemKnownNames(system)) { - addName(knownNames, s); - } + List knownNames = new ArrayList(); + csChecker.listPropertyNames(knownNames); + boolean pok = false; if (cs == null) { pok = hint(errors, "2024-03-09", IssueType.INVALID, stack, knownNames.contains(property), I18nConstants.VALUESET_UNKNOWN_FILTER_PROPERTY_NO_CS, property, system, CommaSeparatedStringBuilder.join(",", knownNames)); @@ -426,14 +436,14 @@ public class ValueSetValidator extends BaseValidator { pok = warning(errors, "2024-03-09", IssueType.INVALID, stack, knownNames.contains(property), I18nConstants.VALUESET_UNKNOWN_FILTER_PROPERTY, property, system, CommaSeparatedStringBuilder.join(",", knownNames)); } if (pok) { - PropertyValidationRules rules = rulesForFilter(system, cs, property); + PropertyValidationRules rules = csChecker.rulesForFilter(property, EnumSet.noneOf(PropertyOperation.class)); if (rules != null) { if (!rules.getOps().isEmpty()) { - ok = rule(errors, "2024-03-09", IssueType.INVALID, stack, opInSet(op, rules.getOps()), I18nConstants.VALUESET_BAD_FILTER_OP, op, property, CommaSeparatedStringBuilder.join(",", rules.getOps())) && ok; + ok = rule(errors, "2024-03-09", IssueType.INVALID, stack, opInSet(op, rules.getOps()), I18nConstants.VALUESET_BAD_FILTER_OP, op, property, CommaSeparatedStringBuilder.join(",", rules.getOps()), system) && ok; } if ("exists".equals(op)) { - ok = checkFilterValue(errors, stack, system, version, ok, property, op, value, PropertyFilterType.Boolean, null) && ok; + ok = checkFilterValue(errors, stack, system, version, ok, property, op, value, new PropertyValidationRules(PropertyFilterType.Boolean, null)) && ok; } else if ("regex".equals(op)) { String err = null; try { @@ -445,10 +455,10 @@ public class ValueSetValidator extends BaseValidator { ok = rule(errors, "2024-03-09", IssueType.INVALID, stack, !"concept".equals(property), I18nConstants.VALUESET_BAD_PROPERTY_NO_REGEX, property) && ok; } else if (Utilities.existsInList(op, "in", "not-in")) { for (String v : value.split("\\,")) { - ok = checkFilterValue(errors, stack, system, version, ok, property, op, v, rules.getType(), rules.getCodeValidation()) && ok; + ok = checkFilterValue(errors, stack, system, version, ok, property, op, v, rules) && ok; } } else { - ok = checkFilterValue(errors, stack, system, version, ok, property, op, value, rules.getType(), rules.getCodeValidation()) && ok; + ok = checkFilterValue(errors, stack, system, version, ok, property, op, value, rules) && ok; } } } @@ -474,30 +484,36 @@ public class ValueSetValidator extends BaseValidator { return false; } - private boolean checkFilterValue(List errors, NodeStack stack, String system, String version,boolean ok, String property, String op, String value, PropertyFilterType type, CodeValidationRule cr) { - if (type != null) { + private boolean checkFilterValue(List errors, NodeStack stack, String system, String version,boolean ok, String property, String op, String value, PropertyValidationRules rules) { + if (rules.getType() != null) { if (!Utilities.existsInList(op, "in", "not-in")) { - hint(errors, "2024-03-09", IssueType.INVALID, stack.getLiteralPath(), !value.contains(","), I18nConstants.VALUESET_BAD_FILTER_VALUE_HAS_COMMA, type.toString()); + hint(errors, "2024-03-09", IssueType.INVALID, stack.getLiteralPath(), !value.contains(","), I18nConstants.VALUESET_BAD_FILTER_VALUE_HAS_COMMA, rules.getType().toString()); } - switch (type) { + switch (rules.getType()) { case Boolean: ok = rule(errors, "2024-03-09", IssueType.INVALID, stack, Utilities.existsInList(value, "true", "false"), I18nConstants.VALUESET_BAD_FILTER_VALUE_BOOLEAN, property, value) && ok; break; + case String: + // nothing to check + break; case Code: ok = rule(errors, "2024-03-09", IssueType.INVALID, stack, value.trim().equals(value), I18nConstants.VALUESET_BAD_FILTER_VALUE_CODE, property, value) && ok; - if (cr == CodeValidationRule.Error || cr == CodeValidationRule.Warning) { + if (rules.getCodeValidation() == CodeValidationRule.Error || rules.getCodeValidation() == CodeValidationRule.Warning) { ValidationResult vr = context.validateCode(baseOptions, system, version, value, null); - if (cr == CodeValidationRule.Error) { - ok = rule(errors, "2024-03-09", IssueType.INVALID, stack.getLiteralPath(), vr.isOk(), I18nConstants.VALUESET_BAD_FILTER_VALUE_VALID_CODE, property, value, system, vr.getMessage()) && ok; + if (rules.getCodeValidation() == CodeValidationRule.Error) { + ok = rule(errors, "2024-03-09", IssueType.INVALID, stack.getLiteralPath(), vr.isOk(), rules.isChange() ? I18nConstants.VALUESET_BAD_FILTER_VALUE_VALID_CODE_CHANGE : I18nConstants.VALUESET_BAD_FILTER_VALUE_VALID_CODE, property, value, system, vr.getMessage()) && ok; } else { - warning(errors, "2024-03-09", IssueType.INVALID, stack.getLiteralPath(), vr.isOk(), I18nConstants.VALUESET_BAD_FILTER_VALUE_VALID_CODE, property, value, system, vr.getMessage()); + warning(errors, "2024-03-09", IssueType.INVALID, stack.getLiteralPath(), vr.isOk(), rules.isChange() ? I18nConstants.VALUESET_BAD_FILTER_VALUE_VALID_CODE_CHANGE : I18nConstants.VALUESET_BAD_FILTER_VALUE_VALID_CODE, property, value, system, vr.getMessage()); } } break; + case CodeList: + ok = rule(errors, "2024-05-12", IssueType.INVALID, stack.getLiteralPath(), rules.getCodeList().contains(value), I18nConstants.VALUESET_BAD_FILTER_VALUE_DATETIME, property, value) && ok; + break; case DateTime: ok = rule(errors, "2024-03-09", IssueType.INVALID, stack.getLiteralPath(), value.matches("([0-9]([0-9]([0-9][1-9]|[1-9]0)|[1-9]00)|[1-9]000)(-(0[1-9]|1[0-2])(-(0[1-9]|[1-2][0-9]|3[0-1])(T([01][0-9]|2[0-3]):[0-5][0-9]:([0-5][0-9]|60)(\\.[0-9]+)?(Z|(\\+|-)((0[0-9]|1[0-3]):[0-5][0-9]|14:00))?)?)?)?"), @@ -529,147 +545,5 @@ public class ValueSetValidator extends BaseValidator { return ok; } - private PropertyValidationRules rulesForFilter(String system, CodeSystem cs, String property) { - var ops = EnumSet.noneOf(PropertyOperation.class); - - if (cs != null) { - - for (CodeSystemFilterComponent f : cs.getFilter()) { - if (property.equals(f.getCode())) { - for (Enumeration op : f.getOperator()) { - ops.add(toOp(op)); - } - } - } - - for (PropertyComponent p : cs.getProperty()) { - if (property.equals(p.getCode())) { - if (p.getType() != null) { - switch (p.getType()) { - case BOOLEAN: return new PropertyValidationRules(PropertyFilterType.Boolean, null, ops); - case CODE: - // the definitions say " a code that identifies a concept defined in the code system" -> ValidCode. - // but many people have ignored that and defined a property as 'code' because it's from a list of values that are otherwise undefined - boolean external = !forPublication || cs.getWebPath() == null || Utilities.isAbsoluteUrl(cs.getWebPath()); - return new PropertyValidationRules(PropertyFilterType.Code, external ? CodeValidationRule.Warning : CodeValidationRule.Error, ops); // valid code... the definitions say that, but people were missing that in the pastm - case CODING: return new PropertyValidationRules(PropertyFilterType.Coding, null, ops); - case DATETIME: return new PropertyValidationRules(PropertyFilterType.DateTime, null, ops); - case DECIMAL: return new PropertyValidationRules(PropertyFilterType.Decimal, null, ops); - case INTEGER: return new PropertyValidationRules(PropertyFilterType.Integer, null, ops); - case STRING: return null; - } - } - } - } - } - - switch (property) { - case "concept" : return new PropertyValidationRules(PropertyFilterType.Code, CodeValidationRule.Error, addToOps(ops, PropertyOperation.Equals, PropertyOperation.In, PropertyOperation.IsA, PropertyOperation.DescendentOf, PropertyOperation.DescendentLeaf, PropertyOperation.IsNotA, PropertyOperation.NotIn)); - case "code" : return new PropertyValidationRules(PropertyFilterType.Code, CodeValidationRule.Error, addToOps(ops, PropertyOperation.Equals, PropertyOperation.RegEx)); - case "status" : return new PropertyValidationRules(PropertyFilterType.Code, CodeValidationRule.None, ops); - case "inactive" : return new PropertyValidationRules(PropertyFilterType.Boolean,null, ops); - case "effectiveDate" : return new PropertyValidationRules(PropertyFilterType.DateTime, null, ops); - case "deprecationDate" : return new PropertyValidationRules(PropertyFilterType.DateTime, null, ops); - case "retirementDate" : return new PropertyValidationRules(PropertyFilterType.DateTime, null, ops); - case "notSelectable" : return new PropertyValidationRules(PropertyFilterType.Boolean, null, ops); - case "parent" : return new PropertyValidationRules(PropertyFilterType.Code, CodeValidationRule.Error, ops); - case "child" : return new PropertyValidationRules(PropertyFilterType.Code, CodeValidationRule.Error, ops); - case "partOf" : return new PropertyValidationRules(PropertyFilterType.Code, CodeValidationRule.Error, ops); - case "synonym" : return new PropertyValidationRules(PropertyFilterType.Code, CodeValidationRule.None, ops); // ? none? - case "comment" : return null; - case "itemWeight" : return new PropertyValidationRules(PropertyFilterType.Decimal, null, ops); - } - switch (system) { - case "http://loinc.org" : - if (Utilities.existsInList(property, "copyright", "STATUS", "CLASS", "CONSUMER_NAME", "ORDER_OBS", "DOCUMENT_SECTION", "SCALE_TYP")) { - return new PropertyValidationRules(PropertyFilterType.Code, CodeValidationRule.None); - } else if ("CLASSTYPE".equals(property)) { - return new PropertyValidationRules(PropertyFilterType.Integer, null, addToOps(ops, PropertyOperation.Equals, PropertyOperation.In)); - } else { - return new PropertyValidationRules(PropertyFilterType.Code, CodeValidationRule.Error, addToOps(ops, PropertyOperation.Equals, PropertyOperation.In)); - } - case "http://snomed.info/sct": - switch (property) { - case "constraint": return null; // for now - case "expressions": return new PropertyValidationRules(PropertyFilterType.Boolean, null, addToOps(ops, PropertyOperation.Equals, PropertyOperation.In)); - default: - return new PropertyValidationRules(PropertyFilterType.Code, CodeValidationRule.Error, addToOps(ops, PropertyOperation.Equals, PropertyOperation.In)); - } - case "http://www.nlm.nih.gov/research/umls/rxnorm" : return new PropertyValidationRules(PropertyFilterType.Code, CodeValidationRule.None, ops); - case "http://unitsofmeasure.org" : return new PropertyValidationRules(PropertyFilterType.Code, CodeValidationRule.None, ops); - case "http://www.ama-assn.org/go/cpt" : - switch (property) { - case "modifier": return new PropertyValidationRules(PropertyFilterType.Boolean, null, ops); - case "kind" : return new PropertyValidationRules(PropertyFilterType.Code, CodeValidationRule.None, ops); // for now - case "modified": return new PropertyValidationRules(PropertyFilterType.Boolean, null, ops); - case "code" : return null; - case "telemedicine": return new PropertyValidationRules(PropertyFilterType.Boolean, null, ops); - case "orthopox" : return new PropertyValidationRules(PropertyFilterType.Boolean,null, ops); - } - } - if (ops != null) { - return new PropertyValidationRules(null, null, ops); - } else { - return null; - } - - } - - - private EnumSet addToOps(EnumSet set, PropertyOperation... ops) { - for (PropertyOperation op : ops) { - set.add(op); - } - return set; - } - - private PropertyOperation toOp(Enumeration op) { - switch (op.getValue()) { - case CHILDOF: return PropertyOperation.ChildOf; - case DESCENDENTLEAF: return PropertyOperation.DescendentLeaf; - case DESCENDENTOF: return PropertyOperation.DescendentOf; - case EQUAL: return PropertyOperation.Equals; - case EXISTS: return PropertyOperation.Exists; - case GENERALIZES: return PropertyOperation.Generalizes; - case IN: return PropertyOperation.In; - case ISA: return PropertyOperation.IsA; - case ISNOTA: return PropertyOperation.IsNotA; - case NOTIN: return PropertyOperation.NotIn; - case REGEX: return PropertyOperation.RegEx; - default: return null; - } - } - private void addName(List knownNames, String code) { - if (code != null && !knownNames.contains(code)) { - knownNames.add(code); - } - } - - private String[] getSystemKnownNames(String system) { - switch (system) { - case "http://loinc.org" : return new String[] {"parent", "ancestor", "copyright", "STATUS", "COMPONENT", "PROPERTY", "TIME_ASPCT", "SYSTEM", "SCALE_TYP", "METHOD_TYP", "CLASS", "CONSUMER_NAME", "CLASSTYPE", "ORDER_OBS", "DOCUMENT_SECTION"}; - - case "http://snomed.info/sct": return new String[] { "constraint", "expressions", "410662002", "42752001", "47429007", "116676008", "116686009", "118168003", "118169006", "118170007", "118171006", "127489000", "131195008", - "246075003", "246090004", "246093002", "246112005", "246454002", "246456000", "246501002", "246513007", "246514001", "255234002", "260507000", - "260686004", "260870009", "263502005", "272741003", "288556008", "363589002", "363698007", "363699004", "363700003", "363701004", "363702006", - "363703001", "363704007", "363705008", "363709002", "363710007", "363713009", "363714003", "370129005", "370130000", "370131001", "370132008", - "370133003", "370134009", "370135005", "371881003", "405813007", "405814001", "405815000", "405816004", "408729009", "408730004", "408731000", - "408732007", "410675002", "411116001", "418775008", "419066007", "424226004", "424244007", "424361007", "424876005", "425391005", "609096000", - "704319004", "704320005", "704321009", "704322002", "704323007", "704324001", "704325000", "704326004", "704327008", "704346009", "704347000", - "704647008", "718497002", "719715003", "719722006", "726542003", "726633004", "732943007", "732945000", "732947008", "733722007", "733725009", - "733928003", "733930001", "733931002", "733932009", "733933004", "734136001", "734137005", "736472000", "736473005", "736474004", "736475003", - "736476002", "736518005", "738774007", "762705008", "762706009", "762949000", "762951001", "763032000", "766939001", "774081006", "774158006", - "774159003", "774160008", "774163005", "827081001", "836358009", "840560000", "860779006", "860781008", "1003703000", "1003735000", "1142135004", - "1142136003", "1142137007", "1142138002", "1142139005", "1142140007", "1142141006", "1142142004", "1142143009", "1148793005", "1148965004", - "1148967007", "1148968002", "1148969005", "1149366004", "1149367008", "1230370004", "320091000221107" }; - // list from http://tx.fhir.org/r4/ValueSet/$expand?url=http://snomed.info/sct?fhir_vs=isa/410662002 - - case "http://www.nlm.nih.gov/research/umls/rxnorm" : return new String[] { "STY", "SAB", "TTY", "SY", "SIB", "RN", "PAR", "CHD", "RB", "RO", "IN", "PIN", "MIN", "BN", "SCD", "SBD", "GPCK", "BPCK", "SCDC", "SCDF", "SCDFP", "SCDG", "SCDGP", "SBDC", "SBDF", "SBDFP", "SBDG", "DF", "DFG" }; - case "http://unitsofmeasure.org" : return new String[] { "property", "canonical" }; - case "http://www.ama-assn.org/go/cpt" : return new String[] { "modifier", "kind", "modified", "code", "telemedicine", "orthopox" }; - case "urn:ietf:bcp:47" : return new String[] {"language", "region", "script", "variant", "extension", "ext-lang", "private-use" }; - default: return new String[] { }; - } - } } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxTester.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxTester.java index 010a95059..d48a135a3 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxTester.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxTester.java @@ -100,7 +100,7 @@ public class TxTester { for (JsonObject suite : tests.getJsonObjects("suites")) { if ((!suite.has("mode") || modes.contains(suite.asString("mode")))) { if (suite.asBoolean("disabled")) { - ok = true; + // ok = true; } else { ok = runSuite(suite, tx, modes, filter, json.forceArray("suites")) && ok; } diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxTesterSorters.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxTesterSorters.java index 12609e7f1..35d069e8a 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxTesterSorters.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/special/TxTesterSorters.java @@ -195,7 +195,6 @@ public class TxTesterSorters { } return res; } - } @@ -220,9 +219,9 @@ public class TxTesterSorters { } } if (o1.getName().equals(o2.getName()) && o1.getName().equals("designation")) { - String code1 = o1.getPart("language").hasValue() ? o1.getPart("language").getValue().primitiveValue().toLowerCase() : ""; - String code2 = o2.getPart("language").hasValue() ? o2.getPart("language").getValue().primitiveValue().toLowerCase() : ""; - if (code1 != null && code2 != null && !code1.equals(code2)) { + String code1 = o1.hasPart("language") && o1.getPart("language").hasValue() && o1.getPart("language").getValue().primitiveValue() != null ? o1.getPart("language").getValue().primitiveValue().toLowerCase() : ""; + String code2 = o2.hasPart("language") && o2.getPart("language").hasValue() && o2.getPart("language").getValue().primitiveValue() != null ? o2.getPart("language").getValue().primitiveValue().toLowerCase() : ""; + if (code1 != null && code2 != null && !code1.equals(code2)) { return code1.compareTo(code2); } String v1 = o1.getPart("value") != null && o1.getPart("value").hasPrimitiveValue() ? o1.getPart("value").getValue().primitiveValue().toLowerCase() : null; diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/terminology/tests/OntoserverTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/terminology/tests/OntoserverTests.java new file mode 100644 index 000000000..3aee51e4d --- /dev/null +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/terminology/tests/OntoserverTests.java @@ -0,0 +1,169 @@ +package org.hl7.fhir.terminology.tests; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.*; + +import org.apache.commons.io.IOUtils; +import org.hl7.fhir.convertors.factory.VersionConvertorFactory_10_50; +import org.hl7.fhir.convertors.factory.VersionConvertorFactory_14_50; +import org.hl7.fhir.convertors.factory.VersionConvertorFactory_30_50; +import org.hl7.fhir.convertors.factory.VersionConvertorFactory_40_50; +import org.hl7.fhir.exceptions.DefinitionException; +import org.hl7.fhir.exceptions.FHIRException; +import org.hl7.fhir.exceptions.FHIRFormatError; +import org.hl7.fhir.r5.formats.JsonParser; +import org.hl7.fhir.r5.formats.XmlParser; +import org.hl7.fhir.r5.model.Constants; +import org.hl7.fhir.r5.model.Resource; +import org.hl7.fhir.r5.test.utils.TestingUtilities; +import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.utilities.filesystem.ManagedFileAccess; +import org.hl7.fhir.utilities.json.model.JsonObject; +import org.hl7.fhir.utilities.settings.FhirSettings; +import org.hl7.fhir.utilities.tests.TestConfig; +import org.hl7.fhir.validation.special.TxTester; +import org.hl7.fhir.validation.special.TxTester.ITxTesterLoader; +import org.hl7.fhir.validation.tests.utilities.TestUtilities; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import com.google.common.base.Charsets; + +@RunWith(Parameterized.class) + +public class OntoserverTests implements ITxTesterLoader { + + public static class JsonObjectPair { + public JsonObjectPair(JsonObject suite, JsonObject test) { + this.suite = suite; + this.test = test; + } + private JsonObject suite; + private JsonObject test; + } + + private static final String SERVER = "https://tx.ontoserver.csiro.au/fhir"; + + private static boolean localTxRunning() throws IOException { + return ManagedFileAccess.file("/Users/grahamegrieve/work/server/server").exists(); + } + + + + @Parameters(name = "{index}: id {0}") + public static Iterable data() throws IOException { + + String contents = TestingUtilities.loadTestResource("tx", "test-cases.json"); + externals = org.hl7.fhir.utilities.json.parser.JsonParser.parseObject(TestingUtilities.loadTestResource("tx", "messages-tx.fhir.org.json")); + + Map examples = new HashMap(); + manifest = org.hl7.fhir.utilities.json.parser.JsonParser.parseObject(contents); + for (org.hl7.fhir.utilities.json.model.JsonObject suite : manifest.getJsonObjects("suites")) { + String sn = suite.asString("name"); + for (org.hl7.fhir.utilities.json.model.JsonObject test : suite.getJsonObjects("tests")) { + String tn = test.asString("name"); + examples.put(sn+"."+tn, new JsonObjectPair(suite, test)); + } + } + + List names = new ArrayList(examples.size()); + names.addAll(examples.keySet()); + Collections.sort(names); + + List objects = new ArrayList(examples.size()); + for (String id : names) { + objects.add(new Object[]{id, examples.get(id)}); + } + return objects; + } + + private static org.hl7.fhir.utilities.json.model.JsonObject manifest; + private static org.hl7.fhir.utilities.json.model.JsonObject externals; + private JsonObjectPair setup; + private String version = "5.0.0"; + private static TxTester tester; + private List modes = new ArrayList<>(); + + public OntoserverTests(String name, JsonObjectPair setup) { + this.setup = setup; + modes.add("flat"); + } + + @SuppressWarnings("deprecation") + @Test + public void test() throws Exception { + if (TestUtilities.runningAsSurefire()) { + logTestSkip("Running in surefire."); + return; + } + if (!localTxRunning()) { + logTestSkip("No local terminology server available."); + return; + } + if (tester == null) { + tester = new TxTester(this, SERVER, true, externals); + } + String err = tester.executeTest(setup.suite, setup.test, modes); + Assertions.assertTrue(true); // we don't care what the result is, only that we didn't crash + + } + + private void logTestSkip(String reason) { + System.out.println("Skipping test: " + setup.suite.asString("name") + " " + setup.test.asString("name") + " reason: " + reason); + } + + public Resource loadResource(String filename) throws IOException, FHIRFormatError, FileNotFoundException, FHIRException, DefinitionException { + String contents = TestingUtilities.loadTestResource("tx", filename); + Resource res = null; + try (InputStream inputStream = IOUtils.toInputStream(contents, Charsets.UTF_8)) { + if (filename.contains(".json")) { + if (Constants.VERSION.equals(version) || "5.0".equals(version)) + res = new JsonParser().parse(inputStream); + else if (org.hl7.fhir.dstu3.model.Constants.VERSION.equals(version) || "3.0".equals(version)) + res = VersionConvertorFactory_30_50.convertResource(new org.hl7.fhir.dstu3.formats.JsonParser().parse(inputStream)); + else if (org.hl7.fhir.dstu2016may.model.Constants.VERSION.equals(version) || "1.4".equals(version)) + res = VersionConvertorFactory_14_50.convertResource(new org.hl7.fhir.dstu2016may.formats.JsonParser().parse(inputStream)); + else if (org.hl7.fhir.dstu2.model.Constants.VERSION.equals(version) || "1.0".equals(version)) + res = VersionConvertorFactory_10_50.convertResource(new org.hl7.fhir.dstu2.formats.JsonParser().parse(inputStream)); + else if (org.hl7.fhir.r4.model.Constants.VERSION.equals(version) || "4.0".equals(version)) + res = VersionConvertorFactory_40_50.convertResource(new org.hl7.fhir.r4.formats.JsonParser().parse(inputStream)); + else + throw new FHIRException("unknown version " + version); + } else { + if (Constants.VERSION.equals(version) || "5.0".equals(version)) + res = new XmlParser().parse(inputStream); + else if (org.hl7.fhir.dstu3.model.Constants.VERSION.equals(version) || "3.0".equals(version)) + res = VersionConvertorFactory_30_50.convertResource(new org.hl7.fhir.dstu3.formats.XmlParser().parse(inputStream)); + else if (org.hl7.fhir.dstu2016may.model.Constants.VERSION.equals(version) || "1.4".equals(version)) + res = VersionConvertorFactory_14_50.convertResource(new org.hl7.fhir.dstu2016may.formats.XmlParser().parse(inputStream)); + else if (org.hl7.fhir.dstu2.model.Constants.VERSION.equals(version) || "1.0".equals(version)) + res = VersionConvertorFactory_10_50.convertResource(new org.hl7.fhir.dstu2.formats.XmlParser().parse(inputStream)); + else if (org.hl7.fhir.r4.model.Constants.VERSION.equals(version) || "4.0".equals(version)) + res = VersionConvertorFactory_40_50.convertResource(new org.hl7.fhir.r4.formats.XmlParser().parse(inputStream)); + else + throw new FHIRException("unknown version " + version); + } + } + org.hl7.fhir.r4.model.Resource r4 = VersionConvertorFactory_40_50.convertResource(res); + String p = Utilities.path(FhirSettings.getFhirTestCasesPath(), "tx", "r4", filename); + Utilities.createDirectory(Utilities.getDirectoryForFile(p)); + new org.hl7.fhir.r4.formats.JsonParser().compose(ManagedFileAccess.outStream(p), r4); + return res; + } + + @Override + public String describe() { + return "Test cases"; + } + + @Override + public byte[] loadContent(String filename) throws FileNotFoundException, IOException { + return TestingUtilities.loadTestResourceBytes("tx", filename); + } +} \ No newline at end of file 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 d0bdbdd3d..1f48dd94d 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 @@ -7399,7 +7399,6 @@ v: { "error" : "Unknown code 'test' in the CodeSystem 'http://loinc.org' version '2.77'", "class" : "UNKNOWN", "server" : "http://tx-dev.fhir.org/r4", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome", "issue" : [{ @@ -7423,3 +7422,67 @@ v: { } ------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://loinc.org", + "code" : "100066-0" +}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"false", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"false", "profile": { + "resourceType" : "Parameters", + "parameter" : [{ + "name" : "profile-url", + "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891" + }] +}}#### +v: { + "display" : "Specular microscopy panel", + "code" : "100066-0", + "system" : "http://loinc.org", + "version" : "2.77", + "server" : "http://tx-dev.fhir.org/r4", + "unknown-systems" : "", + "issues" : { + "resourceType" : "OperationOutcome" +} + +} +------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://loinc.org", + "code" : "100066-0" +}, "url": "http://hl7.org/fhir/test/StructureDefinition/additional-bindings-vs1--0", "version": "1.0.0", "langs":"", "useServer":"true", "useClient":"false", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"false", "profile": { + "resourceType" : "Parameters", + "parameter" : [{ + "name" : "profile-url", + "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891" + }] +}}#### +v: { + "display" : "Specular microscopy panel", + "code" : "100066-0", + "severity" : "error", + "error" : "The provided code 'http://loinc.org#100066-0' was not found in the value set 'http://hl7.org/fhir/test/StructureDefinition/additional-bindings-vs1--0|1.0.0'", + "class" : "UNKNOWN", + "server" : "http://tx-dev.fhir.org/r4", + "unknown-systems" : "", + "issues" : { + "resourceType" : "OperationOutcome", + "issue" : [{ + "extension" : [{ + "url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-server", + "valueUrl" : "http://tx-dev.fhir.org/r4" + }], + "severity" : "error", + "code" : "code-invalid", + "details" : { + "coding" : [{ + "system" : "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", + "code" : "not-in-vs" + }], + "text" : "The provided code 'http://loinc.org#100066-0' was not found in the value set 'http://hl7.org/fhir/test/StructureDefinition/additional-bindings-vs1--0|1.0.0'" + }, + "location" : ["Coding.code"], + "expression" : ["Coding.code"] + }] +} + +} +------------------------------------------------------------------------------------- diff --git a/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/5.0.0/loinc.cache b/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/5.0.0/loinc.cache index 614b640cb..954ed06a8 100644 --- a/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/5.0.0/loinc.cache +++ b/org.hl7.fhir.validation/src/test/resources/txCache/org.hl7.fhir.validation/5.0.0/loinc.cache @@ -1026,7 +1026,6 @@ v: { "error" : "Unknown code 'LP43571-6' in the CodeSystem 'http://loinc.org' version '2.77'", "class" : "UNKNOWN", "server" : "http://tx-dev.fhir.org/r4", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome", "issue" : [{ @@ -1050,3 +1049,67 @@ v: { } ------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://loinc.org", + "code" : "100066-0" +}, "valueSet" :null, "langs":"", "useServer":"true", "useClient":"false", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"false", "profile": { + "resourceType" : "Parameters", + "parameter" : [{ + "name" : "profile-url", + "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891" + }] +}}#### +v: { + "display" : "Specular microscopy panel", + "code" : "100066-0", + "system" : "http://loinc.org", + "version" : "2.77", + "server" : "http://tx-dev.fhir.org/r4", + "unknown-systems" : "", + "issues" : { + "resourceType" : "OperationOutcome" +} + +} +------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://loinc.org", + "code" : "100066-0" +}, "url": "http://hl7.org/fhir/test/StructureDefinition/additional-bindings-vs1--0", "version": "1.0.0", "langs":"", "useServer":"true", "useClient":"false", "guessSystem":"false", "activeOnly":"false", "membershipOnly":"false", "displayWarningMode":"false", "versionFlexible":"false", "profile": { + "resourceType" : "Parameters", + "parameter" : [{ + "name" : "profile-url", + "valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891" + }] +}}#### +v: { + "display" : "Specular microscopy panel", + "code" : "100066-0", + "severity" : "error", + "error" : "The provided code 'http://loinc.org#100066-0' was not found in the value set 'http://hl7.org/fhir/test/StructureDefinition/additional-bindings-vs1--0|1.0.0'", + "class" : "UNKNOWN", + "server" : "http://tx-dev.fhir.org/r4", + "unknown-systems" : "", + "issues" : { + "resourceType" : "OperationOutcome", + "issue" : [{ + "extension" : [{ + "url" : "http://hl7.org/fhir/StructureDefinition/operationoutcome-issue-server", + "valueUrl" : "http://tx-dev.fhir.org/r4" + }], + "severity" : "error", + "code" : "code-invalid", + "details" : { + "coding" : [{ + "system" : "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type", + "code" : "not-in-vs" + }], + "text" : "The provided code 'http://loinc.org#100066-0' was not found in the value set 'http://hl7.org/fhir/test/StructureDefinition/additional-bindings-vs1--0|1.0.0'" + }, + "location" : ["Coding.code"], + "expression" : ["Coding.code"] + }] +} + +} +-------------------------------------------------------------------------------------