Merge pull request #1244 from hapifhir/gg-202305-map-validation

Gg 202305 map validation
This commit is contained in:
Grahame Grieve 2023-05-01 22:33:23 +10:00 committed by GitHub
commit b705ea4d6c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 439 additions and 97 deletions

View File

@ -801,25 +801,17 @@ public class StructureMap40_50 {
return tgt;
}
public static org.hl7.fhir.r5.model.DataType convertVariableStringToParameterDataType(org.hl7.fhir.r4.model.StringType it) {
org.hl7.fhir.r4.model.Extension originalElementType = it.getExtensionByUrl(ToolingExtensions.EXT_ORIGINAL_ELEMENT_TYPE);
return originalElementType != null ? convertVariableStringToParameterDataType(it, originalElementType) : convertVariableStringToGuessedParameterDataType(it);
}
public static org.hl7.fhir.r5.model.DataType convertVariableStringToParameterDataType(org.hl7.fhir.r4.model.StringType it, org.hl7.fhir.r4.model.Extension originalElementType) {
if (!(originalElementType.getValue() instanceof org.hl7.fhir.r4.model.UrlType)) {
throw new FHIRException("");
}
org.hl7.fhir.r4.model.UrlType url = (org.hl7.fhir.r4.model.UrlType)originalElementType.getValue();
switch (url.getValueAsString()) {
case "id" : return it.hasValue() ? new org.hl7.fhir.r5.model.IdType(it.getValueAsString()) : new org.hl7.fhir.r5.model.IdType();
case "string" : return it.hasValue() ? new org.hl7.fhir.r5.model.StringType(it.getValueAsString()) : new org.hl7.fhir.r5.model.StringType();
case "integer" : return it.hasValue() ? new org.hl7.fhir.r5.model.IntegerType(it.getValueAsString()) : new org.hl7.fhir.r5.model.IntegerType();
case "decimal" : return it.hasValue() ? new org.hl7.fhir.r5.model.DecimalType(it.getValueAsString()) : new org.hl7.fhir.r5.model.DecimalType();
case "boolean" : return it.hasValue() ? new org.hl7.fhir.r5.model.BooleanType(it.getValueAsString()) : new org.hl7.fhir.r5.model.BooleanType();
}
return null;
public static org.hl7.fhir.r5.model.DataType convertVariableStringToParameterDataType(org.hl7.fhir.r4.model.StringType src) {
if (src.hasExtension(ToolingExtensions.EXT_ORIGINAL_VARIABLE_TYPE)) {
return ConversionContext40_50.INSTANCE.getVersionConvertor_40_50().convertType(src.getExtensionByUrl(ToolingExtensions.EXT_ORIGINAL_VARIABLE_TYPE).getValue());
} else {
org.hl7.fhir.r5.model.IdType tgt = new org.hl7.fhir.r5.model.IdType();
ConversionContext40_50.INSTANCE.getVersionConvertor_40_50().copyElement(src, tgt);
if (src.hasValue()) {
tgt.setValueAsString(src.getValueAsString());
}
return tgt;
}
}
public static org.hl7.fhir.r5.model.DataType convertVariableStringToGuessedParameterDataType(org.hl7.fhir.r4.model.StringType it) {
@ -860,24 +852,12 @@ public class StructureMap40_50 {
public static org.hl7.fhir.r4.model.StringType convertStructureMapGroupRuleTargetParameterComponentToString(StructureMapGroupRuleTargetParameterComponent src) {
org.hl7.fhir.r4.model.StringType tgt = new org.hl7.fhir.r4.model.StringType();
org.hl7.fhir.instance.model.api.IPrimitiveType primitiveType;
if (src.hasValueIdType()) {
primitiveType = src.getValueIdType();
} else if (src.hasValueStringType()) {
primitiveType = src.getValueStringType();
} else if (src.hasValueIntegerType()) {
primitiveType = src.getValueIntegerType();
} else if (src.hasValueDecimalType()) {
primitiveType = src.getValueDecimalType();
} else if (src.hasValueBooleanType()) {
primitiveType = src.getValueBooleanType();
} else {
throw new FHIRException("Unrecognized primitive type");
}
tgt.setValueAsString(primitiveType.getValueAsString());
ToolingExtensions.addUrlExtension(tgt, ToolingExtensions.EXT_ORIGINAL_ELEMENT_TYPE, primitiveType.fhirType());
ConversionContext40_50.INSTANCE.getVersionConvertor_40_50().copyElement(src, tgt);
if (src.hasValueIdType()) {
tgt.setValueAsString(src.getValueIdType().getValueAsString());
} else if (src.hasValue()) {
tgt.addExtension(ToolingExtensions.EXT_ORIGINAL_VARIABLE_TYPE,ConversionContext40_50.INSTANCE.getVersionConvertor_40_50().convertType(src.getValue()));
}
return tgt;
}
}

View File

@ -2,6 +2,7 @@ package org.hl7.fhir.convertors.conv43_50.resources43_50;
import java.util.stream.Collectors;
import org.hl7.fhir.convertors.context.ConversionContext40_50;
import org.hl7.fhir.convertors.context.ConversionContext43_50;
import org.hl7.fhir.convertors.conv43_50.datatypes43_50.general43_50.CodeableConcept43_50;
import org.hl7.fhir.convertors.conv43_50.datatypes43_50.general43_50.Identifier43_50;
@ -801,25 +802,17 @@ public class StructureMap43_50 {
return tgt;
}
public static org.hl7.fhir.r5.model.DataType convertVariableStringToParameterDataType(org.hl7.fhir.r4b.model.StringType it) {
org.hl7.fhir.r4b.model.Extension originalElementType = it.getExtensionByUrl(ToolingExtensions.EXT_ORIGINAL_ELEMENT_TYPE);
return originalElementType != null ? convertVariableStringToParameterDataType(it, originalElementType) : convertVariableStringToGuessedParameterDataType(it);
}
public static org.hl7.fhir.r5.model.DataType convertVariableStringToParameterDataType(org.hl7.fhir.r4b.model.StringType it, org.hl7.fhir.r4b.model.Extension originalElementType) {
if (!(originalElementType.getValue() instanceof org.hl7.fhir.r4b.model.UrlType)) {
throw new FHIRException("");
}
org.hl7.fhir.r4b.model.UrlType url = (org.hl7.fhir.r4b.model.UrlType)originalElementType.getValue();
switch (url.getValueAsString()) {
case "id" : return it.hasValue() ? new org.hl7.fhir.r5.model.IdType(it.getValueAsString()) : new org.hl7.fhir.r5.model.IdType();
case "string" : return it.hasValue() ? new org.hl7.fhir.r5.model.StringType(it.getValueAsString()) : new org.hl7.fhir.r5.model.StringType();
case "integer" : return it.hasValue() ? new org.hl7.fhir.r5.model.IntegerType(it.getValueAsString()) : new org.hl7.fhir.r5.model.IntegerType();
case "decimal" : return it.hasValue() ? new org.hl7.fhir.r5.model.DecimalType(it.getValueAsString()) : new org.hl7.fhir.r5.model.DecimalType();
case "boolean" : return it.hasValue() ? new org.hl7.fhir.r5.model.BooleanType(it.getValueAsString()) : new org.hl7.fhir.r5.model.BooleanType();
}
return null;
public static org.hl7.fhir.r5.model.DataType convertVariableStringToParameterDataType(org.hl7.fhir.r4b.model.StringType src) {
if (src.hasExtension(ToolingExtensions.EXT_ORIGINAL_VARIABLE_TYPE)) {
return ConversionContext43_50.INSTANCE.getVersionConvertor_43_50().convertType(src.getExtensionByUrl(ToolingExtensions.EXT_ORIGINAL_VARIABLE_TYPE).getValue());
} else {
org.hl7.fhir.r5.model.IdType tgt = new org.hl7.fhir.r5.model.IdType();
ConversionContext43_50.INSTANCE.getVersionConvertor_43_50().copyElement(src, tgt);
if (src.hasValue()) {
tgt.setValueAsString(src.getValueAsString());
}
return tgt;
}
}
public static org.hl7.fhir.r5.model.DataType convertVariableStringToGuessedParameterDataType(org.hl7.fhir.r4b.model.StringType it) {
@ -860,24 +853,12 @@ public class StructureMap43_50 {
public static org.hl7.fhir.r4b.model.StringType convertStructureMapGroupRuleTargetParameterComponentToString(StructureMapGroupRuleTargetParameterComponent src) {
org.hl7.fhir.r4b.model.StringType tgt = new org.hl7.fhir.r4b.model.StringType();
org.hl7.fhir.instance.model.api.IPrimitiveType primitiveType;
if (src.hasValueIdType()) {
primitiveType = src.getValueIdType();
} else if (src.hasValueStringType()) {
primitiveType = src.getValueStringType();
} else if (src.hasValueIntegerType()) {
primitiveType = src.getValueIntegerType();
} else if (src.hasValueDecimalType()) {
primitiveType = src.getValueDecimalType();
} else if (src.hasValueBooleanType()) {
primitiveType = src.getValueBooleanType();
} else {
throw new FHIRException("Unrecognized primitive type");
}
tgt.setValueAsString(primitiveType.getValueAsString());
ToolingExtensions.addUrlExtension(tgt, ToolingExtensions.EXT_ORIGINAL_ELEMENT_TYPE, primitiveType.fhirType());
ConversionContext43_50.INSTANCE.getVersionConvertor_43_50().copyElement(src, tgt);
if (src.hasValueIdType()) {
tgt.setValueAsString(src.getValueIdType().getValueAsString());
} else if (src.hasValue()) {
tgt.addExtension(ToolingExtensions.EXT_ORIGINAL_VARIABLE_TYPE,ConversionContext43_50.INSTANCE.getVersionConvertor_43_50().convertType(src.getValue()));
}
return tgt;
}
}

View File

@ -79,11 +79,11 @@ class Convertor_Factory_40_50Test {
assertEquals("item", mapR4.getGroup().get(0).getRule().get(0).getDependent().get(0).getVariable().get(0).getValueAsString());
assertEquals("patient", mapR4.getGroup().get(0).getRule().get(0).getDependent().get(0).getVariable().get(1).getValueAsString());
assertEquals("url", mapR4.getGroup().get(0).getRule().get(0).getDependent().get(0).getVariable().get(0).getExtensionByUrl(ToolingExtensions.EXT_ORIGINAL_ELEMENT_TYPE).getValue().fhirType());
assertEquals("url", mapR4.getGroup().get(0).getRule().get(0).getDependent().get(0).getVariable().get(1).getExtensionByUrl(ToolingExtensions.EXT_ORIGINAL_ELEMENT_TYPE).getValue().fhirType());
assertNull(mapR4.getGroup().get(0).getRule().get(0).getDependent().get(0).getVariable().get(0).getExtensionByUrl(ToolingExtensions.EXT_ORIGINAL_VARIABLE_TYPE));
assertNull(mapR4.getGroup().get(0).getRule().get(0).getDependent().get(0).getVariable().get(1).getExtensionByUrl(ToolingExtensions.EXT_ORIGINAL_VARIABLE_TYPE));
assertEquals("id", ((org.hl7.fhir.r4.model.UrlType)mapR4.getGroup().get(0).getRule().get(0).getDependent().get(0).getVariable().get(0).getExtensionByUrl(ToolingExtensions.EXT_ORIGINAL_ELEMENT_TYPE).getValue()).getValueAsString());
assertEquals("id", ((org.hl7.fhir.r4.model.UrlType)mapR4.getGroup().get(0).getRule().get(0).getDependent().get(0).getVariable().get(1).getExtensionByUrl(ToolingExtensions.EXT_ORIGINAL_ELEMENT_TYPE).getValue()).getValueAsString());
assertEquals("item", mapR4.getGroup().get(0).getRule().get(0).getDependent().get(0).getVariable().get(0).getValueAsString());
assertEquals("patient", mapR4.getGroup().get(0).getRule().get(0).getDependent().get(0).getVariable().get(1).getValueAsString());
@ -111,7 +111,7 @@ class Convertor_Factory_40_50Test {
assertEquals("item", mapR5.getGroup().get(0).getRule().get(0).getDependent().get(0).getParameter().get(0).getValueIdType().getValueAsString());
assertEquals("patient", mapR5.getGroup().get(0).getRule().get(0).getDependent().get(0).getParameter().get(1).getValueIdType().getValueAsString());
assertNull(mapR5.getGroup().get(0).getRule().get(0).getDependent().get(0).getParameter().get(0).getExtensionByUrl(ToolingExtensions.EXT_ORIGINAL_ELEMENT_TYPE));
assertNull(mapR5.getGroup().get(0).getRule().get(0).getDependent().get(0).getParameter().get(1).getExtensionByUrl(ToolingExtensions.EXT_ORIGINAL_ELEMENT_TYPE));
assertNull(mapR5.getGroup().get(0).getRule().get(0).getDependent().get(0).getParameter().get(0).getExtensionByUrl(ToolingExtensions.EXT_ORIGINAL_VARIABLE_TYPE));
assertNull(mapR5.getGroup().get(0).getRule().get(0).getDependent().get(0).getParameter().get(1).getExtensionByUrl(ToolingExtensions.EXT_ORIGINAL_VARIABLE_TYPE));
}
}

View File

@ -157,8 +157,8 @@ public class ToolingExtensions {
public static final String EXT_XML_TYPE = "http://hl7.org/fhir/StructureDefinition/structuredefinition-xml-type";
public static final String EXT_JSON_TYPE = "http://hl7.org/fhir/StructureDefinition/structuredefinition-json-type";
public static final String EXT_ORIGINAL_ITEM_TYPE = "http://hl7.org/fhir/tools/StructureDefinition/original-item-type";
public static final String EXT_ORIGINAL_ELEMENT_TYPE = "http://hl7.org/fhir/tools/StructureDefinition/original-item-type";
public static final String EXT_ORIGINAL_ITEM_TYPE = "http://hl7.org/fhir/4.0/StructureDefinition/extension-Questionnaire.item.type";
public static final String EXT_ORIGINAL_VARIABLE_TYPE = "http://hl7.org/fhir/5.0/StructureDefinition/extension-StructureMap.group.rule.dependent.parameter";
// specific extension helpers

View File

@ -40,7 +40,7 @@ import org.hl7.fhir.utilities.xhtml.XhtmlNode;
import javax.annotation.Nonnull;
public class QuestionnaireRenderer extends TerminologyRenderer {
public static final String EXT_QUESTIONNAIRE_ITEM_TYPE_ORIGINAL = "http://hl7.org/fhir/tools/StructureDefinition/original-item-type";
public static final String EXT_QUESTIONNAIRE_ITEM_TYPE_ORIGINAL = "http://hl7.org/fhir/4.0/StructureDefinition/extension-Questionnaire.item.type";
public QuestionnaireRenderer(RenderingContext context) {
super(context);

View File

@ -202,8 +202,8 @@ public class ToolingExtensions {
public static final String EXT_EXPAND_GROUP = "http://hl7.org/fhir/StructureDefinition/valueset-expand-group";
public static final String EXT_BINDING_ADDITIONAL = "http://hl7.org/fhir/tools/StructureDefinition/additional-binding";
public static final String EXT_ORIGINAL_ITEM_TYPE = "http://hl7.org/fhir/tools/StructureDefinition/original-item-type";
public static final String EXT_ORIGINAL_ELEMENT_TYPE = "http://hl7.org/fhir/tools/StructureDefinition/original-item-type";
public static final String EXT_ORIGINAL_ITEM_TYPE = "http://hl7.org/fhir/4.0/StructureDefinition/extension-Questionnaire.item.type";
public static final String EXT_ORIGINAL_VARIABLE_TYPE = "http://hl7.org/fhir/5.0/StructureDefinition/extension-StructureMap.group.rule.dependent.parameter";
// specific extension helpers

View File

@ -1,12 +1,19 @@
package org.hl7.fhir.r5.elementmodel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.checkerframework.checker.units.qual.cd;
import org.hl7.fhir.r5.context.ContextUtilities;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionDesignationComponent;
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.terminologies.CodeSystemUtilities;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.i18n.LanguageFileProducer;
@ -29,6 +36,12 @@ import org.hl7.fhir.utilities.i18n.LanguageFileProducer.TranslationUnit;
*/
public class LanguageUtils {
public static final List<String> TRANSLATION_SUPPLEMENT_RESOURCE_TYPES = Arrays.asList("CodeSystem", "StructureDefinition");
private static final String ORPHAN_TRANSLATIONS_NAME = "translations.orphans";
private static final String SUPPLEMENT_NAME = "translations.supplement";
IWorkerContext context;
private List<String> crlist;
@ -185,4 +198,84 @@ public class LanguageUtils {
public static boolean langsMatch(String dstLang, String srcLang) {
return dstLang == null ? false : dstLang.equals(srcLang);
}
public static void fillSupplement(CodeSystem cs, List<TranslationUnit> list) {
cs.setUserData(SUPPLEMENT_NAME, "true");
for (TranslationUnit tu : list) {
ConceptDefinitionComponent cd = CodeSystemUtilities.getCode(cs, tu.getContext());
if (cd != null && cd.hasDisplay() && cd.getDisplay().equals(tu.getSrcText())) {
cd.addDesignation().setLanguage(tu.getLanguage()).setValue(tu.getTgtText());
} else {
addOrphanTranslation(cs, tu);
}
}
}
private static void addOrphanTranslation(CodeSystem cs, TranslationUnit tu) {
List<TranslationUnit> list = (List<TranslationUnit>) cs.getUserData(ORPHAN_TRANSLATIONS_NAME);
if (list == null) {
list = new ArrayList<>();
cs.setUserData(ORPHAN_TRANSLATIONS_NAME, list);
}
list.add(tu);
}
public static String nameForLang(String lang) {
// todo: replace with structures from loading languages properly
switch (lang) {
case "en" : return "English";
case "de" : return "German";
case "es" : return "Spanish";
case "nl" : return "Dutch";
}
return Utilities.capitalize(lang);
}
public static String titleForLang(String lang) {
// todo: replace with structures from loading languages properly
switch (lang) {
case "en" : return "English";
case "de" : return "German";
case "es" : return "Spanish";
case "nl" : return "Dutch";
}
return Utilities.capitalize(lang);
}
public static boolean handlesAsResource(Resource resource) {
return (resource instanceof CodeSystem && resource.hasUserData(SUPPLEMENT_NAME));
}
public static boolean handlesAsElement(Element element) {
return false; // for now...
}
public static List<TranslationUnit> generateTranslations(Resource res, String lang) {
List<TranslationUnit> list = new ArrayList<>();
CodeSystem cs = (CodeSystem) res;
for (ConceptDefinitionComponent cd : cs.getConcept()) {
generateTranslations(list, cd, lang);
}
return list;
}
private static void generateTranslations(List<TranslationUnit> 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();
}
}
for (ConceptDefinitionDesignationComponent d : cd.getDesignation()) {
if (target == null && d.hasLanguage() && lang.equals(d.getLanguage())) {
target = d.getValue();
}
}
list.add(new TranslationUnit(lang, code, display, target));
for (ConceptDefinitionComponent cd1 : cd.getConcept()) {
generateTranslations(list, cd1, lang);
}
}
}

View File

@ -40,7 +40,7 @@ import org.hl7.fhir.utilities.xhtml.XhtmlNode;
import javax.annotation.Nonnull;
public class QuestionnaireRenderer extends TerminologyRenderer {
public static final String EXT_QUESTIONNAIRE_ITEM_TYPE_ORIGINAL = "http://hl7.org/fhir/tools/StructureDefinition/original-item-type";
public static final String EXT_QUESTIONNAIRE_ITEM_TYPE_ORIGINAL = "http://hl7.org/fhir/4.0/StructureDefinition/extension-Questionnaire.item.type";
public QuestionnaireRenderer(RenderingContext context) {
super(context);

View File

@ -730,7 +730,7 @@ public class Utilities {
public static String stripBOM(String string) {
return string.replace("\uFEFF", "");
return string == null ? null : string.replace("\uFEFF", "");
}

View File

@ -787,6 +787,7 @@ public class I18nConstants {
public static final String SD_NO_SLICING_ON_ROOT = "SD_NO_SLICING_ON_ROOT";
public static final String REFERENCE_REF_QUERY_INVALID = "REFERENCE_REF_QUERY_INVALID";
public static final String SM_RULEGROUP_NOT_FOUND = "SM_RULEGROUP_NOT_FOUND";
public static final String SM_RULEGROUP_PARAM_COUNT_MISMATCH = "SM_RULEGROUP_PARAM_COUNT_MISMATCH";
public static final String SM_NAME_INVALID = "SM_NAME_INVALID";
public static final String SM_GROUP_INPUT_DUPLICATE = "SM_GROUP_INPUT_DUPLICATE";
public static final String SM_GROUP_INPUT_MODE_INVALID = "SM_GROUP_INPUT_MODE_INVALID";
@ -862,6 +863,8 @@ public class I18nConstants {
public static final String SD_NO_CONTEXT_WHEN_NOT_EXTENSION = "SD_NO_CONTEXT_WHEN_NOT_EXTENSION";
public static final String SD_CONTEXT_SHOULD_NOT_BE_ELEMENT = "SD_CONTEXT_SHOULD_NOT_BE_ELEMENT";
public static final String SD_NO_CONTEXT_INV_WHEN_NOT_EXTENSION = "SD_NO_CONTEXT_INV_WHEN_NOT_EXTENSION";
public static final String SM_TARGET_TRANSFORM_OP_UNKNOWN_SOURCE = "SM_TARGET_TRANSFORM_OP_UNKNOWN_SOURCE";
public static final String SM_TARGET_TRANSFORM_OP_INVALID_TYPE = "SM_TARGET_TRANSFORM_OP_INVALID_TYPE";
}

View File

@ -0,0 +1,128 @@
package org.hl7.fhir.utilities.i18n;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.i18n.LanguageFileProducer.TranslationUnit;
import org.hl7.fhir.utilities.json.model.JsonObject;
import org.hl7.fhir.utilities.json.parser.JsonParser;
public class JsonLangFileProducer extends LanguageFileProducer {
public JsonLangFileProducer(String folder) {
super(folder);
}
public JsonLangFileProducer() {
super();
}
@Override
public LanguageProducerSession startSession(String id, String baseLang) throws IOException {
return new JsonLangProducerSession(id, baseLang);
}
@Override
public void finish() {
// nothing
}
public class JsonLangProducerSession extends LanguageProducerSession {
JsonObject json = new JsonObject();
public JsonLangProducerSession(String id, String baseLang) {
super (id, baseLang);
json.add("id", id);
json.add("baseLang", baseLang);
}
@Override
public LanguageProducerLanguageSession forLang(String targetLang) {
return new JsonLangLanguageProducerLanguageSession(id, baseLang, targetLang, json);
}
@Override
public void finish() throws IOException {
JsonParser.compose(json, new FileOutputStream(getFileName(id, baseLang)));
}
}
public class JsonLangLanguageProducerLanguageSession extends LanguageProducerLanguageSession {
private JsonObject json;
public JsonLangLanguageProducerLanguageSession(String id, String baseLang, String targetLang, JsonObject parent) {
super(id, baseLang, targetLang);
json = new JsonObject();
parent.forceArray("languages").add(json);
json.add("targetLang", targetLang);
}
@Override
public void finish() throws IOException {
}
@Override
public void entry(TextUnit unit) {
JsonObject entry = new JsonObject();
json.forceArray("entries").add(entry);
entry.add("context", unit.getContext());
entry.add("source", unit.getSrcText());
entry.add("target", unit.getTgtText());
}
}
@Override
public List<TranslationUnit> loadSource(InputStream source) throws IOException {
List<TranslationUnit> list = new ArrayList<>();
JsonObject json = JsonParser.parseObject(source);
for (JsonObject lang : json.forceArray("languages").asJsonObjects()) {
for (JsonObject entry : lang.forceArray("entries").asJsonObjects()) {
list.add(new TranslationUnit(lang.asString("targetLang"), entry.asString("context"), entry.asString("source"), entry.asString("target")));
}
}
return list;
}
private String getFileName(String id, String baseLang) throws IOException {
return Utilities.path(getFolder(), id+"-"+baseLang+".json");
}
@Override
public int fileCount() {
return 1;
}
@Override
public void produce(String id, String baseLang, String targetLang, List<TranslationUnit> translations, String filename) throws IOException {
JsonObject json = new JsonObject();
json.add("id", id);
json.add("baseLang", baseLang);
JsonObject lj = new JsonObject();
json.forceArray("languages").add(lj);
lj.add("targetLang", targetLang);
for (TranslationUnit tu : translations) {
JsonObject entry = new JsonObject();
lj.forceArray("entries").add(entry);
entry.add("context", tu.getContext());
entry.add("source", tu.getSrcText());
entry.add("target", tu.getTgtText());
}
TextFile.stringToFile(JsonParser.compose(json, true), Utilities.path(getFolder(), filename));
}
}

View File

@ -9,6 +9,7 @@ import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import org.hl7.fhir.utilities.i18n.LanguageFileProducer.TextUnit;
import org.hl7.fhir.utilities.i18n.LanguageFileProducer.TranslationUnit;
import org.xml.sax.SAXException;
import java.util.HashMap;
@ -143,4 +144,6 @@ public abstract class LanguageFileProducer {
public abstract List<TranslationUnit> loadSource(InputStream source) throws IOException, ParserConfigurationException, SAXException;
public abstract int fileCount();
public abstract void produce(String id, String baseLang, String targetLang, List<TranslationUnit> translations, String filename) throws IOException;
}

View File

@ -20,6 +20,7 @@ import org.hl7.fhir.utilities.i18n.XLIFFProducer.XLiffLanguageProducerLanguageSe
public class PoGetTextProducer extends LanguageFileProducer {
private int filecount;
private boolean incLangInFilename;
public PoGetTextProducer(String folder) {
super(folder);
@ -144,8 +145,38 @@ public class PoGetTextProducer extends LanguageFileProducer {
}
private String getFileName(String id, String baseLang, String targetLang) throws IOException {
return Utilities.path(getFolder(), id+"-"+baseLang+"-"+targetLang+".po");
return Utilities.path(getFolder(), id+(incLangInFilename ? "-"+baseLang+"-"+targetLang+".po" : ""));
}
public boolean isIncLangInFilename() {
return incLangInFilename;
}
public void setIncLangInFilename(boolean incLangInFilename) {
this.incLangInFilename = incLangInFilename;
}
protected void ln(StringBuilder po, String line) {
po.append(line+"\r\n");
}
@Override
public void produce(String id, String baseLang, String targetLang, List<TranslationUnit> translations, String filename) throws IOException {
StringBuilder po = new StringBuilder();
ln(po, "# "+baseLang+" -> "+targetLang);
ln(po, "");
for (TranslationUnit tu : translations) {
ln(po, "#: "+tu.getContext());
// if (context != null) {
// ln("#. "+context);
// }
ln(po, "msgid \""+tu.getSrcText()+"\"");
ln(po, "msgstr \""+(tu.getTgtText() == null ? "" : tu.getTgtText())+"\"");
ln(po, "");
}
TextFile.stringToFile(po.toString(), Utilities.path(getFolder(), filename));
}
}

View File

@ -11,6 +11,8 @@ import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.i18n.LanguageFileProducer.TextUnit;
import org.hl7.fhir.utilities.i18n.LanguageFileProducer.TranslationUnit;
import org.hl7.fhir.utilities.json.model.JsonObject;
import org.hl7.fhir.utilities.json.parser.JsonParser;
import org.hl7.fhir.utilities.xml.XMLUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@ -132,4 +134,33 @@ public class XLIFFProducer extends LanguageFileProducer {
public int fileCount() {
return filecount;
}
protected void ln(StringBuilder xml, String line) {
xml.append(line+"\r\n");
}
@Override
public void produce(String id, String baseLang, String targetLang, List<TranslationUnit> translations, String filename) throws IOException {
StringBuilder xml = new StringBuilder();
ln(xml, "<?xml version=\"1.0\" ?>\r\n");
ln(xml, "<xliff xmlns=\"urn:oasis:names:tc:xliff:document:2.0\" version=\"2.0\">");
ln(xml, " <file source-language=\""+baseLang+"\" target-language=\""+targetLang+"\" id=\""+id+"\" original=\"Resource "+id+"\" datatype=\"KEYVALUEJSON\">");
ln(xml, " <body>");
for (TranslationUnit tu : translations) {
ln(xml, " <trans-unit id=\""+id+"\" resname=\""+tu.getContext()+"\">");
ln(xml, " <source>"+Utilities.escapeXml(tu.getSrcText())+"</source>");
ln(xml, " <target>"+Utilities.escapeXml(tu.getTgtText())+"</target>");
ln(xml, " </trans-unit>");
}
ln(xml, " </body>");
ln(xml, " </file>");
ln(xml, "</xliff>");
TextFile.stringToFile(xml.toString(), Utilities.path(getFolder(), filename));
}
}

View File

@ -838,6 +838,7 @@ ILLEGAL_COMMENT_TYPE = The fhir_comments property must be an array of strings
SD_NO_SLICING_ON_ROOT = Slicing is not allowed at the root of a profile
REFERENCE_REF_QUERY_INVALID = The query part of the conditional reference is not a valid query string ({0})
SM_RULEGROUP_NOT_FOUND = The group {0} could not be resolved
SM_RULEGROUP_PARAM_COUNT_MISMATCH = The group {0} is invoked using {1} parameters, but it actually takes {2} instead
SM_NAME_INVALID = The name {0} is not valid
SM_GROUP_NAME_DUPLICATE = The Group name ''{0}'' is already used
SM_GROUP_INPUT_DUPLICATE = The name {0} is already used
@ -878,6 +879,8 @@ SM_MATCHING_RULEGROUP_NOT_FOUND = Unable to find a default rule for the type pai
SM_TARGET_TRANSFORM_MISSING_PARAMS = One or more parameters to the translate operation are missing (should be 3, was {0})
SM_TARGET_TRANSFORM_TRANSLATE_NO_PARAM = No value for the {0} parameter found
SM_TARGET_TRANSFORM_TRANSLATE_UNKNOWN_SOURCE = The source variable {0} is unknown
SM_TARGET_TRANSFORM_OP_UNKNOWN_SOURCE = The {1} variable {2} is unknown for the transform {0}
SM_TARGET_TRANSFORM_OP_INVALID_TYPE = The {1} variable {0} type {2} is invalid - must be a primitive
SM_TARGET_TRANSFORM_TRANSLATE_CM_NOT_FOUND = The map_uri ''{0}'' could not be resolved, so the map can''t be checked
SM_TARGET_TRANSFORM_TRANSLATE_CM_BAD_MODE = The value ''{0}'' for the output parameter is incorrect
SM_TARGET_TRANSLATE_BINDING_SOURCE = The source variable does not have a required binding, so this concept map can''t be checked

View File

@ -52,6 +52,7 @@ import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.TimeTracker;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.i18n.JsonLangFileProducer;
import org.hl7.fhir.utilities.i18n.LanguageFileProducer.LanguageProducerLanguageSession;
import org.hl7.fhir.utilities.i18n.LanguageFileProducer.LanguageProducerSession;
import org.hl7.fhir.utilities.i18n.LanguageFileProducer.TranslationUnit;
@ -548,6 +549,7 @@ public class ValidationService {
Utilities.createDirectory(dst);
PoGetTextProducer po = new PoGetTextProducer(Utilities.path(dst));
XLIFFProducer xliff = new XLIFFProducer(Utilities.path(dst));
JsonLangFileProducer jl = new JsonLangFileProducer(Utilities.path(dst));
List<String> refs = new ArrayList<String>();
ValidatorUtils.parseSources(cliContext.getSources(), refs, validator.getContext());
@ -565,6 +567,11 @@ public class ValidationService {
new LanguageUtils(validator.getContext()).generateTranslations(e, psl);
psl.finish();
ps.finish();
ps = jl.startSession(e.fhirType()+"-"+e.getIdBase(), cliContext.getSrcLang());
psl = ps.forLang(cliContext.getTgtLang());
new LanguageUtils(validator.getContext()).generateTranslations(e, psl);
psl.finish();
ps.finish();
}
System.out.println("Done - produced "+(po.fileCount()+xliff.fileCount()) + " files in "+dst);
}

View File

@ -37,6 +37,7 @@ import org.hl7.fhir.r5.utils.structuremap.ResolvedGroup;
import org.hl7.fhir.r5.utils.structuremap.StructureMapUtilities;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.i18n.I18nConstants;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType;
@ -699,7 +700,7 @@ public class StructureMapValidator extends BaseValidator {
if (element != null) {
List<ElementDefinitionSource> els = getElementDefinitions(v.getSd(), v.getEd(), v.getType(), element);
if (rule(errors, "2023-03-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), !els.isEmpty(), I18nConstants.SM_TARGET_PATH_INVALID, context, element, v.getEd().getPath()+"."+element)) {
if (warning(errors, "2023-03-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), els.size() == 1, I18nConstants.SM_TARGET_PATH_MULTIPLE_MATCHES, context, element, v.getEd().getPath()+"."+element, render(els))) {
if (warning(errors, "2023-03-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), els.size() == 1 || isElementandSlicing(els), I18nConstants.SM_TARGET_PATH_MULTIPLE_MATCHES, context, element, v.getEd().getPath()+"."+element, render(els))) {
ElementDefinitionSource el = els.get(0);
String transform = target.getChildValue("transform");
List<Element> params = target.getChildren("parameter");
@ -720,6 +721,16 @@ public class StructureMapValidator extends BaseValidator {
if (rule(errors, "2023-03-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), params.size() < 2, I18nConstants.SM_TARGET_TRANSFORM_PARAM_COUNT_RANGE, "create", "0", "1", params.size())) {
if (params.size() == 1) {
type = params.get(0).getChildValue("value");
// type can be a url, a native type, or an alias
if (!Utilities.isAbsoluteUrl(type)) {
type = resolveType(type, "target", src);
if (!Utilities.isAbsoluteUrl(type)) {
StructureDefinition sdt = this.context.fetchTypeDefinition(type);
if (sdt != null) {
type = sdt.getType();
}
}
}
warning(errors, "2023-03-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(),type != null, I18nConstants.SM_TARGET_TRANSFORM_TYPE_UNPROCESSIBLE, "create");
} else {
// maybe can guess? maybe not ... type =
@ -766,6 +777,21 @@ public class StructureMapValidator extends BaseValidator {
ok = false;
}
break;
case "cc" :
ok = rule(errors, "2023-05-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), params.size() == 2 || params.size() == 3, I18nConstants.SM_TARGET_TRANSFORM_MISSING_PARAMS, transform) && ok;
ok = checkParamExistsOrPrimitive(errors, params.size() > 0 ? params.get(0).getNamedChild("value") : null, "cc", "system", target, variables, stack, ok, true);
ok = checkParamExistsOrPrimitive(errors, params.size() > 1 ? params.get(1).getNamedChild("value") : null, "cc", "code", target, variables, stack, ok, true);
ok = checkParamExistsOrPrimitive(errors, params.size() > 2 ? params.get(2).getNamedChild("value") : null, "cc", "display", target, variables, stack, ok, false);
break;
case "append" :
ok = rule(errors, "2023-05-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), params.size() > 0, I18nConstants.SM_TARGET_TRANSFORM_MISSING_PARAMS, transform) && ok;
for (int i = 0; i < params.size(); i++) {
ok = checkParamExistsOrPrimitive(errors, params.get(1).getNamedChild("value"), "cc", "parameter "+i, target, variables, stack, ok, false);
}
break;
case "uuid" :
ok = rule(errors, "2023-05-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), params.size() == 0, I18nConstants.SM_TARGET_TRANSFORM_MISSING_PARAMS, transform) && ok;
break;
case "translate":
ok = rule(errors, "2023-03-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), params.size() == 3, I18nConstants.SM_TARGET_TRANSFORM_MISSING_PARAMS, transform) && ok;
Element srcE = params.size() > 0 ? params.get(0).getNamedChild("value") : null;
@ -829,6 +855,36 @@ public class StructureMapValidator extends BaseValidator {
}
private boolean checkParamExistsOrPrimitive(List<ValidationMessage> errors, Element e, String string, String string2, Element target, VariableSet variables, NodeStack stack, boolean ok, boolean mandatory) {
if (!mandatory && e == null) {
return ok;
} else if (rule(errors, "2023-05-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), e != null, I18nConstants.SM_TARGET_TRANSFORM_TRANSLATE_NO_PARAM, "system")) {
if ("id".equals(e.fhirType())) {
VariableDefn sv = variables.getVariable(e.getValue(), true);
rule(errors, "2023-03-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), e != null, I18nConstants.SM_TARGET_TRANSFORM_OP_UNKNOWN_SOURCE, "cc", "system", e.getValue());
} else {
rule(errors, "2023-03-01", IssueType.INVALID, target.line(), target.col(), stack.getLiteralPath(), e.isPrimitive(), I18nConstants.SM_TARGET_TRANSFORM_OP_INVALID_TYPE, "cc", "system",e.fhirType());
}
return ok;
} else {
return false;
}
}
private boolean isElementandSlicing(List<ElementDefinitionSource> els) {
if (els.size()== 0) {
return false;
}
String path = els.get(0).getEd().getPath();
for (int i = 1; i < els.size(); i++ ) {
if (!els.get(i).getEd().hasSliceName() || !els.get(i).getEd().getPath().equals(path)) {
return false;
}
}
return true;
}
private boolean checkConceptMap(List<ValidationMessage> errors, int line, int col, String literalPath, ConceptMap cm, ElementDefinition srcED, ElementDefinition tgtED) {
boolean ok = true;
ValueSet srcVS = null;
@ -1077,8 +1133,8 @@ public class StructureMapValidator extends BaseValidator {
} else {
ResolvedGroup grp = resolveGroup(name, src);
if (rule(errors, "2023-03-01", IssueType.NOTFOUND, dependent.line(), dependent.col(), stack.getLiteralPath(), grp != null, I18nConstants.SM_RULEGROUP_NOT_FOUND, name)) {
List<Element> params = dependent.getChildren("parameter");
if (rule(errors, "2023-03-01", IssueType.INVALID, dependent.line(), dependent.col(), stack.getLiteralPath(), params.size() == grp.getTargetGroup().getInput().size(), I18nConstants.SM_RULEGROUP_NOT_FOUND, params.size(), grp.getTargetGroup().getInput().size())) {
List<Element> params = dependent.getChildren(VersionUtilities.isR5Plus(context.getVersion()) ? "parameter" : "variable");
if (rule(errors, "2023-03-01", IssueType.INVALID, dependent.line(), dependent.col(), stack.getLiteralPath(), params.size() == grp.getTargetGroup().getInput().size(), I18nConstants.SM_RULEGROUP_PARAM_COUNT_MISMATCH, name, params.size(), grp.getTargetGroup().getInput().size())) {
VariableSet lvars = new VariableSet();
int cc = 0;
for (Element param : params) {
@ -1136,6 +1192,18 @@ public class StructureMapValidator extends BaseValidator {
return input.getType();
}
private String resolveType(String type, String mode, Element map) {
List<Element> structures = map.getChildrenByName("structure");
for (Element structure : structures) {
String alias = structure.getChildValue("alias");
if ((alias != null && alias.equals(type)) && (mode == null || mode.equals(structure.getNamedChildValue("mode")))) {
return structure.getChildValue("url");
}
}
return type;
}
private StructureMapGroupComponent findDefaultGroup(Element src, String srcType, String tgtType) {
List<Element> groups = src.getChildrenByName("group");
for (Element group : groups) {
@ -1199,24 +1267,38 @@ public class StructureMapValidator extends BaseValidator {
return true;
} else if (v.getSd().getUrl().equals(type) || v.getSd().getType().equals(type)) {
return true;
} else if (v.getType() != null && v.getType().equals(type)) {
return true;
} else {
for (TypeRefComponent tr : v.getEd().getType()) {
if (type.equals(tr.getWorkingCode()) || type.equals("http://hl7.org/fhir/StructureDefinition/"+tr.getWorkingCode())) {
return true;
}
}
StructureDefinition tsd = context.fetchTypeDefinition(type);
StructureDefinition sd = context.fetchTypeDefinition(v.getType());
while (sd != null) {
if (sd.getUrl().equals(tsd.getUrl())) {
return true;
}
sd = context.fetchTypeDefinition(sd.getBaseDefinition());
}
return false;
}
}
private VariableDefn getParameter(List<ValidationMessage> errors, Element param, NodeStack pstack, VariableSet variables, StructureMapInputMode mode) {
Element v = param.getNamedChild("value");
if (v.fhirType().equals("id")) {
return variables.getVariable(v.primitiveValue(), mode == StructureMapInputMode.SOURCE);
if (VersionUtilities.isR5Plus(context.getVersion())) {
Element v = param.getNamedChild("value");
if (v.fhirType().equals("id")) {
return variables.getVariable(v.primitiveValue(), mode == StructureMapInputMode.SOURCE);
} else {
String type = v.fhirType();
StructureDefinition sd = context.fetchTypeDefinition(type);
return new VariableDefn("$", "source").setType(1, sd, sd.getSnapshot().getElementFirstRep(), null);
}
} else {
String type = v.fhirType();
StructureDefinition sd = context.fetchTypeDefinition(type);
return new VariableDefn("$", "source").setType(1, sd, sd.getSnapshot().getElementFirstRep(), null);
return variables.getVariable(param.primitiveValue(), mode == StructureMapInputMode.SOURCE);
}
}

View File

@ -234,7 +234,7 @@ public class TerminologyServiceTests {
}
ValidationResult vm;
if (p.hasParameter("code")) {
vm = engine.getContext().validateCode(options.withGuessSystem(), p.getParameterString("system"), p.getParameterString("version"), p.getParameterString("code"), p.getParameterString("display"), vs);
vm = engine.getContext().validateCode(options.withGuessSystem(), p.getParameterString("system"), p.getParameterString("systemVersion"), p.getParameterString("code"), p.getParameterString("display"), vs);
} else if (p.hasParameter("coding")) {
Coding coding = (Coding) p.getParameterValue("coding");
vm = engine.getContext().validateCode(options, coding, vs);

View File

@ -19,7 +19,7 @@
<properties>
<hapi_fhir_version>6.4.1</hapi_fhir_version>
<validator_test_case_version>1.3.2</validator_test_case_version>
<validator_test_case_version>1.3.3-SNAPSHOT</validator_test_case_version>
<jackson_version>2.14.0</jackson_version>
<junit_jupiter_version>5.9.2</junit_jupiter_version>
<junit_platform_launcher_version>1.8.2</junit_platform_launcher_version>