From 02bd9a5305a422a2e146039cc0a6c4746e3bb531 Mon Sep 17 00:00:00 2001 From: Lloyd McKenzie Date: Tue, 19 Nov 2024 10:51:03 -0700 Subject: [PATCH 1/2] Dropped the removeStatusExtensions subroutine. Most of the extensions it was trying to remove weren't allowed to exist in the provided context, and those that were were not appropriate to remove. (For example, it doesn't make sense to show that an element is deprecated in the differential, but not the snapshot.) Needed for HL7/fhir-ig-publisher#567 --- .../hl7/fhir/r4/conformance/ProfileUtilities.java | 11 ----------- .../fhir/r4b/conformance/ProfileUtilities.java | 15 --------------- .../conformance/profile/ProfilePathProcessor.java | 4 ---- .../r5/conformance/profile/ProfileUtilities.java | 12 +----------- 4 files changed, 1 insertion(+), 41 deletions(-) diff --git a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/conformance/ProfileUtilities.java b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/conformance/ProfileUtilities.java index d74b90a15..ee1dde3d4 100644 --- a/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/conformance/ProfileUtilities.java +++ b/org.hl7.fhir.r4/src/main/java/org/hl7/fhir/r4/conformance/ProfileUtilities.java @@ -797,7 +797,6 @@ public class ProfileUtilities extends TranslatingUtilities { if (diffMatches.get(0).hasSliceName()) outcome.setSliceName(diffMatches.get(0).getSliceName()); updateFromDefinition(outcome, diffMatches.get(0), profileName, trimDifferential, url, srcSD); - removeStatusExtensions(outcome); // if (outcome.getPath().endsWith("[x]") && outcome.getType().size() == 1 && !outcome.getType().get(0).getCode().equals("*") && !diffMatches.get(0).hasSlicing()) // if the base profile allows multiple types, but the profile only allows one, rename it // outcome.setPath(outcome.getPath().substring(0, outcome.getPath().length()-3)+Utilities.capitalize(outcome.getType().get(0).getCode())); outcome.setSlicing(null); @@ -1049,7 +1048,6 @@ public class ProfileUtilities extends TranslatingUtilities { // Else we'll treat it as the base definition of the slice. if (!diffMatches.get(0).hasSliceName()) { updateFromDefinition(outcome, diffMatches.get(0), profileName, trimDifferential, url, srcSD); - removeStatusExtensions(outcome); if (!outcome.hasContentReference() && !outcome.hasType()) { throw new DefinitionException("not done yet"); } @@ -1139,7 +1137,6 @@ public class ProfileUtilities extends TranslatingUtilities { // we don't want to // update the unsliced // description - removeStatusExtensions(outcome); } else if (!diffMatches.get(0).hasSliceName()) diffMatches.get(0).setUserData(GENERATED_IN_SNAPSHOT, outcome); // because of updateFromDefinition isn't // called @@ -1239,7 +1236,6 @@ public class ProfileUtilities extends TranslatingUtilities { throw new DefinitionException("Adding wrong path"); result.getElement().add(outcome); updateFromDefinition(outcome, diffItem, profileName, trimDifferential, url, srcSD); - removeStatusExtensions(outcome); // --- LM Added this diffCursor = differential.getElement().indexOf(diffItem) + 1; if (!outcome.getType().isEmpty() @@ -1332,13 +1328,6 @@ public class ProfileUtilities extends TranslatingUtilities { return res; } - private void removeStatusExtensions(ElementDefinition outcome) { - outcome.removeExtension(ToolingExtensions.EXT_FMM_LEVEL); - outcome.removeExtension(ToolingExtensions.EXT_STANDARDS_STATUS); - outcome.removeExtension(ToolingExtensions.EXT_NORMATIVE_VERSION); - outcome.removeExtension(ToolingExtensions.EXT_WORKGROUP); - } - private String descED(List list, int index) { return index >= 0 && index < list.size() ? list.get(index).present() : "X"; } diff --git a/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/conformance/ProfileUtilities.java b/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/conformance/ProfileUtilities.java index 007469b98..ddc49ff1b 100644 --- a/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/conformance/ProfileUtilities.java +++ b/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/conformance/ProfileUtilities.java @@ -1443,7 +1443,6 @@ public class ProfileUtilities extends TranslatingUtilities { } } updateFromDefinition(outcome, diffMatches.get(0), profileName, trimDifferential, url, srcSD); - removeStatusExtensions(outcome); // if (outcome.getPath().endsWith("[x]") && outcome.getType().size() == 1 && !outcome.getType().get(0).getCode().equals("*") && !diffMatches.get(0).hasSlicing()) // if the base profile allows multiple types, but the profile only allows one, rename it // outcome.setPath(outcome.getPath().substring(0, outcome.getPath().length()-3)+Utilities.capitalize(outcome.getType().get(0).getCode())); outcome.setSlicing(null); @@ -1781,7 +1780,6 @@ public class ProfileUtilities extends TranslatingUtilities { // Else we'll treat it as the base definition of the slice. if (!diffMatches.get(0).hasSliceName()) { updateFromDefinition(outcome, diffMatches.get(0), profileName, trimDifferential, url, srcSD); - removeStatusExtensions(outcome); if (!outcome.hasContentReference() && !outcome.hasType()) { throw new DefinitionException(context.formatMessage(I18nConstants.NOT_DONE_YET)); } @@ -2107,7 +2105,6 @@ public class ProfileUtilities extends TranslatingUtilities { // we don't want to // update the unsliced // description - removeStatusExtensions(outcome); } else if (!diffMatches.get(0).hasSliceName()) { diffMatches.get(0).setUserData(GENERATED_IN_SNAPSHOT, outcome); // because of updateFromDefinition isn't // called @@ -2241,7 +2238,6 @@ public class ProfileUtilities extends TranslatingUtilities { throw new DefinitionException(context.formatMessage(I18nConstants.ADDING_WRONG_PATH)); result.getElement().add(outcome); updateFromDefinition(outcome, diffItem, profileName, trimDifferential, url, srcSD); - removeStatusExtensions(outcome); // --- LM Added this diffCursor = differential.getElement().indexOf(diffItem) + 1; if (!outcome.getType().isEmpty() @@ -2521,17 +2517,6 @@ public class ProfileUtilities extends TranslatingUtilities { } } - private void removeStatusExtensions(ElementDefinition outcome) { - outcome.removeExtension(ToolingExtensions.EXT_FMM_LEVEL); - outcome.removeExtension(ToolingExtensions.EXT_FMM_SUPPORT); - outcome.removeExtension(ToolingExtensions.EXT_FMM_DERIVED); - outcome.removeExtension(ToolingExtensions.EXT_STANDARDS_STATUS); - outcome.removeExtension(ToolingExtensions.EXT_NORMATIVE_VERSION); - outcome.removeExtension(ToolingExtensions.EXT_WORKGROUP); - outcome.removeExtension(ToolingExtensions.EXT_FMM_SUPPORT); - outcome.removeExtension(ToolingExtensions.EXT_FMM_DERIVED); - } - private String descED(List list, int index) { return index >= 0 && index < list.size() ? list.get(index).present() : "X"; } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfilePathProcessor.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfilePathProcessor.java index a26d81569..8b03b1b2c 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfilePathProcessor.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfilePathProcessor.java @@ -324,7 +324,6 @@ public class ProfilePathProcessor { // differential - if the first one in the list has a name, we'll process it. Else we'll treat it as the base definition of the slice. if (!diffMatches.get(0).hasSliceName()) { profileUtilities.updateFromDefinition(outcome, diffMatches.get(0), getProfileName(), isTrimDifferential(), getUrl(),getSourceStructureDefinition(), getDerived(), diffPath(diffMatches.get(0)), mapHelper); - profileUtilities.removeStatusExtensions(outcome); if (!outcome.hasContentReference() && !outcome.hasType() && outcome.getPath().contains(".")) { throw new DefinitionException(profileUtilities.getContext().formatMessage(I18nConstants.NOT_DONE_YET)); } @@ -686,7 +685,6 @@ public class ProfilePathProcessor { } } profileUtilities.updateFromDefinition(outcome, diffMatches.get(0), getProfileName(), isTrimDifferential(), getUrl(), getSourceStructureDefinition(), getDerived(), diffPath(diffMatches.get(0)), mapHelper); - profileUtilities.removeStatusExtensions(outcome); // if (outcome.getPath().endsWith("[x]") && outcome.getType().size() == 1 && !outcome.getType().get(0).getCode().equals("*") && !diffMatches.get(0).hasSlicing()) // if the base profile allows multiple types, but the profile only allows one, rename it // outcome.setPath(outcome.getPath().substring(0, outcome.getPath().length()-3)+Utilities.capitalize(outcome.getType().get(0).getCode())); outcome.setSlicing(null); @@ -1039,7 +1037,6 @@ public class ProfilePathProcessor { if (diffMatches.get(0).hasSlicing() || !diffMatches.get(0).hasSliceName()) { profileUtilities.updateFromSlicing(outcome.getSlicing(), diffMatches.get(0).getSlicing()); profileUtilities.updateFromDefinition(outcome, diffMatches.get(0), getProfileName(), closed, getUrl(), getSourceStructureDefinition(), getDerived(), diffPath(diffMatches.get(0)), mapHelper); // if there's no slice, we don't want to update the unsliced description - profileUtilities.removeStatusExtensions(outcome); } else if (!diffMatches.get(0).hasSliceName()) { diffMatches.get(0).setUserData(profileUtilities.UD_GENERATED_IN_SNAPSHOT, outcome); // because of updateFromDefinition isn't called } else { @@ -1177,7 +1174,6 @@ public class ProfilePathProcessor { debugCheck(outcome); getResult().getElement().add(outcome); profileUtilities.updateFromDefinition(outcome, diffItem, getProfileName(), isTrimDifferential(), getUrl(), getSourceStructureDefinition(), getDerived(), diffPath(diffItem), mapHelper); - profileUtilities.removeStatusExtensions(outcome); // --- LM Added this cursors.diffCursor = getDifferential().getElement().indexOf(diffItem) + 1; if (!outcome.getType().isEmpty() && (/*outcome.getType().get(0).getCode().equals("Extension") || */getDifferential().getElement().size() > cursors.diffCursor) && outcome.getPath().contains(".")/* && isDataType(outcome.getType())*/) { // don't want to do this for the root, since that's base, and we're already processing it diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java index 4aa657d35..62e54f037 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/profile/ProfileUtilities.java @@ -1590,16 +1590,6 @@ public class ProfileUtilities { } } - protected void removeStatusExtensions(ElementDefinition outcome) { - outcome.removeExtension(ToolingExtensions.EXT_FMM_LEVEL); - outcome.removeExtension(ToolingExtensions.EXT_FMM_SUPPORT); - outcome.removeExtension(ToolingExtensions.EXT_STANDARDS_STATUS); - outcome.removeExtension(ToolingExtensions.EXT_NORMATIVE_VERSION); - outcome.removeExtension(ToolingExtensions.EXT_WORKGROUP); - outcome.removeExtension(ToolingExtensions.EXT_FMM_SUPPORT); - outcome.removeExtension(ToolingExtensions.EXT_FMM_DERIVED); - } - protected String descED(List list, int index) { return index >=0 && index < list.size() ? list.get(index).present() : "X"; } @@ -2499,7 +2489,7 @@ public class ProfileUtilities { if (derived.hasSliceName()) { base.setSliceName(derived.getSliceName()); } - + if (derived.hasShortElement()) { if (!Base.compareDeep(derived.getShortElement(), base.getShortElement(), false)) base.setShortElement(derived.getShortElement().copy()); From f0867ce8d00c5e8219b07ed955dcb43aa8a16a8d Mon Sep 17 00:00:00 2001 From: Lloyd McKenzie Date: Fri, 22 Nov 2024 08:37:50 -0700 Subject: [PATCH 2/2] We had been stripping standards status always. In practice, we only want to strip it when inheriting, and then only in certain circumstances. --- .../r4b/conformance/ProfileUtilities.java | 46 ++++++++++++------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/conformance/ProfileUtilities.java b/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/conformance/ProfileUtilities.java index ddc49ff1b..afd966a67 100644 --- a/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/conformance/ProfileUtilities.java +++ b/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/conformance/ProfileUtilities.java @@ -35,16 +35,7 @@ import java.io.FileReader; import java.io.IOException; import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import org.apache.commons.lang3.StringUtils; import org.hl7.fhir.exceptions.DefinitionException; @@ -331,6 +322,10 @@ public class ProfileUtilities extends TranslatingUtilities { private static final boolean DONT_DO_THIS = false; private final boolean ADD_REFERENCE_TO_TABLE = true; + private final List NONPROPAGATING_EXTENSIONS = new ArrayList<>(Arrays.asList(new String[] { + "http://hl7.org/fhir/StructureDefinition/structuredefinition-standards-status", + "http://hl7.org/fhir/StructureDefinition/structuredefinition-normative-version"})); + private boolean useTableForFixedValues = true; private boolean debug; @@ -1224,7 +1219,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (!currentBase.hasSlicing() || cpath.equals(typeSlicingPath)) { if (diffMatches.isEmpty()) { // the differential doesn't say anything about this item // so we just copy it in - ElementDefinition outcome = updateURLs(url, webUrl, currentBase.copy()); + ElementDefinition outcome = updateURLs(url, webUrl, stripNonPropagatingExtensions(currentBase.copy())); outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); updateFromBase(outcome, currentBase); updateConstraintSources(outcome, srcSD.getUrl()); @@ -1421,7 +1416,7 @@ public class ProfileUtilities extends TranslatingUtilities { } } if (template == null) - template = currentBase.copy(); + template = stripNonPropagatingExtensions(currentBase.copy()); else // some of what's in currentBase overrides template template = fillOutFromBase(template, currentBase); @@ -1763,7 +1758,7 @@ public class ProfileUtilities extends TranslatingUtilities { start++; } else { // we're just going to accept the differential slicing at face value - ElementDefinition outcome = updateURLs(url, webUrl, currentBase.copy()); + ElementDefinition outcome = updateURLs(url, webUrl, stripNonPropagatingExtensions(currentBase.copy())); outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); updateFromBase(outcome, currentBase); @@ -1849,7 +1844,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (diffMatches.isEmpty()) { if (hasInnerDiffMatches(differential, path, diffCursor, diffLimit, base.getElement(), true)) { // so we just copy it in - ElementDefinition outcome = updateURLs(url, webUrl, currentBase.copy()); + ElementDefinition outcome = updateURLs(url, webUrl, stripNonPropagatingExtensions(currentBase.copy())); outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); updateFromBase(outcome, currentBase); markDerived(outcome); @@ -2096,7 +2091,7 @@ public class ProfileUtilities extends TranslatingUtilities { I18nConstants.SLICING_RULES_ON_DIFFERENTIAL__DO_NOT_MATCH_THOSE_ON_BASE___RULE___, summarizeSlicing(dSlice), summarizeSlicing(bSlice), path, contextName)); } - ElementDefinition outcome = updateURLs(url, webUrl, currentBase.copy()); + ElementDefinition outcome = updateURLs(url, webUrl, stripNonPropagatingExtensions(currentBase.copy())); outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); updateFromBase(outcome, currentBase); if (diffMatches.get(0).hasSlicing() || !diffMatches.get(0).hasSliceName()) { @@ -2228,7 +2223,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (baseItem.getSliceName().equals(diffItem.getSliceName())) throw new DefinitionException( context.formatMessage(I18nConstants.NAMED_ITEMS_ARE_OUT_OF_ORDER_IN_THE_SLICE)); - outcome = updateURLs(url, webUrl, currentBase.copy()); + outcome = updateURLs(url, webUrl, stripNonPropagatingExtensions(currentBase.copy())); // outcome = updateURLs(url, diffItem.copy()); outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); updateFromBase(outcome, currentBase); @@ -2317,6 +2312,25 @@ public class ProfileUtilities extends TranslatingUtilities { return res; } + /* + * Some extensions we don't want to propagate. For example, the fact a resource is normative doesn't mean a profile on the resource is normative. + * Specific rules: + * - standards status of 'normative' never propagates + * - normative-since never propagates + * - standards status doesn't propagate at the root, but *does* propagate on individual elements + * - An element that's 'draft' in a resource still has to be draft in a profile + * - There's a slight funkiness here if you have a draft profile that's inheriting from a normative resource with certain STU elements, but the intention remains clear + */ + private ElementDefinition stripNonPropagatingExtensions(ElementDefinition e) { + if (e.hasExtension()) { + if (e.hasExtension(ToolingExtensions.EXT_NORMATIVE_VERSION)) + e.removeExtension(ToolingExtensions.EXT_NORMATIVE_VERSION); + if (!e.getPath().contains(".") && e.hasExtension(ToolingExtensions.EXT_STANDARDS_STATUS)) + e.removeExtension(ToolingExtensions.EXT_STANDARDS_STATUS); + } + return e; + } + private ElementDefinition getById(List list, String baseId) { for (ElementDefinition t : list) { if (baseId.equals(t.getId())) {