From 9c14632a7c4d5d830303d2e5d16774a352a99cc6 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Thu, 12 Dec 2024 11:41:31 +1100 Subject: [PATCH 01/15] fix Lloyd's broken code --- .../convertors/conv40_50/resources40_50/ValueSet40_50.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/resources40_50/ValueSet40_50.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/resources40_50/ValueSet40_50.java index 2fc2ae0297..52e8517fc8 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/resources40_50/ValueSet40_50.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/resources40_50/ValueSet40_50.java @@ -479,7 +479,11 @@ public static org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent ConceptPropertyComponent prop = tgt.addProperty(); ConversionContext40_50.INSTANCE.getVersionConvertor_40_50().copyElement(t, prop, "code", "value[x]"); prop.setCode(t.getExtensionString("code")); - prop.setValue(ConversionContext40_50.INSTANCE.getVersionConvertor_40_50().convertType(t.getExtensionByUrl("value[x]").getValue())); + if (t.hasExtension("value")) { + prop.setValue(ConversionContext40_50.INSTANCE.getVersionConvertor_40_50().convertType(t.getExtensionByUrl("value").getValue())); + } else if (t.hasExtension("value[x]")) { + prop.setValue(ConversionContext40_50.INSTANCE.getVersionConvertor_40_50().convertType(t.getExtensionByUrl("value[x]").getValue())); + } } } From bc09c923d71b08859e7c25ac3b274d4255688004 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Sun, 15 Dec 2024 04:48:21 +1100 Subject: [PATCH 02/15] More work on test instance generator --- .../hl7/fhir/r4/profilemodel/PEBuilder.java | 2 +- .../hl7/fhir/r5/elementmodel/JsonParser.java | 9 +- .../hl7/fhir/r5/profilemodel/PEBuilder.java | 2 +- .../fhir/r5/profilemodel/PEDefinition.java | 2 +- .../profilemodel/TestInstanceGenerator.java | 98 +++++++++++++------ 5 files changed, 75 insertions(+), 38 deletions(-) diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/profilemodel/PEBuilder.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/profilemodel/PEBuilder.java index 54f953a77c..a45d23740f 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/profilemodel/PEBuilder.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/profilemodel/PEBuilder.java @@ -361,7 +361,7 @@ protected List listChildren(boolean allFixed, PEDefinition parent, if (!defn.getMax().equals("0") && (allFixed || include(defn))) { if (passElementPropsCheck(defn) && !Utilities.existsInList(defn.getName(), omitList)) { if (defn.getType().size() > 1) { - // DebugUtilities.breakpoint(); + // Debug/Utilities.breakpoint(); i++; } else { String name = uniquefy(names, defn.getName()); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java index a54dc128c4..62a7c3a854 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/elementmodel/JsonParser.java @@ -972,18 +972,19 @@ private void primitiveValue(String name, Element item) throws IOException { json.name(name); } String type = item.getType(); - if (Utilities.existsInList(type, "boolean")) + if (Utilities.existsInList(type, "boolean")) { json.value(item.getValue().trim().equals("true") ? new Boolean(true) : new Boolean(false)); - else if (Utilities.existsInList(type, "integer", "unsignedInt", "positiveInt")) + } else if (Utilities.existsInList(type, "integer", "unsignedInt", "positiveInt")) { json.value(new Integer(item.getValue())); - else if (Utilities.existsInList(type, "decimal")) + } else if (Utilities.existsInList(type, "decimal")) { try { json.value(new BigDecimal(item.getValue())); } catch (Exception e) { throw new NumberFormatException(context.formatMessage(I18nConstants.ERROR_WRITING_NUMBER__TO_JSON, item.getValue())); } - else + } else { json.value(item.getValue()); + } } private void compose(String path, Element element) throws IOException { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEBuilder.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEBuilder.java index dd36b5be93..f599fcf507 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEBuilder.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEBuilder.java @@ -361,7 +361,7 @@ protected List listChildren(boolean allFixed, PEDefinition parent, if (!defn.getMax().equals("0") && (allFixed || include(defn))) { if (passElementPropsCheck(defn) && !Utilities.existsInList(defn.getName(), omitList)) { if (defn.getType().size() > 1) { - // DebugUtilities.breakpoint(); + // Debug/Utilities.breakpoint(); i++; } else { String name = uniquefy(names, defn.getName()); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEDefinition.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEDefinition.java index 2051934910..98f4fb3db3 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEDefinition.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEDefinition.java @@ -85,7 +85,7 @@ protected PEDefinition(PEBuilder builder, String name, StructureDefinition profi this.name = name; this.profile = profile; this.definition = definition; - this.path = path == null ? name : ppath+"."+name; + this.path = ppath == null ? name : ppath+"."+name; } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/TestInstanceGenerator.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/TestInstanceGenerator.java index 1338c724b9..5976da16af 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/TestInstanceGenerator.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/TestInstanceGenerator.java @@ -1,11 +1,17 @@ package org.hl7.fhir.r5.profilemodel; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.util.Map; +import java.util.UUID; +import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.r5.context.IWorkerContext; +import org.hl7.fhir.r5.elementmodel.Element; +import org.hl7.fhir.r5.elementmodel.Manager; +import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat; +import org.hl7.fhir.r5.formats.IParser.OutputStyle; import org.hl7.fhir.r5.model.Base; -import org.hl7.fhir.r5.model.Resource; -import org.hl7.fhir.r5.model.ResourceFactory; import org.hl7.fhir.r5.model.StructureDefinition; import org.hl7.fhir.r5.profilemodel.PEBuilder.PEElementPropertiesPolicy; import org.hl7.fhir.utilities.Utilities; @@ -15,50 +21,80 @@ public class TestInstanceGenerator { private IWorkerContext context; private Map data; - protected TestInstanceGenerator(IWorkerContext context) { + public TestInstanceGenerator(IWorkerContext context) { super(); this.context = context; } - public Resource generate(StructureDefinition profile) { + public byte[] generate(StructureDefinition profile, FhirFormat format) throws FHIRException, IOException { PEBuilder builder = new PEBuilder(context, PEElementPropertiesPolicy.NONE, true); PEDefinition definition = builder.buildPEDefinition(profile); - Resource res = ResourceFactory.createResource(definition.types().get(0).getType()); - populateByProfile(res, definition); + Element element = Manager.build(context, profile); - res.getMeta().addProfile(definition.profile.getVersionedUrl()); - return res; + populateByProfile(element, definition, 0); + + ByteArrayOutputStream ba = new ByteArrayOutputStream(); + Manager.compose(context, element, ba, format, OutputStyle.PRETTY, null); + return ba.toByteArray(); } - protected void populateByProfile(Base base, PEDefinition definition) { + protected void populateByProfile(Element element, PEDefinition definition, int level) { if (definition.types().size() == 1) { for (PEDefinition pe : definition.directChildren(true)) { - if (pe.hasFixedValue()) { - if (pe.definition().hasPattern()) { - base.setProperty(pe.schemaName(), pe.definition().getPattern()); - } else { - base.setProperty(pe.schemaName(), pe.definition().getFixed()); - } - } else if (!pe.isSlicer() && pe.max() == 1) { - for (int i = 0; i < pe.min(); i++) { - Base b = null; - if (pe.schemaName().endsWith("[x]")) { - if (pe.types().size() == 1) { - b = base.addChild(pe.schemaName().replace("[x]", Utilities.capitalize(pe.types().get(0).getType()))); - } - } else if (!pe.isBaseList()) { - b = base.makeProperty(pe.schemaName().hashCode(), pe.schemaName()); - } else { - b = base.addChild(pe.schemaName()); - } - if (b != null) { - populateByProfile(b, pe); - } - } + if (!isIgnoredElement(pe.definition().getBase().getPath())) { + populateElement(element, pe, level); + } + } + } + } + + private boolean isIgnoredElement(String path) { + return Utilities.existsInList(path, "Identifier.assigner", "Resource.meta", "DomainResource.text"); + } + + public void populateElement(Element element, PEDefinition pe, int level) { + System.out.println(pe.path()); + if (pe.hasFixedValue()) { + Element focus = element.addElement(pe.schemaName()); + Base fv = pe.definition().hasPattern() ? pe.definition().getPattern() : pe.definition().getFixed(); + if (fv.isPrimitive()) { + focus.setValue(fv.primitiveValue()); + } else { + populateElementFromDataType(element, fv, null); + } + } else if (!pe.isSlicer() && pe.max() == 1) { + for (int i = 0; i < pe.max(); i++) { + makeChildElement(element, pe, level); + } + } + } + + public void makeChildElement(Element element, PEDefinition pe, int level) { + Element b = null; + if (pe.schemaName().endsWith("[x]")) { + if (pe.types().size() == 1) { + b = element.makeElement(pe.schemaName().replace("[x]", Utilities.capitalize(pe.types().get(0).getType()))); + } + } else { + b = element.makeElement(pe.schemaName()); + } + if (b != null) { + if (pe.definition.hasBinding()) { + + } else if (b.isPrimitive()) { + switch (b.fhirType()) { + case "id": b.setValue(UUID.randomUUID().toString().toLowerCase()); } + } else { + populateByProfile(b, pe, level+1); } } } + private void populateElementFromDataType(Element element, Base fv, Object object) { + // TODO Auto-generated method stub + + } + } From 45ceeb73e1b2196bd0d54e30cfa32e3f48f53077 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Sun, 15 Dec 2024 04:48:46 +1100 Subject: [PATCH 03/15] Improvements to translation file generation (better path, eliminate duplicates) --- .../fhir/r5/elementmodel/LanguageUtils.java | 79 ++++++++++++------- 1 file changed, 50 insertions(+), 29 deletions(-) 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 44ecc181a7..9f3759bd48 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 @@ -2,8 +2,10 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import org.checkerframework.checker.units.qual.cd; @@ -60,6 +62,18 @@ public class LanguageUtils { public static final List TRANSLATION_SUPPLEMENT_RESOURCE_TYPES = Arrays.asList("CodeSystem", "StructureDefinition", "Questionnaire"); + public static class TranslationUnitCollection { + List list= new ArrayList<>(); + Map map = new HashMap<>(); + public void add(TranslationUnit tu) { + String key = tu.getId()+"||"+tu.getSrcText(); + if (!map.containsKey(key)) { + map.put(key, tu); + list.add(tu); + } + + } + } IWorkerContext context; private List crlist; @@ -70,24 +84,25 @@ public LanguageUtils(IWorkerContext context) { } public void generateTranslations(Element resource, LanguageProducerLanguageSession session) { - translate(null, resource, session); + translate(null, resource, session, resource.fhirType()); } - private void translate(Element parent, Element element, LanguageProducerLanguageSession langSession) { + private void translate(Element parent, Element element, LanguageProducerLanguageSession langSession, String path) { + String npath = pathForElement(path, element); if (element.isPrimitive() && isTranslatable(element)) { String base = element.primitiveValue(); if (base != null) { - String translation = getSpecialTranslation(parent, element, langSession.getTargetLang()); + String translation = getSpecialTranslation(path, parent, element, langSession.getTargetLang()); if (translation == null) { translation = element.getTranslation(langSession.getTargetLang()); } - langSession.entry(new TextUnit(pathForElement(element), contextForElement(element), base, translation)); + langSession.entry(new TextUnit(npath, contextForElement(element), base, translation)); } } for (Element c: element.getChildren()) { if (!c.getName().equals("designation")) { - translate(element, c, langSession); + translate(element, c, langSession, npath); } } } @@ -96,17 +111,18 @@ private String contextForElement(Element element) { throw new Error("Not done yet"); } - private String getSpecialTranslation(Element parent, Element element, String targetLang) { + private String getSpecialTranslation(String path, Element parent, Element element, String targetLang) { if (parent == null) { return null; } - if (Utilities.existsInList(pathForElement(parent), "CodeSystem.concept", "CodeSystem.concept.concept") && "CodeSystem.concept.display".equals(pathForElement(element))) { + String npath = parent.getBasePath(); + if (Utilities.existsInList(npath, "CodeSystem.concept", "CodeSystem.concept.concept") && "CodeSystem.concept.display".equals(element.getBasePath())) { return getDesignationTranslation(parent, targetLang); } - if (Utilities.existsInList(pathForElement(parent), "ValueSet.compose.include.concept") && "ValueSet.compose.include.concept.display".equals(pathForElement(element))) { + if (Utilities.existsInList(npath, "ValueSet.compose.include.concept") && "ValueSet.compose.include.concept.display".equals(element.getBasePath())) { return getDesignationTranslation(parent, targetLang); } - if (Utilities.existsInList(pathForElement(parent), "ValueSet.expansion.contains", "ValueSet.expansion.contains.contains") && "ValueSet.expansion.contains.display".equals(pathForElement(element))) { + if (Utilities.existsInList(npath, "ValueSet.expansion.contains", "ValueSet.expansion.contains.contains") && "ValueSet.expansion.contains.display".equals(element.getBasePath())) { return getDesignationTranslation(parent, targetLang); } return null; @@ -126,9 +142,13 @@ private boolean isTranslatable(Element element) { return element.getProperty().isTranslatable(); } - private String pathForElement(Element element) { - String bp = element.getBasePath(); - return pathForElement(bp, element.getProperty().getStructure().getType()); + private String pathForElement(String path, Element element) { + if (element.getSpecial() != null) { + String bp = element.getBasePath(); + return pathForElement(bp, element.getProperty().getStructure().getType()); + } else { + return (path == null ? element.getName() : path+"."+element.getName()); + } } private String pathForElement(String path, String type) { @@ -151,7 +171,7 @@ private String pathForElement(String path, String type) { public int importFromTranslations(Element resource, List translations) { - return importFromTranslations(null, resource, translations, new HashSet<>()); + return importFromTranslations(resource.fhirType(), null, resource, translations, new HashSet<>()); } public int importFromTranslations(Element resource, List translations, List messages) { @@ -160,7 +180,7 @@ public int importFromTranslations(Element resource, List transl if (resource.fhirType().equals("StructureDefinition")) { r = importFromTranslationsForSD(null, resource, translations, usedUnits); } else { - r = importFromTranslations(null, resource, translations, usedUnits); + r = importFromTranslations(null, null, resource, translations, usedUnits); } for (TranslationUnit t : translations) { if (!usedUnits.contains(t)) { @@ -282,13 +302,13 @@ private boolean isTranslatable(Base element, String path) { return Utilities.existsInList(element.fhirType(), "string", "markdown"); } - private int importFromTranslations(Element parent, Element element, List translations, Set usedUnits) { + private int importFromTranslations(String path, Element parent, Element element, List translations, Set usedUnits) { + String npath = pathForElement(path, element); int t = 0; if (element.isPrimitive() && isTranslatable(element)) { String base = element.primitiveValue(); if (base != null) { - String path = pathForElement(element); - Set tlist = findTranslations(path, base, translations); + Set tlist = findTranslations(npath, base, translations); for (TranslationUnit translation : tlist) { t++; if (!handleAsSpecial(parent, element, translation)) { @@ -302,7 +322,7 @@ private int importFromTranslations(Element parent, Element element, List childrenCopy = List.copyOf(element.getChildren()); for (Element c : childrenCopy) { if (!c.getName().equals("designation")) { - t = t + importFromTranslations(element, c, translations, usedUnits); + t = t + importFromTranslations(npath, element, c, translations, usedUnits); } } return t; @@ -312,13 +332,13 @@ private boolean handleAsSpecial(Element parent, Element element, TranslationUnit if (parent == null) { return false; } - if (Utilities.existsInList(pathForElement(parent), "CodeSystem.concept", "CodeSystem.concept.concept") && "CodeSystem.concept.display".equals(pathForElement(element))) { + if (Utilities.existsInList(parent.getBasePath(), "CodeSystem.concept", "CodeSystem.concept.concept") && "CodeSystem.concept.display".equals(element.getBasePath())) { return setDesignationTranslation(parent, translation.getLanguage(), translation.getTgtText()); } - if (Utilities.existsInList(pathForElement(parent), "ValueSet.compose.include.concept") && "ValueSet.compose.include.concept.display".equals(pathForElement(element))) { + if (Utilities.existsInList(parent.getBasePath(), "ValueSet.compose.include.concept") && "ValueSet.compose.include.concept.display".equals(element.getBasePath())) { return setDesignationTranslation(parent, translation.getLanguage(), translation.getTgtText()); } - if (Utilities.existsInList(pathForElement(parent), "ValueSet.expansion.contains", "ValueSet.expansion.contains.contains") && "ValueSet.expansion.contains.display".equals(pathForElement(element))) { + if (Utilities.existsInList(parent.getBasePath(), "ValueSet.expansion.contains", "ValueSet.expansion.contains.contains") && "ValueSet.expansion.contains.display".equals(element.getBasePath())) { return setDesignationTranslation(parent, translation.getLanguage(), translation.getTgtText()); } return false; @@ -500,7 +520,7 @@ public List generateTranslations(Resource res, String lang) { if (res.hasUserData(UserDataNames.LANGUTILS_ORPHAN)) { List orphans = (List) res.getUserData(UserDataNames.LANGUTILS_ORPHAN); for (TranslationUnit t : orphans) { - list.add(new TranslationUnit(lang, "!!"+t.getId(), t.getContext1(), t.getSrcText(), t.getTgtText())); + list.add(new TranslationUnit(lang, "!!"+t.getId(), t.getContext(), t.getSrcText(), t.getTgtText())); } } } else { @@ -512,7 +532,7 @@ public List generateTranslations(Resource res, String lang) { if (cs.hasUserData(UserDataNames.LANGUTILS_ORPHAN)) { List orphans = (List) cs.getUserData(UserDataNames.LANGUTILS_ORPHAN); for (TranslationUnit t : orphans) { - list.add(new TranslationUnit(lang, "!!"+t.getId(), t.getContext1(), t.getSrcText(), t.getTgtText())); + list.add(new TranslationUnit(lang, "!!"+t.getId(), t.getContext(), t.getSrcText(), t.getTgtText())); } } } @@ -601,14 +621,15 @@ private String getDefinition(ConceptDefinitionComponent cd) { } public List generateTranslations(Element e, String lang) { - List list = new ArrayList<>(); - generateTranslations(e, lang, list); - return list; + TranslationUnitCollection list = new TranslationUnitCollection(); + generateTranslations(e, lang, list, e.fhirType()); + return list.list; } - private void generateTranslations(Element e, String lang, List list) { + private void generateTranslations(Element e, String lang, TranslationUnitCollection list, String path) { + String npath = pathForElement(path, e); if (e.getProperty().isTranslatable()) { - String id = pathForElement(e); // .getProperty().getDefinition().getPath(); + String id = npath; // .getProperty().getDefinition().getPath(); String context = e.getProperty().getDefinition().getDefinition(); String src = e.primitiveValue(); String tgt = getTranslation(e, lang); @@ -616,7 +637,7 @@ private void generateTranslations(Element e, String lang, List } if (e.hasChildren()) { for (Element c : e.getChildren()) { - generateTranslations(c, lang, list); + generateTranslations(c, lang, list, npath); } } From d891b278edba7dbcb8efc641bc06549a3b37a6e4 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Sun, 15 Dec 2024 04:48:57 +1100 Subject: [PATCH 04/15] fix regex escapes --- .../src/main/java/org/hl7/fhir/r5/model/Constants.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Constants.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Constants.java index b92182ddbb..c4fd3bf134 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Constants.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Constants.java @@ -35,7 +35,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWIS public class Constants { - public final static String LOCAL_REF_REGEX = "(Account|ActivityDefinition|ActorDefinition|AdministrableProductDefinition|AdverseEvent|AllergyIntolerance|Appointment|AppointmentResponse|ArtifactAssessment|AuditEvent|Basic|Binary|BiologicallyDerivedProduct|BiologicallyDerivedProductDispense|BodyStructure|Bundle|CapabilityStatement|CarePlan|CareTeam|ChargeItem|ChargeItemDefinition|Citation|Claim|ClaimResponse|ClinicalImpression|ClinicalUseDefinition|CodeSystem|Communication|CommunicationRequest|CompartmentDefinition|Composition|ConceptMap|Condition|ConditionDefinition|Consent|Contract|Coverage|CoverageEligibilityRequest|CoverageEligibilityResponse|DetectedIssue|Device|DeviceAssociation|DeviceDefinition|DeviceDispense|DeviceMetric|DeviceRequest|DeviceUsage|DiagnosticReport|DocumentReference|Encounter|EncounterHistory|Endpoint|EnrollmentRequest|EnrollmentResponse|EpisodeOfCare|EventDefinition|Evidence|EvidenceReport|EvidenceVariable|ExampleScenario|ExplanationOfBenefit|FamilyMemberHistory|Flag|FormularyItem|GenomicStudy|Goal|GraphDefinition|Group|GuidanceResponse|HealthcareService|ImagingSelection|ImagingStudy|Immunization|ImmunizationEvaluation|ImmunizationRecommendation|ImplementationGuide|Ingredient|InsurancePlan|InventoryItem|InventoryReport|Invoice|Library|Linkage|List|Location|ManufacturedItemDefinition|Measure|MeasureReport|Medication|MedicationAdministration|MedicationDispense|MedicationKnowledge|MedicationRequest|MedicationStatement|MedicinalProductDefinition|MessageDefinition|MessageHeader|MolecularSequence|NamingSystem|NutritionIntake|NutritionOrder|NutritionProduct|Observation|ObservationDefinition|OperationDefinition|OperationOutcome|Organization|OrganizationAffiliation|PackagedProductDefinition|Parameters|Patient|PaymentNotice|PaymentReconciliation|Permission|Person|PlanDefinition|Practitioner|PractitionerRole|Procedure|Provenance|Questionnaire|QuestionnaireResponse|RegulatedAuthorization|RelatedPerson|RequestOrchestration|Requirements|ResearchStudy|ResearchSubject|RiskAssessment|Schedule|SearchParameter|ServiceRequest|Slot|Specimen|SpecimenDefinition|StructureDefinition|StructureMap|Subscription|SubscriptionStatus|SubscriptionTopic|Substance|SubstanceDefinition|SubstanceNucleicAcid|SubstancePolymer|SubstanceProtein|SubstanceReferenceInformation|SubstanceSourceMaterial|SupplyDelivery|SupplyRequest|Task|TerminologyCapabilities|TestPlan|TestReport|TestScript|Transport|ValueSet|VerificationResult|VisionPrescription)\\\\/[A-Za-z0-9\\\\-\\\\.]{1,64}"; + public final static String LOCAL_REF_REGEX = "(Account|ActivityDefinition|ActorDefinition|AdministrableProductDefinition|AdverseEvent|AllergyIntolerance|Appointment|AppointmentResponse|ArtifactAssessment|AuditEvent|Basic|Binary|BiologicallyDerivedProduct|BiologicallyDerivedProductDispense|BodyStructure|Bundle|CapabilityStatement|CarePlan|CareTeam|ChargeItem|ChargeItemDefinition|Citation|Claim|ClaimResponse|ClinicalImpression|ClinicalUseDefinition|CodeSystem|Communication|CommunicationRequest|CompartmentDefinition|Composition|ConceptMap|Condition|ConditionDefinition|Consent|Contract|Coverage|CoverageEligibilityRequest|CoverageEligibilityResponse|DetectedIssue|Device|DeviceAssociation|DeviceDefinition|DeviceDispense|DeviceMetric|DeviceRequest|DeviceUsage|DiagnosticReport|DocumentReference|Encounter|EncounterHistory|Endpoint|EnrollmentRequest|EnrollmentResponse|EpisodeOfCare|EventDefinition|Evidence|EvidenceReport|EvidenceVariable|ExampleScenario|ExplanationOfBenefit|FamilyMemberHistory|Flag|FormularyItem|GenomicStudy|Goal|GraphDefinition|Group|GuidanceResponse|HealthcareService|ImagingSelection|ImagingStudy|Immunization|ImmunizationEvaluation|ImmunizationRecommendation|ImplementationGuide|Ingredient|InsurancePlan|InventoryItem|InventoryReport|Invoice|Library|Linkage|List|Location|ManufacturedItemDefinition|Measure|MeasureReport|Medication|MedicationAdministration|MedicationDispense|MedicationKnowledge|MedicationRequest|MedicationStatement|MedicinalProductDefinition|MessageDefinition|MessageHeader|MolecularSequence|NamingSystem|NutritionIntake|NutritionOrder|NutritionProduct|Observation|ObservationDefinition|OperationDefinition|OperationOutcome|Organization|OrganizationAffiliation|PackagedProductDefinition|Parameters|Patient|PaymentNotice|PaymentReconciliation|Permission|Person|PlanDefinition|Practitioner|PractitionerRole|Procedure|Provenance|Questionnaire|QuestionnaireResponse|RegulatedAuthorization|RelatedPerson|RequestOrchestration|Requirements|ResearchStudy|ResearchSubject|RiskAssessment|Schedule|SearchParameter|ServiceRequest|Slot|Specimen|SpecimenDefinition|StructureDefinition|StructureMap|Subscription|SubscriptionStatus|SubscriptionTopic|Substance|SubstanceDefinition|SubstanceNucleicAcid|SubstancePolymer|SubstanceProtein|SubstanceReferenceInformation|SubstanceSourceMaterial|SupplyDelivery|SupplyRequest|Task|TerminologyCapabilities|TestPlan|TestReport|TestScript|Transport|ValueSet|VerificationResult|VisionPrescription)\\/[A-Za-z0-9\\-\\.]{1,64}"; public final static String NS_SYSTEM_TYPE = "http://hl7.org/fhirpath/System."; public final static String VERSION = "5.0.0"; From 22b645fb9e3329ddbf4e4beb3ef29ece875700e7 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Sun, 15 Dec 2024 04:49:31 +1100 Subject: [PATCH 05/15] fix rendering issues - resources with no id, and urn: references shouldn't be links --- .../hl7/fhir/r5/renderers/DataRenderer.java | 42 ++++++++++--------- .../fhir/r5/renderers/ResourceRenderer.java | 20 ++++++++- 2 files changed, 40 insertions(+), 22 deletions(-) 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 9e78f42705..7925661cc7 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 @@ -1046,30 +1046,32 @@ protected void renderUri(RenderingStatus status, XhtmlNode x, ResourceWrapper ur if (!renderPrimitiveWithNoValue(status, x, uri)) { String v = uri.primitiveValue(); - if (context.getContextUtilities().isResource(v)) { - v = "http://hl7.org/fhir/"+v; - } - if (v.startsWith("mailto:")) { - x.ah(v).addText(v.substring(7)); - } else { - Resource r = context.getContext().fetchResource(Resource.class, v); - if (r != null && r.getWebPath() != null) { - if (r instanceof CanonicalResource) { - x.ah(context.prefixLocalHref(r.getWebPath())).addText(crPresent((CanonicalResource) r)); - } else { - x.ah(context.prefixLocalHref(r.getWebPath())).addText(v); - } + if (v != null) { + if (context.getContextUtilities().isResource(v)) { + v = "http://hl7.org/fhir/"+v; + } + if (v.startsWith("mailto:")) { + x.ah(v).addText(v.substring(7)); } else { - String url = context.getResolver() != null ? context.getResolver().resolveUri(context, v) : null; - if (url != null) { - x.ah(context.prefixLocalHref(url)).addText(v); - } else if (Utilities.isAbsoluteUrlLinkable(v) && !uri.fhirType().equals("id")) { - x.ah(context.prefixLocalHref(v)).addText(v); + Resource r = context.getContext().fetchResource(Resource.class, v); + if (r != null && r.getWebPath() != null) { + if (r instanceof CanonicalResource) { + x.ah(context.prefixLocalHref(r.getWebPath())).addText(crPresent((CanonicalResource) r)); + } else { + x.ah(context.prefixLocalHref(r.getWebPath())).addText(v); + } } else { - x.addText(v); + String url = context.getResolver() != null ? context.getResolver().resolveUri(context, v) : null; + if (url != null) { + x.ah(context.prefixLocalHref(url)).addText(v); + } else if (Utilities.isAbsoluteUrlLinkable(v) && !uri.fhirType().equals("id")) { + x.ah(context.prefixLocalHref(v)).addText(v); + } else { + x.addText(v); + } } } - } + } } checkRenderExtensions(status, x, uri); } 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 937f39bf0c..baeb6c4c7b 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 @@ -15,6 +15,7 @@ import org.hl7.fhir.r5.model.CanonicalType; import org.hl7.fhir.r5.model.CodeSystem; import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent; +import org.hl7.fhir.r5.model.Constants; import org.hl7.fhir.r5.model.ContactDetail; import org.hl7.fhir.r5.model.ContactPoint; import org.hl7.fhir.r5.model.ContactPoint.ContactPointSystem; @@ -354,7 +355,7 @@ public void renderReference(RenderingStatus status, XhtmlNode x, ResourceWrapper ResourceWithReference rr = resolveReference(actual); if (rr == null) { String disp = display != null && display.hasPrimitiveValue() ? displayDataType(display) : actual.primitiveValue(); - if (Utilities.isAbsoluteUrl(actual.primitiveValue()) || !context.isUnknownLocalReferencesNotLinks()) { + if (Utilities.isAbsoluteUrlLinkable(actual.primitiveValue()) || (isLocalReference(actual.primitiveValue()) && !context.isUnknownLocalReferencesNotLinks())) { x.ah(context.prefixLocalHref(actual.primitiveValue())).tx(disp); } else { x.code().tx(disp); @@ -386,6 +387,21 @@ public void renderReference(RenderingStatus status, XhtmlNode x, ResourceWrapper } + private boolean isLocalReference(String url) { + if (url == null) { + return false; + } + if (url.contains("/_history")) { + url = url.substring(0, url.indexOf("/_hist")); + } + + if (url.matches(Constants.LOCAL_REF_REGEX)) { + return true; + } else { + return false; + } + } + public void renderReference(ResourceWrapper res, HierarchicalTableGenerator gen, List pieces, Reference r, boolean allowLinks) throws UnsupportedEncodingException, IOException { if (r == null) { pieces.add(gen.new Piece(null, "null!", null)); @@ -844,7 +860,7 @@ public boolean canRender(Resource resource) { } protected XhtmlNode renderResourceTechDetails(ResourceWrapper r, XhtmlNode x) throws UnsupportedEncodingException, FHIRException, IOException { - return renderResourceTechDetails(r, x, (context.isContained() ? " #"+r.getId() : r.getId())); + return renderResourceTechDetails(r, x, (context.isContained() && r.getId() != null ? "#"+r.getId() : r.getId())); } protected XhtmlNode renderResourceTechDetails(ResourceWrapper r, XhtmlNode x, String desc) throws UnsupportedEncodingException, FHIRException, IOException { From 6942a91adf3814f0b3cec34556f259d4a6039db3 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Sun, 15 Dec 2024 04:49:54 +1100 Subject: [PATCH 06/15] translation fixes --- .../r5/elementmodel/LanguageUtilsTest.java | 2 +- .../utilities/i18n/JsonLangFileProducer.java | 8 +++--- .../utilities/i18n/LanguageFileProducer.java | 2 +- .../utilities/i18n/PoGetTextProducer.java | 25 ++++++++++++++----- .../fhir/utilities/i18n/XLIFFProducer.java | 8 +++--- 5 files changed, 29 insertions(+), 16 deletions(-) diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/elementmodel/LanguageUtilsTest.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/elementmodel/LanguageUtilsTest.java index 4825f225e2..300cf4ae78 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/elementmodel/LanguageUtilsTest.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/elementmodel/LanguageUtilsTest.java @@ -40,7 +40,7 @@ void importFromTranslations() throws Exception { Writer generatedResource = new StringWriter(); jp.compose(element, new JsonCreatorDirect(generatedResource, false, false)); - assert result == 3; + Assertions.assertEquals(3, result); InputStream translatedResource = getResourceAsInputStream("languageUtils", "CodeSystem-answer-translated.json"); String text = new BufferedReader(new InputStreamReader(translatedResource)) 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 fae4060880..7fc1cdad6d 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 @@ -80,8 +80,8 @@ public void entry(TextUnit unit) { JsonObject entry = new JsonObject(); json.forceArray("entries").add(entry); entry.add("id", unit.getId()); - if (unit.getContext1() != null) { - entry.add("context", unit.getContext1()); + if (unit.getContext() != null) { + entry.add("context", unit.getContext()); } entry.add("source", unit.getSrcText()); entry.add("target", unit.getTgtText()); @@ -127,8 +127,8 @@ public void produce(String id, String baseLang, String targetLang, List "+targetLang); ln(""); + ln("\"Language: pt\\n\""); + ln(""); + } protected void ln(String line) { @@ -74,10 +82,10 @@ public void finish() throws IOException { @Override public void entry(TextUnit unit) { - ln("#: "+unit.getId()); - if (unit.getContext1() != null) { - ln("#. "+unit.getContext1()); + if (unit.getContext() != null) { + ln("#. "+unit.getContext()); } + ln("msgctxt \""+unit.getId()+"\""); ln("msgid \""+unit.getSrcText()+"\""); ln("msgstr \""+(unit.getTgtText() == null ? "" : unit.getTgtText())+"\""); ln(""); @@ -160,16 +168,21 @@ protected void ln(StringBuilder po, String line) { @Override public void produce(String id, String baseLang, String targetLang, List translations, String filename) throws IOException { StringBuilder po = new StringBuilder(); + ln(po, "msgid \"\""); + ln(po, "msgstr \"\""); + ln(po, "\"Language: "+targetLang+"\\n\""); + ln(po, "\"X-Generator: Poedit 3.5\\n\""); + ln(po, ""); ln(po, "# "+baseLang+" -> "+targetLang); ln(po, ""); for (TranslationUnit tu : translations) { - ln(po, "#: "+tu.getId()); - if (tu.getContext1() != null) { - ln(po, "#. "+tu.getContext1()); + if (tu.getContext() != null) { + ln(po, "#. "+tu.getContext()); } if (tu.getOriginal() != null) { ln(po, "#| "+tu.getOriginal()); } + ln(po, "msgctxt \""+tu.getId()+"\""); 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/XLIFFProducer.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/XLIFFProducer.java index 6847a85b6a..8a7e6b00f3 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/XLIFFProducer.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/i18n/XLIFFProducer.java @@ -47,9 +47,9 @@ public void finish() throws IOException { public void entry(TextUnit unit) { i++; ln(" "); - if (unit.getContext1() != null) { + if (unit.getContext() != null) { ln(" "); - ln(" "+Utilities.escapeXml(unit.getContext1())+""); + ln(" "+Utilities.escapeXml(unit.getContext())+""); ln(" "); } ln(" "+Utilities.escapeXml(unit.getSrcText())+""); @@ -149,10 +149,10 @@ public void produce(String id, String baseLang, String targetLang, List"); - if (tu.getContext1() != null) { + if (tu.getContext() != null) { i++; ln(xml, " "); - ln(xml, " "+Utilities.escapeXml(tu.getContext1())+""); + ln(xml, " "+Utilities.escapeXml(tu.getContext())+""); ln(xml, " "); } ln(xml, " "+Utilities.escapeXml(tu.getSrcText())+""); From e3f25dd3c33ac2698160f4426456d834ff5940e9 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Sun, 15 Dec 2024 04:51:34 +1100 Subject: [PATCH 07/15] Add support for languages to npm package and package list --- .../org/hl7/fhir/utilities/StringPair.java | 15 ++++++ .../hl7/fhir/utilities/npm/NpmPackage.java | 36 ++++++++++++- .../hl7/fhir/utilities/npm/PackageList.java | 8 +++ .../fhir/utilities/json/JsonParserTests.java | 7 ++- .../tests/TestInstanceGenerationTester.java | 30 +++++++++++ .../org.hl7.fhir.validation/4.0.1/loinc.cache | 50 +++++++++++++++++-- 6 files changed, 141 insertions(+), 5 deletions(-) create mode 100644 org.hl7.fhir.validation/src/test/java/org/hl7/fhir/generation/tests/TestInstanceGenerationTester.java diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/StringPair.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/StringPair.java index d987390102..21662be2a6 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/StringPair.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/StringPair.java @@ -1,6 +1,21 @@ package org.hl7.fhir.utilities; +import java.util.Comparator; + public class StringPair { + + public static class Sorter implements Comparator { + + @Override + public int compare(StringPair o1, StringPair o2) { + int res = o1.name.compareTo(o2.name); + if (res == 0) { + res = o1.value.compareTo(o2.value); + } + return res; + } + + } private String name; private String value; diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java index 20b316642b..81fd9ae564 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/NpmPackage.java @@ -60,6 +60,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWIS import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.utilities.ByteProvider; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; +import org.hl7.fhir.utilities.StringPair; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.filesystem.ManagedFileAccess; @@ -751,9 +752,17 @@ public List listResources(String... types) throws IOException { return listResources(Utilities.strings(types)); } + public List listResourcesinFolder(String folder, String... types) throws IOException { + return listResourcesInFolder(folder, Utilities.strings(types)); + } + public List listResources(List types) throws IOException { + return listResourcesInFolder("package", types); + } + + public List listResourcesInFolder(String folderName, List types) throws IOException { List res = new ArrayList(); - NpmPackageFolder folder = folders.get("package"); + NpmPackageFolder folder = folders.get(folderName); if (types.size() == 0) { for (String s : folder.types.keySet()) { if (folder.types.containsKey(s)) { @@ -771,6 +780,31 @@ public List listResources(List types) throws IOException { return res; } + public List listAllResources(List types) throws IOException { + List res = new ArrayList(); + for (NpmPackageFolder folder : folders.values()) { + if (types.size() == 0) { + for (String s : folder.types.keySet()) { + if (folder.types.containsKey(s)) { + for (String n : folder.types.get(s)) { + res.add(new StringPair(folder.folderName, n)); + } + } + } + } else { + for (String s : types) { + if (folder.types.containsKey(s)) { + for (String n : folder.types.get(s)) { + res.add(new StringPair(folder.folderName, n)); + } + } + } + } + } + Collections.sort(res, new StringPair.Sorter()); + return res; + } + public List listIndexedResources(String... types) throws IOException { return listIndexedResources(Utilities.strings(types)); } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageList.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageList.java index 7e179ffe97..4748475d27 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageList.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageList.java @@ -176,6 +176,14 @@ public void update(String version, String path, String status, String sequence, setDate(date); } + public List languages() { + return json.forceArray("languages").asStrings(); + } + + public PackageListEntry addLang(String langCode) { + json.forceArray("languages").add(langCode); + return this; + } } private String source; diff --git a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/json/JsonParserTests.java b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/json/JsonParserTests.java index 8aa6263d0b..1a38d58c6f 100644 --- a/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/json/JsonParserTests.java +++ b/org.hl7.fhir.utilities/src/test/java/org/hl7/fhir/utilities/json/JsonParserTests.java @@ -506,7 +506,12 @@ public void testElementNumber() throws IOException, JsonException { Assertions.assertEquals("-1.2e10", JsonParser.compose(e)); Assertions.assertEquals("// comment\n-1.2e10\n", JsonParser.compose(e, true)); } - + + @Test + public void testDecimal() throws IOException, JsonException { + JsonObject o = JsonParser.parseObject("{ \"n\" : 0.00001 }"); + Assertions.assertEquals("0.00001", o.getJsonNumber("n").asString()); + } @Test public void testElementString() throws IOException, JsonException { JsonElement e = JsonParser.parse("\"str\\ning\""); diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/generation/tests/TestInstanceGenerationTester.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/generation/tests/TestInstanceGenerationTester.java new file mode 100644 index 0000000000..5991f413db --- /dev/null +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/generation/tests/TestInstanceGenerationTester.java @@ -0,0 +1,30 @@ +package org.hl7.fhir.generation.tests; + +import java.io.IOException; + +import org.hl7.fhir.convertors.loaders.loaderR5.NullLoaderKnowledgeProviderR5; +import org.hl7.fhir.convertors.loaders.loaderR5.R4ToR5Loader; +import org.hl7.fhir.r5.context.SimpleWorkerContext; +import org.hl7.fhir.r5.context.SimpleWorkerContext.SimpleWorkerContextBuilder; +import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat; +import org.hl7.fhir.r5.model.StructureDefinition; +import org.hl7.fhir.r5.profilemodel.TestInstanceGenerator; +import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.junit.jupiter.api.Test; + +public class TestInstanceGenerationTester { + + @Test + public void testBasic() throws IOException { + FilesystemPackageCacheManager pcm = new FilesystemPackageCacheManager.Builder().build(); + SimpleWorkerContext context = new SimpleWorkerContextBuilder().withAllowLoadingDuplicates(true).fromPackage(pcm.loadPackage("hl7.fhir.r4.core")); + context.loadFromPackage(pcm.loadPackage("hl7.fhir.us.core#6.0.0"), new R4ToR5Loader(Utilities.strings("CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"), + new NullLoaderKnowledgeProviderR5(), context.getVersion())); + + TestInstanceGenerator gen = new TestInstanceGenerator(context); + byte[] output = gen.generate(context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient"), FhirFormat.JSON); + String res = new String(output); + System.out.println(res); + } +} 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 9e797a65fa..6f8babbcfa 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 @@ -11179,7 +11179,6 @@ v: { "error" : "Wrong Display Name 'O2 % BldC Oximetry' for http://loinc.org#59408-5. Valid display is one of 3 choices: 'Oxygen saturation in Arterial blood by Pulse oximetry' (en-US), 'Oxygen saturation in Arterial blood by Pulse oximetry' (en-US) or 'SaO2 % BldA PulseOx' (en-US) (for the language(s) 'en-US')", "class" : "UNKNOWN", "server" : "http://tx-dev.fhir.org/r4", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome", "issue" : [{ @@ -11222,7 +11221,6 @@ v: { "system" : "http://loinc.org", "version" : "2.78", "server" : "http://tx-dev.fhir.org/r4", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome" } @@ -11251,7 +11249,6 @@ v: { "error" : "Wrong Display Name 'Flow Rate' for http://loinc.org#3151-8. Valid display is one of 4 choices: 'Inhaled oxygen flow rate' (en-US), 'Inhaled oxygen flow rate' (en-US), 'Inhaled O2 flow rate' (en-US) or 'Inhaled oxygen' (en-US) (for the language(s) 'en-US')", "class" : "UNKNOWN", "server" : "http://tx-dev.fhir.org/r4", - "unknown-systems" : "", "issues" : { "resourceType" : "OperationOutcome", "issue" : [{ @@ -11275,3 +11272,50 @@ v: { } ------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://loinc.org", + "code" : "18776-5", + "display" : "Plan of care note" +}, "valueSet" :null, "langs":"en-US", "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" : "Plan of care note", + "code" : "18776-5", + "system" : "http://loinc.org", + "version" : "2.78", + "server" : "http://tx-dev.fhir.org/r4", + "unknown-systems" : "", + "issues" : { + "resourceType" : "OperationOutcome" +} + +} +------------------------------------------------------------------------------------- +{"code" : { + "system" : "http://loinc.org", + "code" : "18776-5" +}, "url": "http://hl7.org/fhir/ValueSet/doc-typecodes--0", "version": "4.0.1", "langs":"en-US", "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" : "Plan of care note", + "code" : "18776-5", + "system" : "http://loinc.org", + "version" : "2.78", + "server" : "http://tx-dev.fhir.org/r4", + "unknown-systems" : "", + "issues" : { + "resourceType" : "OperationOutcome" +} + +} +------------------------------------------------------------------------------------- From d014b1f10ae30d19cf77446c402bb74d33c84751 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Sun, 15 Dec 2024 04:52:03 +1100 Subject: [PATCH 08/15] fix error message validating ConceptMap when size too large --- .../hl7/fhir/validation/instance/type/ValueSetValidator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 7f7617898c..6ed9f5831a 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 @@ -324,7 +324,7 @@ private boolean validateValueSetInclude(ValidationContext valContext, List batch = new ArrayList<>(); boolean first = true; if (concepts.size() > TOO_MANY_CODES_TO_VALIDATE) { - hint(errors, "2023-09-06", IssueType.BUSINESSRULE, stack, false, I18nConstants.VALUESET_INC_TOO_MANY_CODES, batch.size()); + hint(errors, "2023-09-06", IssueType.BUSINESSRULE, stack, false, I18nConstants.VALUESET_INC_TOO_MANY_CODES, concepts.size()); } else { if (((InstanceValidator) parent).isValidateValueSetCodesOnTxServer() && !context.isNoTerminologyServer()) { try { From 98966e4f08615c82d1014b155f60a60c4f76a8d1 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Sun, 15 Dec 2024 04:52:17 +1100 Subject: [PATCH 09/15] more work on test instance generation --- .../convertors/analytics/PackageVisitor.java | 8 +- .../TestGenerationDataGenerator.java | 782 ++++++++++++++++++ 2 files changed, 786 insertions(+), 4 deletions(-) create mode 100644 org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/analytics/TestGenerationDataGenerator.java diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/analytics/PackageVisitor.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/analytics/PackageVisitor.java index 232db1642a..98196ebabf 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/analytics/PackageVisitor.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/analytics/PackageVisitor.java @@ -68,7 +68,7 @@ public interface IPackageVisitorProcessor { public void alreadyVisited(String pid) throws FHIRException, IOException, EOperationOutcome; } - private List resourceTypes = new ArrayList<>(); + private Set resourceTypes = new HashSet<>(); private List versions = new ArrayList<>(); private boolean corePackages; private boolean oldVersions; @@ -79,16 +79,16 @@ public interface IPackageVisitorProcessor { private String cache; private int step; - public List getResourceTypes() { + public Set getResourceTypes() { return resourceTypes; } - public void setResourceTypes(List resourceTypes) { + public void setResourceTypes(Set resourceTypes) { this.resourceTypes = resourceTypes; } public void setResourceTypes(String... resourceTypes) { - this.resourceTypes = new ArrayList(); + this.resourceTypes = new HashSet(); for (String s : resourceTypes) { this.resourceTypes.add(s); } diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/analytics/TestGenerationDataGenerator.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/analytics/TestGenerationDataGenerator.java new file mode 100644 index 0000000000..82b7062360 --- /dev/null +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/analytics/TestGenerationDataGenerator.java @@ -0,0 +1,782 @@ +package org.hl7.fhir.convertors.analytics; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.xml.parsers.ParserConfigurationException; + +import org.hl7.fhir.convertors.analytics.PackageVisitor.IPackageVisitorProcessor; +import org.hl7.fhir.convertors.analytics.PackageVisitor.PackageContext; +import org.hl7.fhir.exceptions.FHIRException; +import org.hl7.fhir.r5.context.IWorkerContext; +import org.hl7.fhir.r5.context.SimpleWorkerContext; +import org.hl7.fhir.r5.context.SimpleWorkerContext.SimpleWorkerContextBuilder; +import org.hl7.fhir.r5.elementmodel.Element; +import org.hl7.fhir.r5.elementmodel.Manager; +import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat; +import org.hl7.fhir.r5.elementmodel.ValidatedFragment; +import org.hl7.fhir.r5.utils.EOperationOutcome; +import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; +import org.hl7.fhir.utilities.StringPair; +import org.hl7.fhir.utilities.TextFile; +import org.hl7.fhir.utilities.Utilities; +import org.hl7.fhir.utilities.VersionUtilities; +import org.hl7.fhir.utilities.filesystem.ManagedFileAccess; +import org.hl7.fhir.utilities.http.ManagedWebAccess; +import org.hl7.fhir.utilities.http.ManagedWebAccess.WebAccessPolicy; +import org.hl7.fhir.utilities.npm.FilesystemPackageCacheManager; +import org.hl7.fhir.utilities.npm.NpmPackage; +import org.xml.sax.SAXException; + +public class TestGenerationDataGenerator implements IPackageVisitorProcessor { + + private static class Counter { + private int key; + private int count; + } + private Map> hashes = new HashMap>(); + private Map elements = new HashMap(); + private Map types = new HashMap(); + private Map contexts= new HashMap<>(); + private Connection conn; + private PreparedStatement psqlE; + private PreparedStatement psqlT; + private PreparedStatement psqlV; + private int keyV = 0; + private int keyT = 0; + private int keyE = 0; + private PreparedStatement psqlEC; + private PreparedStatement psqlET; + + + @Override + public void alreadyVisited(String pid) { + + } + + @Override + public Object startPackage(PackageContext ctxt) { + return null; + } + + @Override + public void processResource(PackageContext ctxt, Object context, String type, String id, byte[] content) throws FHIRException, IOException, EOperationOutcome { + String version = ctxt.getNpm().fhirVersion(); + IWorkerContext worker = contexts.get(version); + if (worker == null) { + FilesystemPackageCacheManager pcm = new FilesystemPackageCacheManager.Builder().build(); + NpmPackage npm = pcm.loadPackage(VersionUtilities.packageForVersion(version)); + SimpleWorkerContext swc = new SimpleWorkerContextBuilder().withAllowLoadingDuplicates(true).fromPackage(npm); + contexts.put(version, swc); + worker = swc; + } + List res = Manager.parse(worker, new ByteArrayInputStream(content), FhirFormat.JSON); + if (res.size() > 0) { + try { + processElement(res.get(0).getElement()); + } catch (SQLException e) { + throw new FHIRException(e); + } + } + } + + private void processElement(Element element) throws SQLException { + String id = element.getProperty().getDefinition().getId(); + switch (element.fhirType()) { + case "Address": + recordValue(id, "Address", getValues(element, "use", "type", "text", "line", "city", "district", "state", "postalCode", "country")); + break; + case "Age": + recordValue(id, "Age", getValues(element, "value", "comparator", "unit", "system", "code")); + break; + case "Annotation": + recordValue(id, "Annotation", getValues(element, "author", "time", "text")); + break; + case "Attachment": + recordValue(id, "Attachment", getValues(element, "contentType", "language", "data", "url", "size", "hash", "title")); + break; + case "CodeableConcept": + break; + case "CodeableReference": + break; + case "Coding": + recordValue(id, "Coding", getValues(element, "system", "version", "code", "display")); + break; + case "ContactPoint": + recordValue(id, "ContactPoint", getValues(element, "system", "value", "use", "rank")); + break; + case "Count": + recordValue(id, "Count", getValues(element, "value", "comparator", "unit", "system", "code")); + break; + case "Distance": + recordValue(id, "Distance", getValues(element, "value", "comparator", "unit", "system", "code")); + break; + case "Duration": + recordValue(id, "Duration", getValues(element, "value", "comparator", "unit", "system", "code")); + break; + case "HumanName": + recordValue(id, "Address", getValues(element, "use", "text", "family", "given", "prefix", "suffix")); + break; + case "Identifier": + recordValue(id, "Identifier", getValues(element, "use", "type", "system", "value")); + break; + case "Money": + recordValue(id, "Money", getValues(element, "value", "currency")); + break; + case "Period": + recordValue(id, "Period", getValues(element, "start", "end")); + break; + case "Quantity": + recordValue(id, "Quantity", getValues(element, "value", "comparator", "unit", "system", "code")); + break; + case "Range": + case "Ratio": + case "RatioRange": + case "Reference": + case "SampledData": + case "Signature": + case "Timing": + case "RelatedArtifact": + case "DataRequirement": + case "Expression": + break; + case "xhtml": + case "id": + case "canonical": + case "boolean": + case "code": + case "uri": + case "instant": + break; + default: + if (element.isPrimitive()) { + recordValue(id, element.fhirType(), element.primitiveValue()); + } else { + for (Element child : element.getChildren()) { + if (!child.fhirType().equals("Extension") && !child.getPath().endsWith(".id") && !child.getPath().endsWith(".linkId")) { + if (!child.isResource() || !Utilities.existsInList(child.fhirType(), "Bundle", "CapabilityStatement", "CodeSystem", "ConceptMap", "GraphDefinition", "ImplementationGuide", "MessageHeader", "NamingSystem", "OperationDefinition", "OperationOutcome", "Parameters", "SearchParameter", "StructureDefinition", "StructureMap", "TerminologyCapabilities", "ValueSet")) { + processElement(child); + } + } + } + } + } + } + + private String[] getValues(Element element, String... names) { + List values = new ArrayList<>(); + for (String name : names) { + List children = element.getChildren(name); + if (!children.isEmpty()) { + CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder("~"); + for (Element child : children) { + if (child.hasPrimitiveValue()) { + b.append(child.primitiveValue()); + } + } + if (b.length() > 0) { + values.add(name+":"+b.toString()); + } + } + } + + return values.toArray(new String[0]); + } + + public void start(String filename) throws SQLException, IOException { + ManagedFileAccess.file(filename).delete(); + conn = DriverManager.getConnection("jdbc:sqlite:"+filename); + Statement stmt = conn.createStatement(); + stmt.execute("CREATE TABLE TestElements (ElementKey int NOT NULL, ElementId nvarchar NOT NULL, Count int NULL, PRIMARY KEY (ElementKey))"); + stmt.execute("CREATE INDEX TestElementsElement ON TestElements ( ElementId )"); + + stmt.execute("CREATE TABLE TestTypes (TypeKey int NOT NULL, TypeName nvarchar NOT NULL, Count int NULL, PRIMARY KEY (TypeKey))"); + stmt.execute("CREATE INDEX TestTypesType ON TestTypes ( TypeName )"); + + stmt.execute("CREATE TABLE TestValues (ValueKey int NOT NULL, ElementKey int NOT NULL, TypeKey int NOT NULL, ValueData nvarchar NOT NULL, PRIMARY KEY (ValueKey))"); + stmt.execute("CREATE INDEX TestValueElement ON TestValues ( ElementKey, TypeKey)"); + + psqlE = conn.prepareStatement("Insert into TestElements (ElementKey, ElementId) values (?, ?)"); + psqlT = conn.prepareStatement("Insert into TestTypes (TypeKey, TypeName) values (?, ?)"); + psqlV = conn.prepareStatement("Insert into TestValues (ValueKey, ElementKey, TypeKey, ValueData) values (?, ?, ?, ?)"); + psqlEC = conn.prepareStatement("Update TestElements set Count = ? where ElementKey = ?"); + psqlET = conn.prepareStatement("Update TestTypes set Count = ? where TypeKey = ?"); + } + + private void store(String path, String type, String[] values) throws SQLException { + Counter cE = elements.get(path); + if (cE != null) { + cE.count++; + psqlEC.setInt(1, cE.count); + psqlEC.setInt(2, cE.key); + psqlEC.execute(); + } else { + keyE++; + cE = new Counter(); + cE.key = keyE; + cE.count = 1; + elements.put(path, cE); + psqlE.setInt(1, cE.key); + psqlE.setString(2, path); + psqlE.execute(); + } + + Counter cT = types.get(type); + if (cT != null) { + cT.count++; + psqlET.setInt(1, cT.count); + psqlET.setInt(2, cT.key); + psqlET.execute(); + } else { + keyT++; + cT = new Counter(); + cT.key = keyT; + cT.count = 1; + types.put(type, cT); + psqlT.setInt(1, cT.key); + psqlT.setString(2, type); + psqlT.execute(); + } + + psqlV.setInt(1, keyE++); + psqlV.setInt(2, cE.key); + psqlV.setInt(3, cT.key); + psqlV.setString(4, CommaSeparatedStringBuilder.join("|:|",values)); + psqlV.execute(); + } + + private void recordValue(String path, String type, String... values) throws SQLException { + StringBuilder v = new StringBuilder(); + v.append(type); + v.append("|"); + for (String s : values) { + v.append(s); + v.append("|"); + } + Set hashset = hashes.get(path); + if (hashset == null) { + hashset = new HashSet(); + hashes.put(path, hashset); + } + String s= v.toString(); + if (!hashset.contains(s)) { + hashset.add(s); + store(path, type, values); + } + } + + @Override + public void finishPackage(PackageContext ctxt) { + + } + + + public static void main(String[] args) throws Exception { + new TestGenerationDataGenerator().execute(); + // new TestGenerationDataGenerator().offAirWExecute(); + } + + private void offAirWExecute() throws FHIRException, IOException, EOperationOutcome, SQLException { + ManagedWebAccess.setAccessPolicy(WebAccessPolicy.PROHIBITED); + start("/Users/grahamegrieve/temp/testdata.db"); + FilesystemPackageCacheManager pcm = new FilesystemPackageCacheManager.Builder().build(); + + System.out.println("Processing"); + for (String pid : pcm.listPackages()) { + System.out.println(pid); + NpmPackage npm = pcm.loadPackage(pid); + try { + processPackage(npm); + } catch (Exception e) { + System.out.println(" "+e.getMessage()); + } + } + System.out.print("Done"); + } + + private void processPackage(NpmPackage npm) throws IOException, FHIRException, EOperationOutcome { + + + String fv = npm.fhirVersion(); + String v = npm.version(); + PackageContext ctxt = new PackageContext(npm.name()+"#"+v, npm, fv); + boolean ok = false; + Object context = null; + context = startPackage(ctxt); + ok = true; + if (ok) { + int c = 0; + Set resourceTypes = new HashSet(); + addR5ResourceNames(resourceTypes); + addR4ResourceNames(resourceTypes); + addR3ResourceNames(resourceTypes); + + for (String type : resourceTypes) { + List rt = new ArrayList(); + rt.add(type); + for (StringPair s : npm.listAllResources(rt)) { + c++; + processResource(ctxt, context, type, s.getName(), TextFile.streamToBytes(npm.load(s.getName(), s.getValue()))); + } + } + } + finishPackage(ctxt); + } + + + private void execute() throws IOException, ParserConfigurationException, SAXException, FHIRException, EOperationOutcome, SQLException { + start("/Users/grahamegrieve/temp/testdata.db"); + PackageVisitor pv = new PackageVisitor(); + addR5ResourceNames(pv.getResourceTypes()); + addR4ResourceNames(pv.getResourceTypes()); + addR3ResourceNames(pv.getResourceTypes()); + + pv.setOldVersions(false); + pv.setCorePackages(true); + pv.setProcessor(this); + pv.visitPackages(); + System.out.println("Done"); + + } + + private void addR5ResourceNames(Set set) { + set.add("Account"); + set.add("ActivityDefinition"); + set.add("ActorDefinition"); + set.add("AdministrableProductDefinition"); + set.add("AdverseEvent"); + set.add("AllergyIntolerance"); + set.add("Appointment"); + set.add("AppointmentResponse"); + set.add("ArtifactAssessment"); + set.add("AuditEvent"); + set.add("Basic"); +// set.add("Binary"); + set.add("BiologicallyDerivedProduct"); + set.add("BiologicallyDerivedProductDispense"); + set.add("BodyStructure"); +// set.add("Bundle"); +// set.add("CapabilityStatement"); + set.add("CarePlan"); + set.add("CareTeam"); + set.add("ChargeItem"); + set.add("ChargeItemDefinition"); + set.add("Citation"); + set.add("Claim"); + set.add("ClaimResponse"); + set.add("ClinicalImpression"); + set.add("ClinicalUseDefinition"); +// set.add("CodeSystem"); + set.add("Communication"); + set.add("CommunicationRequest"); + set.add("CompartmentDefinition"); + set.add("Composition"); +// set.add("ConceptMap"); + set.add("Condition"); + set.add("ConditionDefinition"); + set.add("Consent"); + set.add("Contract"); + set.add("Coverage"); + set.add("CoverageEligibilityRequest"); + set.add("CoverageEligibilityResponse"); + set.add("DetectedIssue"); + set.add("Device"); + set.add("DeviceAssociation"); + set.add("DeviceDefinition"); + set.add("DeviceDispense"); + set.add("DeviceMetric"); + set.add("DeviceRequest"); + set.add("DeviceUsage"); + set.add("DiagnosticReport"); + set.add("DocumentReference"); + set.add("Encounter"); + set.add("EncounterHistory"); + set.add("Endpoint"); + set.add("EnrollmentRequest"); + set.add("EnrollmentResponse"); + set.add("EpisodeOfCare"); + set.add("EventDefinition"); + set.add("Evidence"); + set.add("EvidenceReport"); + set.add("EvidenceVariable"); + set.add("ExampleScenario"); + set.add("ExplanationOfBenefit"); + set.add("FamilyMemberHistory"); + set.add("Flag"); + set.add("FormularyItem"); + set.add("GenomicStudy"); + set.add("Goal"); +// set.add("GraphDefinition"); + set.add("Group"); + set.add("GuidanceResponse"); + set.add("HealthcareService"); + set.add("ImagingSelection"); + set.add("ImagingStudy"); + set.add("Immunization"); + set.add("ImmunizationEvaluation"); + set.add("ImmunizationRecommendation"); +// set.add("ImplementationGuide"); + set.add("Ingredient"); + set.add("InsurancePlan"); + set.add("InventoryItem"); + set.add("InventoryReport"); + set.add("Invoice"); + set.add("Library"); + set.add("Linkage"); + set.add("List"); + set.add("Location"); + set.add("ManufacturedItemDefinition"); + set.add("Measure"); + set.add("MeasureReport"); + set.add("Medication"); + set.add("MedicationAdministration"); + set.add("MedicationDispense"); + set.add("MedicationKnowledge"); + set.add("MedicationRequest"); + set.add("MedicationStatement"); + set.add("MedicinalProductDefinition"); + set.add("MessageDefinition"); +// set.add("MessageHeader"); + set.add("MolecularSequence"); +// set.add("NamingSystem"); + set.add("NutritionIntake"); + set.add("NutritionOrder"); + set.add("NutritionProduct"); + set.add("Observation"); + set.add("ObservationDefinition"); +// set.add("OperationDefinition"); +// set.add("OperationOutcome"); + set.add("Organization"); + set.add("OrganizationAffiliation"); + set.add("PackagedProductDefinition"); +// set.add("Parameters"); + set.add("Patient"); + set.add("PaymentNotice"); + set.add("PaymentReconciliation"); + set.add("Permission"); + set.add("Person"); + set.add("PlanDefinition"); + set.add("Practitioner"); + set.add("PractitionerRole"); + set.add("Procedure"); + set.add("Provenance"); + set.add("Questionnaire"); + set.add("QuestionnaireResponse"); + set.add("RegulatedAuthorization"); + set.add("RelatedPerson"); + set.add("RequestOrchestration"); + set.add("Requirements"); + set.add("ResearchStudy"); + set.add("ResearchSubject"); + set.add("RiskAssessment"); + set.add("Schedule"); +// set.add("SearchParameter"); + set.add("ServiceRequest"); + set.add("Slot"); + set.add("Specimen"); + set.add("SpecimenDefinition"); +// set.add("StructureDefinition"); +// set.add("StructureMap"); + set.add("Subscription"); + set.add("SubscriptionStatus"); + set.add("SubscriptionTopic"); + set.add("Substance"); + set.add("SubstanceDefinition"); + set.add("SubstanceNucleicAcid"); + set.add("SubstancePolymer"); + set.add("SubstanceProtein"); + set.add("SubstanceReferenceInformation"); + set.add("SubstanceSourceMaterial"); + set.add("SupplyDelivery"); + set.add("SupplyRequest"); + set.add("Task"); +// set.add("TerminologyCapabilities"); + set.add("TestPlan"); + set.add("TestReport"); + set.add("TestScript"); + set.add("Transport"); +// set.add("ValueSet"); + set.add("VerificationResult"); + set.add("VisionPrescription"); + } + + private void addR4ResourceNames(Set set) { + set.add("Account"); + set.add("ActivityDefinition"); + set.add("AdverseEvent"); + set.add("AllergyIntolerance"); + set.add("Appointment"); + set.add("AppointmentResponse"); + set.add("AuditEvent"); + set.add("Basic"); +// set.add("Binary"); + set.add("BiologicallyDerivedProduct"); + set.add("BodyStructure"); +// set.add("Bundle"); +// set.add("CapabilityStatement"); + set.add("CarePlan"); + set.add("CareTeam"); + set.add("CatalogEntry"); + set.add("ChargeItem"); + set.add("ChargeItemDefinition"); + set.add("Claim"); + set.add("ClaimResponse"); + set.add("ClinicalImpression"); +// set.add("CodeSystem"); + set.add("Communication"); + set.add("CommunicationRequest"); + set.add("CompartmentDefinition"); + set.add("Composition"); +// set.add("ConceptMap"); + set.add("Condition"); + set.add("Consent"); + set.add("Contract"); + set.add("Coverage"); + set.add("CoverageEligibilityRequest"); + set.add("CoverageEligibilityResponse"); + set.add("DetectedIssue"); + set.add("Device"); + set.add("DeviceDefinition"); + set.add("DeviceMetric"); + set.add("DeviceRequest"); + set.add("DeviceUseStatement"); + set.add("DiagnosticReport"); + set.add("DocumentManifest"); + set.add("DocumentReference"); + set.add("EffectEvidenceSynthesis"); + set.add("Encounter"); + set.add("Endpoint"); + set.add("EnrollmentRequest"); + set.add("EnrollmentResponse"); + set.add("EpisodeOfCare"); + set.add("EventDefinition"); + set.add("Evidence"); + set.add("EvidenceVariable"); + set.add("ExampleScenario"); + set.add("ExplanationOfBenefit"); + set.add("FamilyMemberHistory"); + set.add("Flag"); + set.add("Goal"); +// set.add("GraphDefinition"); + set.add("Group"); + set.add("GuidanceResponse"); + set.add("HealthcareService"); + set.add("ImagingStudy"); + set.add("Immunization"); + set.add("ImmunizationEvaluation"); + set.add("ImmunizationRecommendation"); +// set.add("ImplementationGuide"); + set.add("InsurancePlan"); + set.add("Invoice"); + set.add("Library"); + set.add("Linkage"); + set.add("List"); + set.add("Location"); + set.add("Measure"); + set.add("MeasureReport"); + set.add("Media"); + set.add("Medication"); + set.add("MedicationAdministration"); + set.add("MedicationDispense"); + set.add("MedicationKnowledge"); + set.add("MedicationRequest"); + set.add("MedicationStatement"); + set.add("MedicinalProduct"); + set.add("MedicinalProductAuthorization"); + set.add("MedicinalProductContraindication"); + set.add("MedicinalProductIndication"); + set.add("MedicinalProductIngredient"); + set.add("MedicinalProductInteraction"); + set.add("MedicinalProductManufactured"); + set.add("MedicinalProductPackaged"); + set.add("MedicinalProductPharmaceutical"); + set.add("MedicinalProductUndesirableEffect"); + set.add("MessageDefinition"); +// set.add("MessageHeader"); + set.add("MolecularSequence"); +// set.add("NamingSystem"); + set.add("NutritionOrder"); + set.add("Observation"); + set.add("ObservationDefinition"); +// set.add("OperationDefinition"); +// set.add("OperationOutcome"); + set.add("Organization"); + set.add("OrganizationAffiliation"); +// set.add("Parameters"); + set.add("Patient"); + set.add("PaymentNotice"); + set.add("PaymentReconciliation"); + set.add("Person"); + set.add("PlanDefinition"); + set.add("Practitioner"); + set.add("PractitionerRole"); + set.add("Procedure"); + set.add("Provenance"); + set.add("Questionnaire"); + set.add("QuestionnaireResponse"); + set.add("RelatedPerson"); + set.add("RequestGroup"); + set.add("ResearchDefinition"); + set.add("ResearchElementDefinition"); + set.add("ResearchStudy"); + set.add("ResearchSubject"); + set.add("RiskAssessment"); + set.add("RiskEvidenceSynthesis"); + set.add("Schedule"); +// set.add("SearchParameter"); + set.add("ServiceRequest"); + set.add("Slot"); + set.add("Specimen"); + set.add("SpecimenDefinition"); +// set.add("StructureDefinition"); +// set.add("StructureMap"); + set.add("Subscription"); + set.add("Substance"); + set.add("SubstancePolymer"); + set.add("SubstanceProtein"); + set.add("SubstanceReferenceInformation"); + set.add("SubstanceSpecification"); + set.add("SubstanceSourceMaterial"); + set.add("SupplyDelivery"); + set.add("SupplyRequest"); + set.add("Task"); + set.add("TerminologyCapabilities"); + set.add("TestReport"); + set.add("TestScript"); +// set.add("ValueSet"); + set.add("VerificationResult"); + set.add("VisionPrescription"); + } + + private void addR3ResourceNames(Set set) { + set.add("Account"); + set.add("ActivityDefinition"); + set.add("AllergyIntolerance"); + set.add("AdverseEvent"); + set.add("Appointment"); + set.add("AppointmentResponse"); + set.add("AuditEvent"); + set.add("Basic"); +// set.add("Binary"); + set.add("BodySite"); +// set.add("Bundle"); +// set.add("CapabilityStatement"); + set.add("CarePlan"); + set.add("CareTeam"); + set.add("ChargeItem"); + set.add("Claim"); + set.add("ClaimResponse"); + set.add("ClinicalImpression"); +// set.add("CodeSystem"); + set.add("Communication"); + set.add("CommunicationRequest"); + set.add("CompartmentDefinition"); + set.add("Composition"); +// set.add("ConceptMap"); + set.add("Condition"); + set.add("Consent"); + set.add("Contract"); + set.add("Coverage"); + set.add("DataElement"); + set.add("DetectedIssue"); + set.add("Device"); + set.add("DeviceComponent"); + set.add("DeviceMetric"); + set.add("DeviceRequest"); + set.add("DeviceUseStatement"); + set.add("DiagnosticReport"); + set.add("DocumentManifest"); + set.add("DocumentReference"); + set.add("EligibilityRequest"); + set.add("EligibilityResponse"); + set.add("Encounter"); + set.add("Endpoint"); + set.add("EnrollmentRequest"); + set.add("EnrollmentResponse"); + set.add("EpisodeOfCare"); + set.add("ExpansionProfile"); + set.add("ExplanationOfBenefit"); + set.add("FamilyMemberHistory"); + set.add("Flag"); + set.add("Goal"); +// set.add("GraphDefinition"); + set.add("Group"); + set.add("GuidanceResponse"); + set.add("HealthcareService"); + set.add("ImagingManifest"); + set.add("ImagingStudy"); + set.add("Immunization"); + set.add("ImmunizationRecommendation"); +// set.add("ImplementationGuide"); + set.add("Library"); + set.add("Linkage"); + set.add("List"); + set.add("Location"); + set.add("Measure"); + set.add("MeasureReport"); + set.add("Media"); + set.add("Medication"); + set.add("MedicationAdministration"); + set.add("MedicationDispense"); + set.add("MedicationRequest"); + set.add("MedicationStatement"); + set.add("MessageDefinition"); +// set.add("MessageHeader"); +// set.add("NamingSystem"); + set.add("NutritionOrder"); + set.add("Observation"); +// set.add("OperationDefinition"); +// set.add("OperationOutcome"); + set.add("Organization"); +// set.add("Parameters"); + set.add("Patient"); + set.add("PaymentNotice"); + set.add("PaymentReconciliation"); + set.add("Person"); + set.add("PlanDefinition"); + set.add("Practitioner"); + set.add("PractitionerRole"); + set.add("Procedure"); + set.add("ProcedureRequest"); + set.add("ProcessRequest"); + set.add("ProcessResponse"); + set.add("Provenance"); + set.add("Questionnaire"); + set.add("QuestionnaireResponse"); + set.add("ReferralRequest"); + set.add("RelatedPerson"); + set.add("RequestGroup"); + set.add("ResearchStudy"); + set.add("ResearchSubject"); + set.add("RiskAssessment"); + set.add("Schedule"); +// set.add("SearchParameter"); + set.add("Sequence"); + set.add("ServiceDefinition"); + set.add("Slot"); + set.add("Specimen"); +// set.add("StructureDefinition"); +// set.add("StructureMap"); + set.add("Subscription"); + set.add("Substance"); + set.add("SupplyDelivery"); + set.add("SupplyRequest"); + set.add("Task"); + set.add("TestScript"); + set.add("TestReport"); +// set.add("ValueSet"); + set.add("VisionPrescription"); + } + +} From 96b04a33651dcb8b8e43b2a2ecfde05935010af6 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Sun, 15 Dec 2024 04:52:37 +1100 Subject: [PATCH 10/15] fix issue with value set version conversion on contains.property --- .../fhir/convertors/conv40_50/resources40_50/ValueSet40_50.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/resources40_50/ValueSet40_50.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/resources40_50/ValueSet40_50.java index 15e0ae2110..fb72f9bef4 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/resources40_50/ValueSet40_50.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/conv40_50/resources40_50/ValueSet40_50.java @@ -477,7 +477,7 @@ public static org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent for (org.hl7.fhir.r4.model.Extension t : src.getExtension()) { if ("http://hl7.org/fhir/5.0/StructureDefinition/extension-ValueSet.expansion.contains.property".equals(t.getUrl())) { ConceptPropertyComponent prop = tgt.addProperty(); - ConversionContext40_50.INSTANCE.getVersionConvertor_40_50().copyElement(t, prop, "code", "value[x]"); + ConversionContext40_50.INSTANCE.getVersionConvertor_40_50().copyElement(t, prop, "code", "value[x]", "value"); prop.setCode(t.getExtensionString("code")); if (t.hasExtension("value")) { prop.setValue(ConversionContext40_50.INSTANCE.getVersionConvertor_40_50().convertType(t.getExtensionByUrl("value").getValue())); From 023d87ad20815fc34b977bcaf02dd915bc958db9 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Sun, 15 Dec 2024 04:53:00 +1100 Subject: [PATCH 11/15] Switch priority order of package servers --- .../main/java/org/hl7/fhir/utilities/npm/PackageServer.java | 4 ++-- pom.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageServer.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageServer.java index 896126bd99..26a5e8424b 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageServer.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/PackageServer.java @@ -49,8 +49,8 @@ public PackageServer(String url) { - public static final String PRIMARY_SERVER = "https://packages.fhir.org"; - public static final String SECONDARY_SERVER = "https://packages2.fhir.org/packages"; + public static final String SECONDARY_SERVER = "https://packages.fhir.org"; + public static final String PRIMARY_SERVER = "https://packages2.fhir.org/packages"; public static PackageServer primaryServer() { return new PackageServer(PRIMARY_SERVER); diff --git a/pom.xml b/pom.xml index 8de072975c..7439586be2 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ 2.17.0 32.0.1-jre 6.4.1 - 1.7.0 + 1.7.1-SNAPSHOT 2.17.0 5.9.2 1.8.2 From a3804bab474ca75e5b4d19ad6976c17f392dbc8a Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Sun, 15 Dec 2024 07:23:18 +1100 Subject: [PATCH 12/15] fixes for snapshot generation test debugging --- .../org/hl7/fhir/convertors/loaders/XVersionLoader.java | 6 +++--- .../java/org/hl7/fhir/dstu2016may/formats/XmlParser.java | 8 ++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/XVersionLoader.java b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/XVersionLoader.java index e5df003d6d..a2b03eac15 100644 --- a/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/XVersionLoader.java +++ b/org.hl7.fhir.convertors/src/main/java/org/hl7/fhir/convertors/loaders/XVersionLoader.java @@ -57,14 +57,14 @@ public static Resource loadJson(String version, InputStream stream) throws FHIRE public static void saveXml(String version, Resource resource, OutputStream stream) throws FHIRFormatError, IOException { if (Utilities.noString(version)) { - new org.hl7.fhir.r5.formats.XmlParser().compose(stream, resource, true); + new org.hl7.fhir.r5.formats.XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(stream, resource); } switch (VersionUtilities.getMajMin(version)) { case "1.0": new org.hl7.fhir.dstu2.formats.XmlParser().compose(stream, VersionConvertorFactory_10_50.convertResource(resource), true); return; case "1.4": - new org.hl7.fhir.dstu2016may.formats.XmlParser().compose(stream, VersionConvertorFactory_14_50.convertResource(resource), true); + new org.hl7.fhir.dstu2016may.formats.XmlParser(true, true).compose(stream, VersionConvertorFactory_14_50.convertResource(resource), true); return; case "3.0": new org.hl7.fhir.dstu3.formats.XmlParser().compose(stream, VersionConvertorFactory_30_50.convertResource(resource), true); @@ -73,7 +73,7 @@ public static void saveXml(String version, Resource resource, OutputStream strea new org.hl7.fhir.r4.formats.XmlParser().compose(stream, VersionConvertorFactory_40_50.convertResource(resource), true); return; case "5.0": - new org.hl7.fhir.r5.formats.XmlParser().compose(stream, resource, true); + new org.hl7.fhir.r5.formats.XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(stream, resource); return; } throw new FHIRException("Unknown version " + version + " loading resource"); diff --git a/org.hl7.fhir.dstu2016may/src/main/java/org/hl7/fhir/dstu2016may/formats/XmlParser.java b/org.hl7.fhir.dstu2016may/src/main/java/org/hl7/fhir/dstu2016may/formats/XmlParser.java index da5fbec041..fb0eec49de 100644 --- a/org.hl7.fhir.dstu2016may/src/main/java/org/hl7/fhir/dstu2016may/formats/XmlParser.java +++ b/org.hl7.fhir.dstu2016may/src/main/java/org/hl7/fhir/dstu2016may/formats/XmlParser.java @@ -49,6 +49,14 @@ public XmlParser(boolean allowUnknownContent) { setAllowUnknownContent(allowUnknownContent); } + public XmlParser(boolean allowUnknownContent, boolean pretty) { + super(); + setAllowUnknownContent(allowUnknownContent); + if (pretty) { + setOutputStyle(OutputStyle.PRETTY); + } + } + protected boolean parseElementContent(int eventType, XmlPullParser xpp, Element res) throws XmlPullParserException, IOException, FHIRFormatError { if (eventType == XmlPullParser.START_TAG && xpp.getName().equals("extension")) From 6a3d7ffca8fc3c4184fd352651acd3b4ad88ff84 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Sun, 15 Dec 2024 07:23:33 +1100 Subject: [PATCH 13/15] more work on sample instance generation --- .../fhir/r5/context/SimpleWorkerContext.java | 18 +++ .../java/org/hl7/fhir/r5/model/Coding.java | 9 ++ .../hl7/fhir/r5/profilemodel/PEBuilder.java | 18 ++- .../fhir/r5/profilemodel/PEDefinition.java | 14 ++ .../profilemodel/TestInstanceGenerator.java | 125 +++++++++++++++--- .../tests/SnapShotGenerationXTests.java | 4 +- .../tests/TestInstanceGenerationTester.java | 4 +- 7 files changed, 171 insertions(+), 21 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java index 22d89b4e52..0d0ef5f3cb 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/context/SimpleWorkerContext.java @@ -217,6 +217,7 @@ public static class SimpleWorkerContextBuilder { @With private final org.hl7.fhir.r5.context.ILoggingService loggingService; + private boolean defaultExpParams; public SimpleWorkerContextBuilder() { cacheTerminologyClientErrors = false; @@ -247,6 +248,9 @@ private SimpleWorkerContext build(SimpleWorkerContext context) throws IOExceptio context.setUserAgent(userAgent); context.setLogger(loggingService); context.cacheResource(new org.hl7.fhir.r5.formats.JsonParser().parse(MagicResources.spdxCodesAsData())); + if (defaultExpParams) { + context.setExpansionParameters(makeExpProfile()); + } return context; } @@ -257,6 +261,12 @@ public SimpleWorkerContext fromPackage(NpmPackage pi) throws IOException, FHIREx context.loadFromPackage(pi, null); return build(context); } + + private Parameters makeExpProfile() { + Parameters ep = new Parameters(); + ep.addParameter("cache-id", UUID.randomUUID().toString().toLowerCase()); + return ep; + } public SimpleWorkerContext fromPackage(NpmPackage pi, IContextResourceLoader loader, boolean genSnapshots) throws IOException, FHIRException { SimpleWorkerContext context = getSimpleWorkerContextInstance(); @@ -265,6 +275,9 @@ public SimpleWorkerContext fromPackage(NpmPackage pi, IContextResourceLoader loa context.terminologyClientManager.setFactory(loader.txFactory()); context.loadFromPackage(pi, loader); context.finishLoading(genSnapshots); + if (defaultExpParams) { + context.setExpansionParameters(makeExpProfile()); + } return build(context); } @@ -321,6 +334,11 @@ public SimpleWorkerContext fromDefinitions(Map source, ICo public SimpleWorkerContext fromNothing() throws FHIRException, IOException { return build(); } + + public SimpleWorkerContextBuilder withDefaultParams() { + defaultExpParams = true; + return this; + } } private void loadDefinitionItem(String name, InputStream stream, IContextResourceLoader loader, ILoadFilter filter, PackageInformation pi) throws IOException, FHIRException { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Coding.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Coding.java index c04f37b642..16e92060a2 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Coding.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/model/Coding.java @@ -36,6 +36,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWIS import java.util.List; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.r5.model.Enumerations.*; +import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent; import org.hl7.fhir.instance.model.api.IBaseDatatypeElement; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.instance.model.api.ICompositeType; @@ -648,6 +649,14 @@ public Coding(String theSystem, String theVersion, String theCode, String theDis } // end addition + public Coding(ValueSetExpansionContainsComponent cc) { + super(); + setSystem(cc.getSystem()); + setVersion(cc.getVersion()); + setCode(cc.getCode()); + setDisplay(cc.getDisplay()); + } + public String getVersionedSystem() { return hasVersion() ? getSystem()+"|"+getVersion() : getSystem(); } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEBuilder.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEBuilder.java index f599fcf507..a25c7790a2 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEBuilder.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEBuilder.java @@ -57,6 +57,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWIS import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent; import org.hl7.fhir.r5.terminologies.expansion.ValueSetExpansionOutcome; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; +import org.hl7.fhir.utilities.DebugUtilities; import org.hl7.fhir.utilities.Utilities; /** @@ -155,7 +156,7 @@ public PEDefinition buildPEDefinition(StructureDefinition profile) { if (!profile.hasSnapshot()) { throw new DefinitionException("Profile '"+profile.getVersionedUrl()+"' does not have a snapshot"); } - return new PEDefinitionResource(this, profile, profile.getName()); + return new PEDefinitionResource(this, profile, null); } /** @@ -342,6 +343,10 @@ private StructureDefinition getProfile(String url, String version) { protected List listChildren(boolean allFixed, PEDefinition parent, StructureDefinition profileStructure, ElementDefinition definition, String url, String... omitList) { StructureDefinition profile = profileStructure; + boolean inExtension = profile.getDerivation() == TypeDerivationRule.CONSTRAINT && "Extension".equals(profile.getType()); + if (inExtension) { + DebugUtilities.breakpoint(); + } List list = pu.getChildList(profile, definition); if (definition.getType().size() == 1 || (!definition.getPath().contains(".")) || list.isEmpty()) { assert url == null || checkType(definition, url); @@ -359,7 +364,7 @@ protected List listChildren(boolean allFixed, PEDefinition parent, while (i < list.size()) { ElementDefinition defn = list.get(i); if (!defn.getMax().equals("0") && (allFixed || include(defn))) { - if (passElementPropsCheck(defn) && !Utilities.existsInList(defn.getName(), omitList)) { + if (passElementPropsCheck(defn, inExtension) && !Utilities.existsInList(defn.getName(), omitList)) { if (defn.getType().size() > 1) { // Debug/Utilities.breakpoint(); i++; @@ -434,7 +439,10 @@ protected PEDefinition makeChild(PEDefinition parent, StructureDefinition profil return pe; } - private boolean passElementPropsCheck(ElementDefinition bdefn) { + private boolean passElementPropsCheck(ElementDefinition bdefn, boolean inExtension) { + if (inExtension) { + return !Utilities.existsInList(bdefn.getBase().getPath(), "Element.id"); + } switch (elementProps) { case EXTENSION: return !Utilities.existsInList(bdefn.getBase().getPath(), "Element.id"); @@ -679,4 +687,8 @@ public List exec(Resource resource, Base data, String fhirpath) { public boolean isResource(String name) { return cu.isResource(name); } + + public ContextUtilities getContextUtilities() { + return cu; + } } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEDefinition.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEDefinition.java index 98f4fb3db3..4e7f0fde4e 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEDefinition.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEDefinition.java @@ -41,6 +41,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWIS import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent; import org.hl7.fhir.r5.model.StructureDefinition; +import org.hl7.fhir.r5.model.ValueSet; import org.hl7.fhir.r5.profilemodel.PEDefinition.PEDefinitionElementMode; import org.hl7.fhir.utilities.Utilities; @@ -393,6 +394,19 @@ public boolean isExtension() { return false; } + + public ValueSet valueSet() { + if (definition.getBinding().hasValueSet()) { + return builder.getContext().fetchResource(ValueSet.class, definition.getBinding().getValueSet()); + } + return null; + } + + + public PEBuilder getBuilder() { + return builder; + } + } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/TestInstanceGenerator.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/TestInstanceGenerator.java index 5976da16af..c986470201 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/TestInstanceGenerator.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/TestInstanceGenerator.java @@ -2,8 +2,13 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; import java.util.Map; import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.r5.context.IWorkerContext; @@ -12,8 +17,18 @@ import org.hl7.fhir.r5.elementmodel.Manager.FhirFormat; import org.hl7.fhir.r5.formats.IParser.OutputStyle; import org.hl7.fhir.r5.model.Base; +import org.hl7.fhir.r5.model.CodeableConcept; +import org.hl7.fhir.r5.model.Coding; +import org.hl7.fhir.r5.model.DateType; +import org.hl7.fhir.r5.model.DateTimeType; +import org.hl7.fhir.r5.model.Property; import org.hl7.fhir.r5.model.StructureDefinition; +import org.hl7.fhir.r5.model.ValueSet; +import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionComponent; +import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent; import org.hl7.fhir.r5.profilemodel.PEBuilder.PEElementPropertiesPolicy; +import org.hl7.fhir.r5.terminologies.expansion.ValueSetExpansionOutcome; +import org.hl7.fhir.utilities.Base64; import org.hl7.fhir.utilities.Utilities; public class TestInstanceGenerator { @@ -41,7 +56,7 @@ public byte[] generate(StructureDefinition profile, FhirFormat format) throws FH protected void populateByProfile(Element element, PEDefinition definition, int level) { if (definition.types().size() == 1) { for (PEDefinition pe : definition.directChildren(true)) { - if (!isIgnoredElement(pe.definition().getBase().getPath())) { + if (pe.max() > 0 && (!isIgnoredElement(pe.definition().getBase().getPath()) || pe.hasFixedValue())) { populateElement(element, pe, level); } } @@ -49,26 +64,35 @@ protected void populateByProfile(Element element, PEDefinition definition, int l } private boolean isIgnoredElement(String path) { - return Utilities.existsInList(path, "Identifier.assigner", "Resource.meta", "DomainResource.text"); + return Utilities.existsInList(path, "Identifier.assigner", "Resource.meta", "DomainResource.text", "Resource.implicitRules"); } public void populateElement(Element element, PEDefinition pe, int level) { System.out.println(pe.path()); - if (pe.hasFixedValue()) { - Element focus = element.addElement(pe.schemaName()); - Base fv = pe.definition().hasPattern() ? pe.definition().getPattern() : pe.definition().getFixed(); - if (fv.isPrimitive()) { - focus.setValue(fv.primitiveValue()); + if (!pe.isSlicer() && isNonAbstractType(pe)) { + if (pe.hasFixedValue()) { + Element focus = element.addElement(pe.schemaName()); + Base fv = pe.definition().hasPattern() ? pe.definition().getPattern() : pe.definition().getFixed(); + if (fv.isPrimitive()) { + focus.setValue(fv.primitiveValue()); + } else { + populateElementFromDataType(element, fv, null); + } } else { - populateElementFromDataType(element, fv, null); - } - } else if (!pe.isSlicer() && pe.max() == 1) { - for (int i = 0; i < pe.max(); i++) { makeChildElement(element, pe, level); } } } + private boolean isNonAbstractType(PEDefinition pe) { + for (PEType t : pe.types()) { + if (!pe.getBuilder().getContextUtilities().isAbstractType(t.getType())) { + return true; + } + } + return false; + } + public void makeChildElement(Element element, PEDefinition pe, int level) { Element b = null; if (pe.schemaName().endsWith("[x]")) { @@ -80,10 +104,56 @@ public void makeChildElement(Element element, PEDefinition pe, int level) { } if (b != null) { if (pe.definition.hasBinding()) { - + ValueSet vs = pe.valueSet(); + if (vs != null) { + ValueSetExpansionOutcome vse = context.expandVS(vs, true, false); + if (vse.isOk()) { + ValueSetExpansionContainsComponent cc = pickRandomConcept(vse.getValueset().getExpansion().getContains()); + if (b.isPrimitive()) { + b.setValue(vse.getValueset().getExpansion().getContainsFirstRep().getCode()); + } else if ("Coding".equals(b.fhirType())) { + populateElementFromDataType(b, new Coding(cc), null); + } else if ("CodeableConcept".equals(b.fhirType())) { + populateElementFromDataType(b, new CodeableConcept(new Coding(cc)), null); + } + } else { + System.out.println(" ValueSet Error: "+vse.getError()); + } + } else { + System.out.println(" Unknown ValueSet: "+pe.definition.getBinding().getValueSet()); + } } else if (b.isPrimitive()) { switch (b.fhirType()) { - case "id": b.setValue(UUID.randomUUID().toString().toLowerCase()); + case "id": + b.setValue(UUID.randomUUID().toString().toLowerCase()); + break; + case "string": + b.setValue("Some String value"); + break; + case "base64Binary" : + b.setValue(java.util.Base64.getMimeEncoder().encodeToString("Some Binary Value".getBytes(StandardCharsets.UTF_8))); + break; + case "boolean" : + b.setValue(ThreadLocalRandom.current().nextInt(0, 2) == 1 ? "true" : "false"); + break; + case "date" : + b.setValue(new DateType(new Date()).asStringValue()); + break; + case "dateTime": + b.setValue(new DateTimeType(new Date()).asStringValue()); + break; + case "positiveInt" : + b.setValue(Integer.toString(ThreadLocalRandom.current().nextInt(1, 1000))); + break; + case "usignedInt" : + b.setValue(Integer.toString(ThreadLocalRandom.current().nextInt(0, 1000))); + break; + case "url" : + b.setValue("http://some.url/path"); + break; + + default: + System.out.println("Unhandled type: "+b.fhirType()); } } else { populateByProfile(b, pe, level+1); @@ -91,8 +161,33 @@ public void makeChildElement(Element element, PEDefinition pe, int level) { } } - private void populateElementFromDataType(Element element, Base fv, Object object) { - // TODO Auto-generated method stub + private ValueSetExpansionContainsComponent pickRandomConcept(List list) { + ValueSetExpansionContainsComponent res = null; + while (res == null) { + int r = ThreadLocalRandom.current().nextInt(0, list.size()); + if (list.get(r).getAbstract()) { + if (list.get(r).hasContains()) { + res = pickRandomConcept(list.get(0).getContains()); + } + } else { + res = list.get(r); + } + } + return res; + } + + private void populateElementFromDataType(Element element, Base source, PEDefinition defn) { + for (Property prop : source.children()) { + for (Base b : prop.getValues()) { + Element child = element.makeElement(prop.getName()); + if (b.isPrimitive()) { + child.setValue(b.primitiveValue()); + } else { + populateElementFromDataType(child, b, null); + } + } + } + } diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/SnapShotGenerationXTests.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/SnapShotGenerationXTests.java index 8582f9752f..d892d6b798 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/SnapShotGenerationXTests.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/conversion/tests/SnapShotGenerationXTests.java @@ -572,9 +572,9 @@ private void testGen(boolean fail, TestDetails test) throws Exception { if (dst.exists()) dst.delete(); if (test.outputIsJson) { - XVersionLoader.saveJson(version, output, ManagedFileAccess.outStream(dst.getAbsolutePath())); + XVersionLoader.saveJson("5.0", output, ManagedFileAccess.outStream(dst.getAbsolutePath())); } else { - XVersionLoader.saveXml(version, output, ManagedFileAccess.outStream(dst.getAbsolutePath())); + XVersionLoader.saveXml("5.0", output, ManagedFileAccess.outStream(dst.getAbsolutePath())); } if (test.outputIsJson) { XVersionLoader.saveJson(version, test.expected, ManagedFileAccess.outStream(UtilitiesXTests.tempFile("snapshot", test.getId() + "-expected" + (test.outputIsJson ? ".json" : ".xml")))); diff --git a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/generation/tests/TestInstanceGenerationTester.java b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/generation/tests/TestInstanceGenerationTester.java index 5991f413db..8ba638f705 100644 --- a/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/generation/tests/TestInstanceGenerationTester.java +++ b/org.hl7.fhir.validation/src/test/java/org/hl7/fhir/generation/tests/TestInstanceGenerationTester.java @@ -18,7 +18,9 @@ public class TestInstanceGenerationTester { @Test public void testBasic() throws IOException { FilesystemPackageCacheManager pcm = new FilesystemPackageCacheManager.Builder().build(); - SimpleWorkerContext context = new SimpleWorkerContextBuilder().withAllowLoadingDuplicates(true).fromPackage(pcm.loadPackage("hl7.fhir.r4.core")); + SimpleWorkerContext context = new SimpleWorkerContextBuilder().withAllowLoadingDuplicates(true).withDefaultParams().fromPackage(pcm.loadPackage("hl7.fhir.r4.core")); + context.loadFromPackage(pcm.loadPackage("us.nlm.vsac#0.21.0"), new R4ToR5Loader(Utilities.strings("CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"), + new NullLoaderKnowledgeProviderR5(), context.getVersion())); context.loadFromPackage(pcm.loadPackage("hl7.fhir.us.core#6.0.0"), new R4ToR5Loader(Utilities.strings("CapabilityStatement", "StructureDefinition", "ValueSet", "CodeSystem", "SearchParameter", "OperationDefinition", "Questionnaire","ConceptMap","StructureMap", "NamingSystem"), new NullLoaderKnowledgeProviderR5(), context.getVersion())); From 313842ea4001bb2aa8de571afdad0cb505bdd02e Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Sun, 15 Dec 2024 09:31:47 +1100 Subject: [PATCH 14/15] compile fixes --- .../src/main/java/org/hl7/fhir/r5/profilemodel/PEBuilder.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEBuilder.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEBuilder.java index a25c7790a2..838cfc12b0 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEBuilder.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEBuilder.java @@ -57,7 +57,6 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWIS import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent; import org.hl7.fhir.r5.terminologies.expansion.ValueSetExpansionOutcome; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; -import org.hl7.fhir.utilities.DebugUtilities; import org.hl7.fhir.utilities.Utilities; /** @@ -344,9 +343,6 @@ private StructureDefinition getProfile(String url, String version) { protected List listChildren(boolean allFixed, PEDefinition parent, StructureDefinition profileStructure, ElementDefinition definition, String url, String... omitList) { StructureDefinition profile = profileStructure; boolean inExtension = profile.getDerivation() == TypeDerivationRule.CONSTRAINT && "Extension".equals(profile.getType()); - if (inExtension) { - DebugUtilities.breakpoint(); - } List list = pu.getChildList(profile, definition); if (definition.getType().size() == 1 || (!definition.getPath().contains(".")) || list.isEmpty()) { assert url == null || checkType(definition, url); From 3c20be779eff66be64f6987519593a7c9aea7859 Mon Sep 17 00:00:00 2001 From: hl7-devops Date: Sat, 14 Dec 2024 22:50:04 +0000 Subject: [PATCH 15/15] Updating i18n-coverage csv and png table ***NO_CI*** --- i18n-coverage-table.png | Bin 32027 -> 32028 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/i18n-coverage-table.png b/i18n-coverage-table.png index b426da41b2b6edad2222c28d47290aae8cc4005c..257811a1e85432516c5a9d5e5441d9cb32310827 100644 GIT binary patch delta 51 zcmbRJi*e2`#tABnRufef6%7sa40IGSN=gcft@QPC6H5wm@=J0ull1b7()FhlMHFpJ H+gbwv(2Ek_ delta 50 zcmbR9i*fcZ#tABnmJ?MK6)g3Pbrdp6N(zdt^!0NSOA2!GOL8)k^zw_+^^XNF_1l=f GwFUskloIv;