Merge pull request #1395 from hapifhir/2023-08-gg-rendering-comparisons

2023 08 gg rendering comparisons
This commit is contained in:
Grahame Grieve 2023-08-17 11:13:29 +10:00 committed by GitHub
commit 4766cb3e4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 276 additions and 157 deletions

View File

@ -135,21 +135,21 @@ public abstract class CanonicalResourceComparer extends ResourceComparer {
changedContentInterpretation = updateState(state, changedContentInterpretation); changedContentInterpretation = updateState(state, changedContentInterpretation);
} }
public void updatedMetadataState(boolean state, List<String> chMetadataFields) { public void updatedMetadataState(boolean changed, List<String> chMetadataFields) {
changedMetadata = updateState(state ? ChangeAnalysisState.Changed : ChangeAnalysisState.NotChanged, changedMetadata); changedMetadata = updateState(changed ? ChangeAnalysisState.Changed : ChangeAnalysisState.NotChanged, changedMetadata);
this.chMetadataFields = chMetadataFields; this.chMetadataFields = chMetadataFields;
} }
public void updateDefinitionsState(boolean state) { public void updateDefinitionsState(boolean changed) {
changedDefinitions = updateState(state ? ChangeAnalysisState.Changed : ChangeAnalysisState.NotChanged, changedDefinitions); changedDefinitions = updateState(changed ? ChangeAnalysisState.Changed : ChangeAnalysisState.NotChanged, changedDefinitions);
} }
public void updateContentState(boolean state) { public void updateContentState(boolean changed) {
changedContent = updateState(state ? ChangeAnalysisState.Changed : ChangeAnalysisState.NotChanged, changedContent); changedContent = updateState(changed ? ChangeAnalysisState.Changed : ChangeAnalysisState.NotChanged, changedContent);
} }
public void updateContentInterpretationState(boolean state) { public void updateContentInterpretationState(boolean changed) {
changedContentInterpretation = updateState(state ? ChangeAnalysisState.Changed : ChangeAnalysisState.NotChanged, changedContentInterpretation); changedContentInterpretation = updateState(changed ? ChangeAnalysisState.Changed : ChangeAnalysisState.NotChanged, changedContentInterpretation);
} }
public boolean anyUpdates() { public boolean anyUpdates() {
@ -236,59 +236,74 @@ public abstract class CanonicalResourceComparer extends ResourceComparer {
public boolean noUpdates() { public boolean noUpdates() {
return !(changedMetadata.noteable() || changedDefinitions.noteable() || !changedContent.noteable() || !changedContentInterpretation.noteable()); return !(changedMetadata.noteable() || changedDefinitions.noteable() || !changedContent.noteable() || !changedContentInterpretation.noteable());
} }
public boolean noChangeOtherThanMetadata(String[] metadataFields) {
if (changedDefinitions.noteable() || changedContent.noteable() || changedContentInterpretation.noteable()) {
return false;
}
if (!changedMetadata.noteable()) {
return true;
}
for (String s : this.chMetadataFields) {
if (!Utilities.existsInList(s, metadataFields)) {
return false;
}
}
return true;
}
} }
public CanonicalResourceComparer(ComparisonSession session) { public CanonicalResourceComparer(ComparisonSession session) {
super(session); super(session);
} }
protected boolean compareMetadata(CanonicalResource left, CanonicalResource right, Map<String, StructuralMatch<String>> comp, CanonicalResourceComparison<? extends CanonicalResource> res, List<String> changes) { protected boolean compareMetadata(CanonicalResource left, CanonicalResource right, Map<String, StructuralMatch<String>> comp, CanonicalResourceComparison<? extends CanonicalResource> res, List<String> changes, Base parent, String version) {
var changed = false; var changed = false;
if (comparePrimitives("url", left.getUrlElement(), right.getUrlElement(), comp, IssueSeverity.ERROR, res)) { if (comparePrimitivesWithTracking("url", left.getUrlElement(), right.getUrlElement(), comp, IssueSeverity.ERROR, res, parent, version)) {
changed = true; changed = true;
changes.add("url"); changes.add("url");
} }
if (session.getForVersion() == null) { if (session.getForVersion() == null) {
if (comparePrimitives("version", left.getVersionElement(), right.getVersionElement(), comp, IssueSeverity.ERROR, res)) { if (comparePrimitivesWithTracking("version", left.getVersionElement(), right.getVersionElement(), comp, IssueSeverity.ERROR, res, parent, version)) {
changed = true; changed = true;
changes.add("version"); changes.add("version");
} }
} }
if (comparePrimitives("name", left.getNameElement(), right.getNameElement(), comp, IssueSeverity.INFORMATION, res)) { if (comparePrimitivesWithTracking("name", left.getNameElement(), right.getNameElement(), comp, IssueSeverity.INFORMATION, res, parent, version)) {
changed = true; changed = true;
changes.add("name"); changes.add("name");
} }
if (comparePrimitives("title", left.getTitleElement(), right.getTitleElement(), comp, IssueSeverity.INFORMATION, res)) { if (comparePrimitivesWithTracking("title", left.getTitleElement(), right.getTitleElement(), comp, IssueSeverity.INFORMATION, res, parent, version)) {
changed = true; changed = true;
changes.add("title"); changes.add("title");
} }
if (comparePrimitives("status", left.getStatusElement(), right.getStatusElement(), comp, IssueSeverity.INFORMATION, res)) { if (comparePrimitivesWithTracking("status", left.getStatusElement(), right.getStatusElement(), comp, IssueSeverity.INFORMATION, res, parent, version)) {
changed = true; changed = true;
changes.add("status"); changes.add("status");
} }
if (comparePrimitives("experimental", left.getExperimentalElement(), right.getExperimentalElement(), comp, IssueSeverity.WARNING, res)) { if (comparePrimitivesWithTracking("experimental", left.getExperimentalElement(), right.getExperimentalElement(), comp, IssueSeverity.WARNING, res, parent, version)) {
changed = true; changed = true;
changes.add("experimental"); changes.add("experimental");
} }
if (session.getForVersion() == null) { if (session.getForVersion() == null) {
if (comparePrimitives("date", left.getDateElement(), right.getDateElement(), comp, IssueSeverity.INFORMATION, res)) { if (comparePrimitivesWithTracking("date", left.getDateElement(), right.getDateElement(), comp, IssueSeverity.INFORMATION, res, parent, version)) {
changed = true; changed = true;
changes.add("date"); changes.add("date");
} }
} }
if (comparePrimitives("publisher", left.getPublisherElement(), right.getPublisherElement(), comp, IssueSeverity.INFORMATION, res)) { if (comparePrimitivesWithTracking("publisher", left.getPublisherElement(), right.getPublisherElement(), comp, IssueSeverity.INFORMATION, res, parent, version)) {
changed = true; changed = true;
changes.add("publisher"); changes.add("publisher");
} }
if (comparePrimitives("description", left.getDescriptionElement(), right.getDescriptionElement(), comp, IssueSeverity.NULL, res)) { if (comparePrimitivesWithTracking("description", left.getDescriptionElement(), right.getDescriptionElement(), comp, IssueSeverity.NULL, res, parent, version)) {
changed = true; changed = true;
changes.add("description"); changes.add("description");
} }
if (comparePrimitives("purpose", left.getPurposeElement(), right.getPurposeElement(), comp, IssueSeverity.NULL, res)) { if (comparePrimitivesWithTracking("purpose", left.getPurposeElement(), right.getPurposeElement(), comp, IssueSeverity.NULL, res, parent, version)) {
changed = true; changed = true;
changes.add("purpose"); changes.add("purpose");
} }
if (comparePrimitives("copyright", left.getCopyrightElement(), right.getCopyrightElement(), comp, IssueSeverity.INFORMATION, res)) { if (comparePrimitivesWithTracking("copyright", left.getCopyrightElement(), right.getCopyrightElement(), comp, IssueSeverity.INFORMATION, res, parent, version)) {
changed = true; changed = true;
changes.add("copyright"); changes.add("copyright");
} }

View File

@ -10,7 +10,7 @@ import java.util.Map;
import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError; import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.comparison.ProfileComparer.ProfileComparison; import org.hl7.fhir.r5.comparison.StructureDefinitionComparer.ProfileComparison;
import org.hl7.fhir.r5.comparison.ResourceComparer.MessageCounts; import org.hl7.fhir.r5.comparison.ResourceComparer.MessageCounts;
import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.model.BackboneElement; import org.hl7.fhir.r5.model.BackboneElement;
@ -114,7 +114,7 @@ public class CapabilityStatementComparer extends CanonicalResourceComparer {
cs1.setStatus(left.getStatus()); cs1.setStatus(left.getStatus());
cs1.setDate(new Date()); cs1.setDate(new Date());
compareMetadata(left, right, res.getMetadata(), res, new ArrayList<>()); compareMetadata(left, right, res.getMetadata(), res, new ArrayList<>(), right, session.getForVersion());
comparePrimitives("kind", left.getKindElement(), right.getKindElement(), res.getMetadata(), IssueSeverity.ERROR, res); comparePrimitives("kind", left.getKindElement(), right.getKindElement(), res.getMetadata(), IssueSeverity.ERROR, res);
compareCanonicalList("instantiates", left.getInstantiates(), right.getInstantiates(), res.getMetadata(), IssueSeverity.ERROR, res, cs.getInstantiates(), cs1.getInstantiates()); compareCanonicalList("instantiates", left.getInstantiates(), right.getInstantiates(), res.getMetadata(), IssueSeverity.ERROR, res, cs.getInstantiates(), cs1.getInstantiates());
compareCanonicalList("imports", left.getImports(), right.getImports(), res.getMetadata(), IssueSeverity.ERROR, res, cs.getImports(), cs1.getImports()); compareCanonicalList("imports", left.getImports(), right.getImports(), res.getMetadata(), IssueSeverity.ERROR, res, cs.getImports(), cs1.getImports());

View File

@ -132,7 +132,7 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
List<String> chMetadata = new ArrayList<>(); List<String> chMetadata = new ArrayList<>();
boolean ch = compareMetadata(left, right, res.getMetadata(), res, chMetadata); boolean ch = compareMetadata(left, right, res.getMetadata(), res, chMetadata, right, session.getForVersion());
if (comparePrimitives("versionNeeded", left.getVersionNeededElement(), right.getVersionNeededElement(), res.getMetadata(), IssueSeverity.INFORMATION, res)) { if (comparePrimitives("versionNeeded", left.getVersionNeededElement(), right.getVersionNeededElement(), res.getMetadata(), IssueSeverity.INFORMATION, res)) {
ch = true; ch = true;
chMetadata.add("versionNeeded"); chMetadata.add("versionNeeded");

View File

@ -16,7 +16,7 @@ import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.PathEngineException; import org.hl7.fhir.exceptions.PathEngineException;
import org.hl7.fhir.r5.comparison.CapabilityStatementComparer.CapabilityStatementComparison; import org.hl7.fhir.r5.comparison.CapabilityStatementComparer.CapabilityStatementComparison;
import org.hl7.fhir.r5.comparison.CodeSystemComparer.CodeSystemComparison; import org.hl7.fhir.r5.comparison.CodeSystemComparer.CodeSystemComparison;
import org.hl7.fhir.r5.comparison.ProfileComparer.ProfileComparison; import org.hl7.fhir.r5.comparison.StructureDefinitionComparer.ProfileComparison;
import org.hl7.fhir.r5.comparison.ResourceComparer.PlaceHolderComparison; import org.hl7.fhir.r5.comparison.ResourceComparer.PlaceHolderComparison;
import org.hl7.fhir.r5.comparison.ResourceComparer.ResourceComparison; import org.hl7.fhir.r5.comparison.ResourceComparer.ResourceComparison;
import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison; import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison;
@ -213,7 +213,7 @@ public class ComparisonRenderer implements IEvaluationContext {
private void renderProfile(String id, ProfileComparison comp) throws IOException { private void renderProfile(String id, ProfileComparison comp) throws IOException {
String template = templates.get("Profile"); String template = templates.get("Profile");
Map<String, Base> vars = new HashMap<>(); Map<String, Base> vars = new HashMap<>();
ProfileComparer cs = new ProfileComparer(session, new ProfileUtilities(session.getContextLeft(), null, session.getPkpLeft()), StructureDefinitionComparer cs = new StructureDefinitionComparer(session, new ProfileUtilities(session.getContextLeft(), null, session.getPkpLeft()),
new ProfileUtilities(session.getContextRight(), null, session.getPkpRight())); new ProfileUtilities(session.getContextRight(), null, session.getPkpRight()));
vars.put("left", new StringType(comp.getLeft().present())); vars.put("left", new StringType(comp.getLeft().present()));
vars.put("right", new StringType(comp.getRight().present())); vars.put("right", new StringType(comp.getRight().present()));

View File

@ -10,7 +10,7 @@ import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError; import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.comparison.CapabilityStatementComparer.CapabilityStatementComparison; import org.hl7.fhir.r5.comparison.CapabilityStatementComparer.CapabilityStatementComparison;
import org.hl7.fhir.r5.comparison.CodeSystemComparer.CodeSystemComparison; import org.hl7.fhir.r5.comparison.CodeSystemComparer.CodeSystemComparison;
import org.hl7.fhir.r5.comparison.ProfileComparer.ProfileComparison; import org.hl7.fhir.r5.comparison.StructureDefinitionComparer.ProfileComparison;
import org.hl7.fhir.r5.comparison.ResourceComparer.ResourceComparison; import org.hl7.fhir.r5.comparison.ResourceComparer.ResourceComparison;
import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison; import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison;
import org.hl7.fhir.r5.conformance.profile.ProfileKnowledgeProvider; import org.hl7.fhir.r5.conformance.profile.ProfileKnowledgeProvider;
@ -94,7 +94,7 @@ public class ComparisonSession {
compares.put(key, csc); compares.put(key, csc);
return csc; return csc;
} else if (left instanceof StructureDefinition && right instanceof StructureDefinition) { } else if (left instanceof StructureDefinition && right instanceof StructureDefinition) {
ProfileComparer cs = new ProfileComparer(this, new ProfileUtilities(contextLeft, null, pkpLeft), new ProfileUtilities(contextRight, null, pkpRight)); StructureDefinitionComparer cs = new StructureDefinitionComparer(this, new ProfileUtilities(contextLeft, null, pkpLeft), new ProfileUtilities(contextRight, null, pkpRight));
ProfileComparison csc = cs.compare((StructureDefinition) left, (StructureDefinition) right); ProfileComparison csc = cs.compare((StructureDefinition) left, (StructureDefinition) right);
compares.put(key, csc); compares.put(key, csc);
return csc; return csc;

View File

@ -56,7 +56,7 @@ import org.hl7.fhir.utilities.xhtml.XhtmlNode;
import kotlin.NotImplementedError; import kotlin.NotImplementedError;
public class ProfileComparer extends CanonicalResourceComparer implements ProfileKnowledgeProvider { public class StructureDefinitionComparer extends CanonicalResourceComparer implements ProfileKnowledgeProvider {
public class ProfileComparison extends CanonicalResourceComparison<StructureDefinition> { public class ProfileComparison extends CanonicalResourceComparison<StructureDefinition> {
@ -113,7 +113,7 @@ public class ProfileComparer extends CanonicalResourceComparer implements Profil
private ProfileUtilities utilsLeft; private ProfileUtilities utilsLeft;
private ProfileUtilities utilsRight; private ProfileUtilities utilsRight;
public ProfileComparer(ComparisonSession session, ProfileUtilities utilsLeft, ProfileUtilities utilsRight) { public StructureDefinitionComparer(ComparisonSession session, ProfileUtilities utilsLeft, ProfileUtilities utilsRight) {
super(session); super(session);
this.utilsLeft = utilsLeft; this.utilsLeft = utilsLeft;
this.utilsRight = utilsRight; this.utilsRight = utilsRight;
@ -147,7 +147,7 @@ public class ProfileComparer extends CanonicalResourceComparer implements Profil
sd1.setDate(new Date()); sd1.setDate(new Date());
List<String> chMetadata = new ArrayList<>(); List<String> chMetadata = new ArrayList<>();
boolean ch = compareMetadata(left, right, res.getMetadata(), res, chMetadata); boolean ch = compareMetadata(left, right, res.getMetadata(), res, chMetadata, right, session.getForVersion());
if (comparePrimitives("fhirVersion", left.getFhirVersionElement(), right.getFhirVersionElement(), res.getMetadata(), IssueSeverity.WARNING, res)) { if (comparePrimitives("fhirVersion", left.getFhirVersionElement(), right.getFhirVersionElement(), res.getMetadata(), IssueSeverity.WARNING, res)) {
ch = true; ch = true;
chMetadata.add("fhirVersion"); chMetadata.add("fhirVersion");
@ -173,7 +173,7 @@ public class ProfileComparer extends CanonicalResourceComparer implements Profil
res.combined = sm; res.combined = sm;
ln = new DefinitionNavigator(session.getContextLeft(), left, true); ln = new DefinitionNavigator(session.getContextLeft(), left, true);
rn = new DefinitionNavigator(session.getContextRight(), right, true); rn = new DefinitionNavigator(session.getContextRight(), right, true);
ch = compareDiff(ln.path(), null, ln, rn, res) || ch; ch = compareDiff(ln.path(), null, ln, rn, res, right) || ch;
// we don't preserve the differences - we only want the annotations // we don't preserve the differences - we only want the annotations
} }
res.updateDefinitionsState(ch); res.updateDefinitionsState(ch);
@ -389,7 +389,7 @@ public class ProfileComparer extends CanonicalResourceComparer implements Profil
} }
private boolean compareDiff(String path, String sliceName, DefinitionNavigator left, DefinitionNavigator right, ProfileComparison res) throws DefinitionException, FHIRFormatError, IOException { private boolean compareDiff(String path, String sliceName, DefinitionNavigator left, DefinitionNavigator right, ProfileComparison res, Base parent) throws DefinitionException, FHIRFormatError, IOException {
assert(path != null); assert(path != null);
assert(left != null); assert(left != null);
assert(right != null); assert(right != null);
@ -403,6 +403,13 @@ public class ProfileComparer extends CanonicalResourceComparer implements Profil
// ruleEqual(comp, res, left.current().getIsModifierElement(), right.current().getIsModifierElement(), "isModifier", path); - this check belongs in the core // ruleEqual(comp, res, left.current().getIsModifierElement(), right.current().getIsModifierElement(), "isModifier", path); - this check belongs in the core
// ruleEqual(comp, res, left.current().getIsSummaryElement(), right.current().getIsSummaryElement(), "isSummary", path); - so does this // ruleEqual(comp, res, left.current().getIsSummaryElement(), right.current().getIsSummaryElement(), "isSummary", path); - so does this
if (left.current() == null && right.current() == null) {
// both are sparse at this point, do nothing
} else if (left.current() == null) {
VersionComparisonAnnotation.markAdded(right.current(), session.getForVersion());
} else if (right.current() == null) {
VersionComparisonAnnotation.markDeleted(right.parent(), session.getForVersion(), "element", left.current());
} else {
// descriptive properties from ElementDefinition - merge them: // descriptive properties from ElementDefinition - merge them:
comparePrimitivesWithTracking("label", left.current().getLabelElement(), right.current().getLabelElement(), null, IssueSeverity.INFORMATION, null, right.current(), session.getForVersion()); comparePrimitivesWithTracking("label", left.current().getLabelElement(), right.current().getLabelElement(), null, IssueSeverity.INFORMATION, null, right.current(), session.getForVersion());
def = comparePrimitivesWithTracking("short", left.current().getShortElement(), right.current().getShortElement(), null, IssueSeverity.INFORMATION, null, right.current(), session.getForVersion()) || def; def = comparePrimitivesWithTracking("short", left.current().getShortElement(), right.current().getShortElement(), null, IssueSeverity.INFORMATION, null, right.current(), session.getForVersion()) || def;
@ -412,9 +419,9 @@ public class ProfileComparer extends CanonicalResourceComparer implements Profil
def = comparePrimitivesWithTracking("mustSupport", left.current().getMustSupportElement(), right.current().getMustSupportElement(), null, IssueSeverity.INFORMATION, null, right.current(), session.getForVersion()) || def; def = comparePrimitivesWithTracking("mustSupport", left.current().getMustSupportElement(), right.current().getMustSupportElement(), null, IssueSeverity.INFORMATION, null, right.current(), session.getForVersion()) || def;
def = comparePrimitivesWithTracking("min", left.current().getMinElement(), right.current().getMinElement(), null, IssueSeverity.INFORMATION, null, right.current(), session.getForVersion()) || def; def = comparePrimitivesWithTracking("min", left.current().getMinElement(), right.current().getMinElement(), null, IssueSeverity.INFORMATION, null, right.current(), session.getForVersion()) || def;
def = comparePrimitivesWithTracking("max", left.current().getMaxElement(), right.current().getMaxElement(), null, IssueSeverity.INFORMATION, null, right.current(), session.getForVersion()) || def; def = comparePrimitivesWithTracking("max", left.current().getMaxElement(), right.current().getMaxElement(), null, IssueSeverity.INFORMATION, null, right.current(), session.getForVersion()) || def;
}
// add the children // add the children
def = compareDiffChildren(path, left, right, right.current(), res) || def; def = compareDiffChildren(path, left, right, right.current() == null ? parent : right.current(), res) || def;
// //
// // now process the slices // // now process the slices
// if (left.current().hasSlicing() || right.current().hasSlicing()) { // if (left.current().hasSlicing() || right.current().hasSlicing()) {
@ -491,7 +498,8 @@ public class ProfileComparer extends CanonicalResourceComparer implements Profil
VersionComparisonAnnotation.markDeleted(parent, session.getForVersion(), "element", l.current()); VersionComparisonAnnotation.markDeleted(parent, session.getForVersion(), "element", l.current());
res.updateContentState(true); res.updateContentState(true);
} else { } else {
def = compareDiff(l.path(), null, l, r, res) || def; matchR.add(r);
def = compareDiff(l.path(), null, l, r, res, parent) || def;
} }
} }
for (DefinitionNavigator r : rc) { for (DefinitionNavigator r : rc) {

View File

@ -125,7 +125,7 @@ public class ValueSetComparer extends CanonicalResourceComparer {
vs1.setDate(new Date()); vs1.setDate(new Date());
List<String> chMetadata = new ArrayList<>(); List<String> chMetadata = new ArrayList<>();
var ch = compareMetadata(left, right, res.getMetadata(), res, chMetadata); var ch = compareMetadata(left, right, res.getMetadata(), res, chMetadata, right, session.getForVersion());
var def = false; var def = false;
if (comparePrimitives("immutable", left.getImmutableElement(), right.getImmutableElement(), res.getMetadata(), IssueSeverity.WARNING, res)) { if (comparePrimitives("immutable", left.getImmutableElement(), right.getImmutableElement(), res.getMetadata(), IssueSeverity.WARNING, res)) {
ch = true; ch = true;

View File

@ -38,13 +38,15 @@ public class VersionComparisonAnnotation {
this.version = version; this.version = version;
} }
public static void annotate(Base base, String version, CanonicalResourceComparison<? extends CanonicalResource> comp) { public static void annotate(Base base, String version, CanonicalResourceComparison<? extends CanonicalResource> comp) {
if (version != null) { if (version != null) {
VersionComparisonAnnotation vca = new VersionComparisonAnnotation(comp.noUpdates() ? AnotationType.NoChange : AnotationType.Changed, version); VersionComparisonAnnotation vca = (VersionComparisonAnnotation) base.getUserData(USER_DATA_NAME);
vca.comp = comp; if (vca == null) {
vca = new VersionComparisonAnnotation(comp.noUpdates() ? AnotationType.NoChange : AnotationType.Changed, version);
base.setUserData(USER_DATA_NAME, vca); base.setUserData(USER_DATA_NAME, vca);
} }
vca.comp = comp;
}
} }
@ -248,7 +250,7 @@ public class VersionComparisonAnnotation {
} }
} }
public static void renderSummary(Base base, XhtmlNode x, String version) { public static void renderSummary(Base base, XhtmlNode x, String version, String... metadataFields) {
if (base.hasUserData(USER_DATA_NAME)) { if (base.hasUserData(USER_DATA_NAME)) {
VersionComparisonAnnotation self = (VersionComparisonAnnotation) base.getUserData(USER_DATA_NAME); VersionComparisonAnnotation self = (VersionComparisonAnnotation) base.getUserData(USER_DATA_NAME);
switch (self.type) { switch (self.type) {
@ -258,9 +260,14 @@ public class VersionComparisonAnnotation {
spanInner.tx(" Added"); spanInner.tx(" Added");
return; return;
case Changed: case Changed:
if (self.comp.noChangeOtherThanMetadata(metadataFields)) {
x.span("color: #eeeeee").tx("n/c");
return;
} else {
spanInner = x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This content has been added since "+version); spanInner = x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This content has been added since "+version);
spanInner.img("icon-change-edit.png", "icon"); spanInner.img("icon-change-edit.png", "icon");
spanInner.tx(" Changed"); spanInner.tx(" Changed");
}
return; return;
case Deleted: case Deleted:
spanInner = x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This content has been added since "+version); spanInner = x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This content has been added since "+version);
@ -277,4 +284,5 @@ public class VersionComparisonAnnotation {
} }
} }

View File

@ -913,7 +913,9 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
public ValidationResult validateCode(ValidationOptions options, String system, String version, String code, String display, ValueSet vs) { public ValidationResult validateCode(ValidationOptions options, String system, String version, String code, String display, ValueSet vs) {
assert options != null; assert options != null;
Coding c = new Coding(system, version, code, display); Coding c = new Coding(system, version, code, display);
return validateCode(options, "code", c, vs); ValidationResult ret = validateCode(options, "$", c, vs);
ret.trimPath("$");
return ret;
} }
@Override @Override

View File

@ -323,6 +323,22 @@ public interface IWorkerContext {
} }
public void trimPath(String prefix) {
if (issues != null) {
for (OperationOutcomeIssueComponent iss : issues) {
for (int i = iss.getLocation().size() -1; i >= 0; i--) {
var s = iss.getLocation().get(i).primitiveValue();
if (prefix.equals(s)) {
iss.getLocation().remove(i);
} else if (s.startsWith(prefix+".")) {
iss.getLocation().get(i).setValueAsString(s.substring(prefix.length()+1));
}
}
}
}
}
} }
public class CodingValidationRequest { public class CodingValidationRequest {

View File

@ -3094,7 +3094,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
List<String> anchors = makeAnchors(ec, anchorPrefix); List<String> anchors = makeAnchors(ec, anchorPrefix);
String title = ec.getId(); String title = ec.getId();
XhtmlNode tr = t.tr(); XhtmlNode tr = t.tr();
XhtmlNode sp = tr.td("structure").colspan(2).spanClss("self-link-parent"); XhtmlNode sp = VersionComparisonAnnotation.render(ec, tr.td("structure").colspan(2).spanClss("self-link-parent"));
for (String s : anchors) { for (String s : anchors) {
sp.an(s).tx(" "); sp.an(s).tx(" ");
} }
@ -3104,7 +3104,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
if (isProfiledExtension(ec)) { if (isProfiledExtension(ec)) {
StructureDefinition extDefn = context.getContext().fetchResource(StructureDefinition.class, ec.getType().get(0).getProfile().get(0).getValue()); StructureDefinition extDefn = context.getContext().fetchResource(StructureDefinition.class, ec.getType().get(0).getProfile().get(0).getValue());
if (extDefn == null) { if (extDefn == null) {
generateElementInner(t, sd, ec, 1, null, compareElement, null); generateElementInner(t, sd, ec, 1, null, compareElement, null, false);
} else { } else {
ElementDefinition valueDefn = getExtensionValueDefinition(extDefn); ElementDefinition valueDefn = getExtensionValueDefinition(extDefn);
ElementDefinition compareValueDefn = null; ElementDefinition compareValueDefn = null;
@ -3112,19 +3112,34 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
StructureDefinition compareExtDefn = context.getContext().fetchResource(StructureDefinition.class, compareElement.getType().get(0).getProfile().get(0).getValue()); StructureDefinition compareExtDefn = context.getContext().fetchResource(StructureDefinition.class, compareElement.getType().get(0).getProfile().get(0).getValue());
compareValueDefn = getExtensionValueDefinition(extDefn); compareValueDefn = getExtensionValueDefinition(extDefn);
} catch (Exception except) {} } catch (Exception except) {}
generateElementInner(t, sd, ec, valueDefn == null || valueDefn.prohibited() ? 2 : 3, valueDefn, compareElement, compareValueDefn); generateElementInner(t, sd, ec, valueDefn == null || valueDefn.prohibited() ? 2 : 3, valueDefn, compareElement, compareValueDefn, false);
// generateElementInner(b, extDefn, extDefn.getSnapshot().getElement().get(0), valueDefn == null ? 2 : 3, valueDefn); // generateElementInner(b, extDefn, extDefn.getSnapshot().getElement().get(0), valueDefn == null ? 2 : 3, valueDefn);
} }
} else { } else {
generateElementInner(t, sd, ec, mode, null, compareElement, null); generateElementInner(t, sd, ec, mode, null, compareElement, null, false);
if (ec.hasSlicing()) { if (ec.hasSlicing()) {
generateSlicing(t, sd, ec, ec.getSlicing(), compareElement, mode); generateSlicing(t, sd, ec, ec.getSlicing(), compareElement, mode, false);
} }
} }
} }
t.tx("\r\n"); t.tx("\r\n");
i++; i++;
} }
for (Base b : VersionComparisonAnnotation.getDeleted(sd, "element")) {
ElementDefinition ec = (ElementDefinition) b;
String title = ec.getId();
XhtmlNode tr = t.tr();
XhtmlNode sp = VersionComparisonAnnotation.render(ec, tr.td("structure").colspan(2).spanClss("self-link-parent"));
sp.span("color: grey", null).tx(Integer.toString(i++));
sp.b().tx(". "+title);
generateElementInner(t, sd, ec, mode, null, null, null, true);
if (ec.hasSlicing()) {
generateSlicing(t, sd, ec, ec.getSlicing(), null, mode, true);
}
t.tx("\r\n");
}
} }
public ElementDefinition getElementById(String url, String id) { public ElementDefinition getElementById(String url, String id) {
@ -3416,106 +3431,106 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
return "color:DarkGray;text-decoration:line-through"; return "color:DarkGray;text-decoration:line-through";
} }
private void generateElementInner(XhtmlNode tbl, StructureDefinition sd, ElementDefinition d, int mode, ElementDefinition value, ElementDefinition compare, ElementDefinition compareValue) throws FHIRException, IOException { private void generateElementInner(XhtmlNode tbl, StructureDefinition sd, ElementDefinition d, int mode, ElementDefinition value, ElementDefinition compare, ElementDefinition compareValue, boolean strikethrough) throws FHIRException, IOException {
boolean root = !d.getPath().contains("."); boolean root = !d.getPath().contains(".");
boolean slicedExtension = d.hasSliceName() && (d.getPath().endsWith(".extension") || d.getPath().endsWith(".modifierExtension")); boolean slicedExtension = d.hasSliceName() && (d.getPath().endsWith(".extension") || d.getPath().endsWith(".modifierExtension"));
// int slicedExtensionMode = (mode == GEN_MODE_KEY) && slicedExtension ? GEN_MODE_SNAP : mode; // see ProfileUtilities.checkExtensionDoco / Task 3970 // int slicedExtensionMode = (mode == GEN_MODE_KEY) && slicedExtension ? GEN_MODE_SNAP : mode; // see ProfileUtilities.checkExtensionDoco / Task 3970
if (d.hasSliceName()) { if (d.hasSliceName()) {
tableRow(tbl, "SliceName", "profiling.html#slicing").tx(d.getSliceName()); tableRow(tbl, "SliceName", "profiling.html#slicing", strikethrough).tx(d.getSliceName());
} }
tableRow(tbl, "Definition", null, compareMarkdown(sd.getName(), d.getDefinitionElement(), (compare==null) || slicedExtension ? null : compare.getDefinitionElement(), mode)); tableRow(tbl, "Definition", null, strikethrough, compareMarkdown(sd.getName(), d.getDefinitionElement(), (compare==null) || slicedExtension ? null : compare.getDefinitionElement(), mode));
tableRow(tbl, "Short", null, compareString(d.hasShort() ? d.getShort() : null, d.getShortElement(), null, "short", d, compare!= null && compare.hasShortElement() ? compare.getShort() : null, null, mode)); tableRow(tbl, "Short", null, strikethrough, compareString(d.hasShort() ? d.getShort() : null, d.getShortElement(), null, "short", d, compare!= null && compare.hasShortElement() ? compare.getShort() : null, null, mode));
tableRow(tbl, "Note", null, businessIdWarning(sd.getName(), tail(d.getPath()))); tableRow(tbl, "Note", null, strikethrough, businessIdWarning(sd.getName(), tail(d.getPath())));
tableRow(tbl, "Control", "conformance-rules.html#conformance", describeCardinality(d, compare, mode)); tableRow(tbl, "Control", "conformance-rules.html#conformance", strikethrough, describeCardinality(d, compare, mode));
tableRow(tbl, "Binding", "terminologies.html", describeBinding(sd, d, d.getPath(), compare, mode)); tableRow(tbl, "Binding", "terminologies.html", strikethrough, describeBinding(sd, d, d.getPath(), compare, mode));
if (d.hasContentReference()) { if (d.hasContentReference()) {
tableRow(tbl, "Type", null, "See " + d.getContentReference().substring(1)); tableRow(tbl, "Type", null, strikethrough, "See " + d.getContentReference().substring(1));
} else { } else {
tableRow(tbl, "Type", "datatypes.html", describeTypes(d.getType(), false, compare, mode, value, compareValue, sd)); tableRow(tbl, "Type", "datatypes.html", strikethrough, describeTypes(d.getType(), false, compare, mode, value, compareValue, sd));
} }
if (d.hasExtension(ToolingExtensions.EXT_DEF_TYPE)) { if (d.hasExtension(ToolingExtensions.EXT_DEF_TYPE)) {
tableRow(tbl, "Default Type", "datatypes.html", ToolingExtensions.readStringExtension(d, ToolingExtensions.EXT_DEF_TYPE)); tableRow(tbl, "Default Type", "datatypes.html", strikethrough, ToolingExtensions.readStringExtension(d, ToolingExtensions.EXT_DEF_TYPE));
} }
if (d.hasExtension(ToolingExtensions.EXT_TYPE_SPEC)) { if (d.hasExtension(ToolingExtensions.EXT_TYPE_SPEC)) {
tableRow(tbl, Utilities.pluralize("Type Specifier", d.getExtensionsByUrl(ToolingExtensions.EXT_TYPE_SPEC).size()), "datatypes.html", formatTypeSpecifiers(d)); tableRow(tbl, Utilities.pluralize("Type Specifier", d.getExtensionsByUrl(ToolingExtensions.EXT_TYPE_SPEC).size()), "datatypes.html", strikethrough, formatTypeSpecifiers(d));
} }
if (d.getPath().endsWith("[x]") && !d.prohibited()) { if (d.getPath().endsWith("[x]") && !d.prohibited()) {
tableRow(tbl, "[x] Note", null).ahWithText("See ", spec("formats.html#choice"), null, "Choice of Data Types", " for further information about how to use [x]"); tableRow(tbl, "[x] Note", null, strikethrough).ahWithText("See ", spec("formats.html#choice"), null, "Choice of Data Types", " for further information about how to use [x]");
} }
tableRow(tbl, "Is Modifier", "conformance-rules.html#ismodifier", displayBoolean(d.getIsModifier(), d.getIsModifierElement(), "isModifier", d, null, mode)); tableRow(tbl, "Is Modifier", "conformance-rules.html#ismodifier", strikethrough, displayBoolean(d.getIsModifier(), d.getIsModifierElement(), "isModifier", d, null, mode));
if (d.getMustHaveValue()) { if (d.getMustHaveValue()) {
tableRow(tbl, "Primitive Value", "elementdefinition.html#primitives", "This primitive type must have a value (the value must be present, and cannot be replaced by an extension)"); tableRow(tbl, "Primitive Value", "elementdefinition.html#primitives", strikethrough, "This primitive type must have a value (the value must be present, and cannot be replaced by an extension)");
} else if (d.hasValueAlternatives()) { } else if (d.hasValueAlternatives()) {
tableRow(tbl, "Primitive Value", "elementdefinition.html#primitives", renderCanonicalList(d.getValueAlternatives())); tableRow(tbl, "Primitive Value", "elementdefinition.html#primitives", strikethrough, renderCanonicalList(d.getValueAlternatives()));
} else if (hasPrimitiveTypes(d)) { } else if (hasPrimitiveTypes(d)) {
tableRow(tbl, "Primitive Value", "elementdefinition.html#primitives", "This primitive element may be present, or absent, or replaced by an extension"); tableRow(tbl, "Primitive Value", "elementdefinition.html#primitives", strikethrough, "This primitive element may be present, or absent, or replaced by an extension");
} }
if (ToolingExtensions.hasAllowedUnits(d)) { if (ToolingExtensions.hasAllowedUnits(d)) {
tableRow(tbl, "Allowed Units", "http://hl7.org/fhir/extensions/StructureDefinition-elementdefinition-allowedUnits.html", describeAllowedUnits(d)); tableRow(tbl, "Allowed Units", "http://hl7.org/fhir/extensions/StructureDefinition-elementdefinition-allowedUnits.html", strikethrough, describeAllowedUnits(d));
} }
tableRow(tbl, "Must Support", "conformance-rules.html#mustSupport", displayBoolean(d.getMustSupport(), d.getMustSupportElement(), "mustSupport", d, compare==null ? null : compare.getMustSupportElement(), mode)); tableRow(tbl, "Must Support", "conformance-rules.html#mustSupport", strikethrough, displayBoolean(d.getMustSupport(), d.getMustSupportElement(), "mustSupport", d, compare==null ? null : compare.getMustSupportElement(), mode));
if (d.getMustSupport()) { if (d.getMustSupport()) {
if (hasMustSupportTypes(d.getType())) { if (hasMustSupportTypes(d.getType())) {
tableRow(tbl, "Must Support Types", "datatypes.html", describeTypes(d.getType(), true, compare, mode, null, null, sd)); tableRow(tbl, "Must Support Types", "datatypes.html", strikethrough, describeTypes(d.getType(), true, compare, mode, null, null, sd));
} else if (hasChoices(d.getType())) { } else if (hasChoices(d.getType())) {
tableRow(tbl, "Must Support Types", "datatypes.html", "No must-support rules about the choice of types/profiles"); tableRow(tbl, "Must Support Types", "datatypes.html", strikethrough, "No must-support rules about the choice of types/profiles");
} }
} }
if (root && sd.getKind() == StructureDefinitionKind.LOGICAL) { if (root && sd.getKind() == StructureDefinitionKind.LOGICAL) {
tableRow(tbl, "Logical Model", null, ToolingExtensions.readBoolExtension(sd, ToolingExtensions.EXT_LOGICAL_TARGET) ? "This logical model can be the target of a reference" : "This logical model cannot be the target of a reference"); tableRow(tbl, "Logical Model", null, strikethrough, ToolingExtensions.readBoolExtension(sd, ToolingExtensions.EXT_LOGICAL_TARGET) ? "This logical model can be the target of a reference" : "This logical model cannot be the target of a reference");
} }
if (root && sd.hasExtension(ToolingExtensions.EXT_SD_IMPOSE_PROFILE)) { if (root && sd.hasExtension(ToolingExtensions.EXT_SD_IMPOSE_PROFILE)) {
tableRow(tbl, "Impose Profile", "http://hl7.org/fhir/extensions/StructureDefinition-structuredefinition-imposeProfile.html", tableRow(tbl, "Impose Profile", "http://hl7.org/fhir/extensions/StructureDefinition-structuredefinition-imposeProfile.html", strikethrough,
renderCanonicalListExt(sd.getExtensionsByUrl(ToolingExtensions.EXT_SD_IMPOSE_PROFILE))); renderCanonicalListExt(sd.getExtensionsByUrl(ToolingExtensions.EXT_SD_IMPOSE_PROFILE)));
} }
if (root && sd.hasExtension(ToolingExtensions.EXT_SD_COMPLIES_WITH_PROFILE)) { if (root && sd.hasExtension(ToolingExtensions.EXT_SD_COMPLIES_WITH_PROFILE)) {
tableRow(tbl, "Complies with Profile", "http://hl7.org/fhir/extensions/StructureDefinition-structuredefinition-compliesWithProfile.html", tableRow(tbl, "Complies with Profile", "http://hl7.org/fhir/extensions/StructureDefinition-structuredefinition-compliesWithProfile.html", strikethrough,
renderCanonicalListExt(sd.getExtensionsByUrl(ToolingExtensions.EXT_SD_COMPLIES_WITH_PROFILE))); renderCanonicalListExt(sd.getExtensionsByUrl(ToolingExtensions.EXT_SD_COMPLIES_WITH_PROFILE)));
} }
tableRow(tbl, "Obligations", null, describeObligations(d, root, sd)); tableRow(tbl, "Obligations", null, strikethrough, describeObligations(d, root, sd));
if (d.hasExtension(ToolingExtensions.EXT_EXTENSION_STYLE)) { if (d.hasExtension(ToolingExtensions.EXT_EXTENSION_STYLE)) {
String es = d.getExtensionString(ToolingExtensions.EXT_EXTENSION_STYLE); String es = d.getExtensionString(ToolingExtensions.EXT_EXTENSION_STYLE);
if ("named-elements".equals(es)) { if ("named-elements".equals(es)) {
if (context.hasLink(KnownLinkType.JSON_NAMES)) { if (context.hasLink(KnownLinkType.JSON_NAMES)) {
tableRow(tbl, "Extension Style", context.getLink(KnownLinkType.JSON_NAMES), "This element can be extended by named JSON elements"); tableRow(tbl, "Extension Style", context.getLink(KnownLinkType.JSON_NAMES), strikethrough, "This element can be extended by named JSON elements");
} else { } else {
tableRow(tbl, "Extension Style", ToolingExtensions.WEB_EXTENSION_STYLE, "This element can be extended by named JSON elements"); tableRow(tbl, "Extension Style", ToolingExtensions.WEB_EXTENSION_STYLE, strikethrough, "This element can be extended by named JSON elements");
} }
} }
} }
if (!d.getPath().contains(".") && ToolingExtensions.hasExtension(sd, ToolingExtensions.EXT_BINDING_STYLE)) { if (!d.getPath().contains(".") && ToolingExtensions.hasExtension(sd, ToolingExtensions.EXT_BINDING_STYLE)) {
tableRow(tbl, "Binding Style", ToolingExtensions.WEB_BINDING_STYLE, tableRow(tbl, "Binding Style", ToolingExtensions.WEB_BINDING_STYLE, strikethrough,
"This type can be bound to a value set using the " + ToolingExtensions.readStringExtension(sd, ToolingExtensions.EXT_BINDING_STYLE)+" binding style"); "This type can be bound to a value set using the " + ToolingExtensions.readStringExtension(sd, ToolingExtensions.EXT_BINDING_STYLE)+" binding style");
} }
if (d.hasExtension(ToolingExtensions.EXT_DATE_FORMAT)) { if (d.hasExtension(ToolingExtensions.EXT_DATE_FORMAT)) {
tableRow(tbl, "Date Format", null, ToolingExtensions.readStringExtension(d, ToolingExtensions.EXT_DATE_FORMAT)); tableRow(tbl, "Date Format", null, strikethrough, ToolingExtensions.readStringExtension(d, ToolingExtensions.EXT_DATE_FORMAT));
} }
String ide = ToolingExtensions.readStringExtension(d, ToolingExtensions.EXT_ID_EXPECTATION); String ide = ToolingExtensions.readStringExtension(d, ToolingExtensions.EXT_ID_EXPECTATION);
if (ide != null) { if (ide != null) {
if (ide.equals("optional")) { if (ide.equals("optional")) {
tableRow(tbl, "ID Expectation", null, "Id may or not be present (this is the default for elements but not resources)"); tableRow(tbl, "ID Expectation", null, strikethrough, "Id may or not be present (this is the default for elements but not resources)");
} else if (ide.equals("required")) { } else if (ide.equals("required")) {
tableRow(tbl, "ID Expectation", null, "Id is required to be present (this is the default for resources but not elements)"); tableRow(tbl, "ID Expectation", null, strikethrough, "Id is required to be present (this is the default for resources but not elements)");
} else if (ide.equals("required")) { } else if (ide.equals("required")) {
tableRow(tbl, "ID Expectation", null, "An ID is not allowed in this context"); tableRow(tbl, "ID Expectation", null, strikethrough, "An ID is not allowed in this context");
} }
} }
// tooling extensions for formats // tooling extensions for formats
if (ToolingExtensions.hasExtensions(d, ToolingExtensions.EXT_JSON_EMPTY, ToolingExtensions.EXT_JSON_PROP_KEY, ToolingExtensions.EXT_JSON_NULLABLE, if (ToolingExtensions.hasExtensions(d, ToolingExtensions.EXT_JSON_EMPTY, ToolingExtensions.EXT_JSON_PROP_KEY, ToolingExtensions.EXT_JSON_NULLABLE,
ToolingExtensions.EXT_JSON_NAME, ToolingExtensions.EXT_JSON_PRIMITIVE_CHOICE)) { ToolingExtensions.EXT_JSON_NAME, ToolingExtensions.EXT_JSON_PRIMITIVE_CHOICE)) {
tableRow(tbl, "JSON Format", null, describeJson(d)); tableRow(tbl, "JSON Format", null, strikethrough, describeJson(d));
} }
if (d.hasExtension(ToolingExtensions.EXT_XML_NAMESPACE) || sd.hasExtension(ToolingExtensions.EXT_XML_NAMESPACE) || d.hasExtension(ToolingExtensions.EXT_XML_NAME) || (root && sd.hasExtension(ToolingExtensions.EXT_XML_NO_ORDER)) || if (d.hasExtension(ToolingExtensions.EXT_XML_NAMESPACE) || sd.hasExtension(ToolingExtensions.EXT_XML_NAMESPACE) || d.hasExtension(ToolingExtensions.EXT_XML_NAME) || (root && sd.hasExtension(ToolingExtensions.EXT_XML_NO_ORDER)) ||
d.hasRepresentation()) { d.hasRepresentation()) {
tableRow(tbl, "XML Format", null, describeXml(sd, d, root)); tableRow(tbl, "XML Format", null, strikethrough, describeXml(sd, d, root));
} }
if (d.hasExtension(ToolingExtensions.EXT_IMPLIED_PREFIX)) { if (d.hasExtension(ToolingExtensions.EXT_IMPLIED_PREFIX)) {
tableRow(tbl, "String Format", null).codeWithText("When this element is read ", ToolingExtensions.readStringExtension(d, ToolingExtensions.EXT_IMPLIED_PREFIX), "is prefixed to the value before validation"); tableRow(tbl, "String Format", null, strikethrough).codeWithText("When this element is read ", ToolingExtensions.readStringExtension(d, ToolingExtensions.EXT_IMPLIED_PREFIX), "is prefixed to the value before validation");
} }
if (d.hasExtension(ToolingExtensions.EXT_STANDARDS_STATUS)) { if (d.hasExtension(ToolingExtensions.EXT_STANDARDS_STATUS)) {
@ -3525,29 +3540,29 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
if (sdb != null) { if (sdb != null) {
StandardsStatus base = determineStandardsStatus(sdb, (ElementDefinition) d.getUserData("derived.pointer")); StandardsStatus base = determineStandardsStatus(sdb, (ElementDefinition) d.getUserData("derived.pointer"));
if (base != null) { if (base != null) {
tableRow(tbl, "Standards Status", "versions.html#std-process", ss.toDisplay()+" (from "+base.toDisplay()+")"); tableRow(tbl, "Standards Status", "versions.html#std-process", strikethrough, ss.toDisplay()+" (from "+base.toDisplay()+")");
} else { } else {
tableRow(tbl, "Standards Status", "versions.html#std-process", ss.toDisplay()); tableRow(tbl, "Standards Status", "versions.html#std-process", strikethrough, ss.toDisplay());
} }
} else { } else {
tableRow(tbl, "Standards Status", "versions.html#std-process", ss.toDisplay()); tableRow(tbl, "Standards Status", "versions.html#std-process", strikethrough, ss.toDisplay());
} }
} }
if (mode != GEN_MODE_DIFF && d.hasIsSummary()) { if (mode != GEN_MODE_DIFF && d.hasIsSummary()) {
tableRow(tbl, "Summary", "search.html#summary", Boolean.toString(d.getIsSummary())); tableRow(tbl, "Summary", "search.html#summary", strikethrough, Boolean.toString(d.getIsSummary()));
} }
tableRow(tbl, "Requirements", null, compareMarkdown(sd.getName(), d.getRequirementsElement(), (compare==null) || slicedExtension ? null : compare.getRequirementsElement(), mode)); tableRow(tbl, "Requirements", null, strikethrough, compareMarkdown(sd.getName(), d.getRequirementsElement(), (compare==null) || slicedExtension ? null : compare.getRequirementsElement(), mode));
tableRow(tbl, "Alternate Names", null, compareSimpleTypeLists(d.getAlias(), ((compare==null) || slicedExtension ? null : compare.getAlias()), mode)); tableRow(tbl, "Alternate Names", null, strikethrough, compareSimpleTypeLists(d.getAlias(), ((compare==null) || slicedExtension ? null : compare.getAlias()), mode));
tableRow(tbl, "Comments", null, compareMarkdown(sd.getName(), d.getCommentElement(), (compare==null) || slicedExtension ? null : compare.getCommentElement(), mode)); tableRow(tbl, "Comments", null, strikethrough, compareMarkdown(sd.getName(), d.getCommentElement(), (compare==null) || slicedExtension ? null : compare.getCommentElement(), mode));
tableRow(tbl, "Max Length", null, compareString(d.hasMaxLength() ? toStr(d.getMaxLength()) : null, d.getMaxLengthElement(), null, "maxLength", d, compare!= null && compare.hasMaxLengthElement() ? toStr(compare.getMaxLength()) : null, null, mode)); tableRow(tbl, "Max Length", null, strikethrough, compareString(d.hasMaxLength() ? toStr(d.getMaxLength()) : null, d.getMaxLengthElement(), null, "maxLength", d, compare!= null && compare.hasMaxLengthElement() ? toStr(compare.getMaxLength()) : null, null, mode));
tableRow(tbl, "Default Value", null, encodeValue(d.getDefaultValue(), "defaultValue", d, compare==null ? null : compare.getDefaultValue(), mode)); tableRow(tbl, "Default Value", null, strikethrough, encodeValue(d.getDefaultValue(), "defaultValue", d, compare==null ? null : compare.getDefaultValue(), mode));
tableRow(tbl, "Meaning if Missing", null, d.getMeaningWhenMissing()); tableRow(tbl, "Meaning if Missing", null, strikethrough, d.getMeaningWhenMissing());
tableRow(tbl, "Fixed Value", null, encodeValue(d.getFixed(), "fixed", d, compare==null ? null : compare.getFixed(), mode)); tableRow(tbl, "Fixed Value", null, strikethrough, encodeValue(d.getFixed(), "fixed", d, compare==null ? null : compare.getFixed(), mode));
tableRow(tbl, "Pattern Value", null, encodeValue(d.getPattern(), "pattern", d, compare==null ? null : compare.getPattern(), mode)); tableRow(tbl, "Pattern Value", null, strikethrough, encodeValue(d.getPattern(), "pattern", d, compare==null ? null : compare.getPattern(), mode));
tableRow(tbl, "Example", null, encodeValues(d.getExample())); tableRow(tbl, "Example", null, strikethrough, encodeValues(d.getExample()));
tableRow(tbl, "Invariants", null, invariants(d.getConstraint(), compare==null ? null : compare.getConstraint(), mode)); tableRow(tbl, "Invariants", null, strikethrough, invariants(d.getConstraint(), compare==null ? null : compare.getConstraint(), mode));
tableRow(tbl, "LOINC Code", null, getMapping(sd, d, LOINC_MAPPING, compare, mode)); tableRow(tbl, "LOINC Code", null, strikethrough, getMapping(sd, d, LOINC_MAPPING, compare, mode));
tableRow(tbl, "SNOMED-CT Code", null, getMapping(sd, d, SNOMED_MAPPING, compare, mode)); tableRow(tbl, "SNOMED-CT Code", null, strikethrough, getMapping(sd, d, SNOMED_MAPPING, compare, mode));
} }
private String spec(String name) { private String spec(String name) {
@ -3772,7 +3787,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
return "unordered"; return "unordered";
} }
private void generateSlicing(XhtmlNode tbl, StructureDefinition profile, ElementDefinition ed, ElementDefinitionSlicingComponent slicing, ElementDefinition compare, int mode) throws IOException { private void generateSlicing(XhtmlNode tbl, StructureDefinition profile, ElementDefinition ed, ElementDefinitionSlicingComponent slicing, ElementDefinition compare, int mode, boolean strikethrough) throws IOException {
XhtmlNode x = new XhtmlNode(NodeType.Element, "div"); XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
x.codeWithText("This element introduces a set of slices on ", ed.getPath(), ". The slices are "); x.codeWithText("This element introduces a set of slices on ", ed.getPath(), ". The slices are ");
@ -3801,27 +3816,36 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
} else { } else {
x.tx(", and defines no discriminators to differentiate the slices"); x.tx(", and defines no discriminators to differentiate the slices");
} }
tableRow(tbl, "Slicing", "profiling.html#slicing", x); tableRow(tbl, "Slicing", "profiling.html#slicing", strikethrough, x);
} }
private XhtmlNode tableRow(XhtmlNode x, String name, String defRef) throws IOException { private XhtmlNode tableRow(XhtmlNode x, String name, String defRef, boolean strikethrough) throws IOException {
var tr = x.tr(); var tr = x.tr();
if (strikethrough) {
tr.style("text-decoration: line-through");
}
addFirstCell(name, defRef, tr); addFirstCell(name, defRef, tr);
return tr.td(); return tr.td();
} }
private void tableRow(XhtmlNode x, String name, String defRef, XhtmlNode possibleTd) throws IOException { private void tableRow(XhtmlNode x, String name, String defRef, boolean strikethrough, XhtmlNode possibleTd) throws IOException {
if (possibleTd != null && !possibleTd.isEmpty()) { if (possibleTd != null && !possibleTd.isEmpty()) {
var tr = x.tr(); var tr = x.tr();
if (strikethrough) {
tr.style("text-decoration: line-through");
}
addFirstCell(name, defRef, tr); addFirstCell(name, defRef, tr);
tr.td().copyAllContent(possibleTd); tr.td().copyAllContent(possibleTd);
} }
} }
private void tableRow(XhtmlNode x, String name, String defRef, String text) throws IOException { private void tableRow(XhtmlNode x, String name, String defRef, boolean strikethrough, String text) throws IOException {
if (!Utilities.noString(text)) { if (!Utilities.noString(text)) {
var tr = x.tr(); var tr = x.tr();
if (strikethrough) {
tr.style("text-decoration: line-through");
}
addFirstCell(name, defRef, tr); addFirstCell(name, defRef, tr);
tr.td().tx(text); tr.td().tx(text);
} }

View File

@ -447,17 +447,18 @@ public class ValueSetRenderer extends TerminologyRenderer {
private void generateVersionNotice(XhtmlNode x, ValueSetExpansionComponent expansion, Resource vs) { private void generateVersionNotice(XhtmlNode x, ValueSetExpansionComponent expansion, Resource vs) {
Multimap<String, String> versions = HashMultimap.create(); Multimap<String, String> versions = HashMultimap.create();
for (ValueSetExpansionParameterComponent p : expansion.getParameter()) { for (ValueSetExpansionParameterComponent p : expansion.getParameter()) {
if (p.getName().equals("version")) { if (p.getName().startsWith("used-") || p.getName().equals("version")) {
String name = p.getName().equals("version") ? "system" : p.getName().substring(5);
String[] parts = ((PrimitiveType) p.getValue()).asStringValue().split("\\|"); String[] parts = ((PrimitiveType) p.getValue()).asStringValue().split("\\|");
if (parts.length == 2 && !Utilities.noString(parts[0])) if (parts.length == 2 && !Utilities.noString(parts[0]))
versions.put(parts[0], parts[1]); versions.put(name+"|"+parts[0], parts[1]);
} }
} }
if (versions.size() > 0) { if (versions.size() > 0) {
XhtmlNode div = null; XhtmlNode div = null;
XhtmlNode ul = null; XhtmlNode ul = null;
boolean first = true; boolean first = true;
for (String s : versions.keySet()) { for (String s : Utilities.sorted(versions.keySet())) {
if (versions.size() == 1 && versions.get(s).size() == 1) { if (versions.size() == 1 && versions.get(s).size() == 1) {
for (String v : versions.get(s)) { // though there'll only be one for (String v : versions.get(s)) { // though there'll only be one
XhtmlNode p = x.para().style("border: black 1px dotted; background-color: #EEEEEE; padding: 8px; margin-bottom: 8px"); XhtmlNode p = x.para().style("border: black 1px dotted; background-color: #EEEEEE; padding: 8px; margin-bottom: 8px");
@ -480,6 +481,8 @@ public class ValueSetRenderer extends TerminologyRenderer {
} }
private void expRef(XhtmlNode x, String u, String v, Resource source) { private void expRef(XhtmlNode x, String u, String v, Resource source) {
String t = u.substring(0, u.indexOf("|"));
u = u.substring(u.indexOf("|")+1);
// TODO Auto-generated method stub // TODO Auto-generated method stub
if (u.equals("http://snomed.info/sct")) { if (u.equals("http://snomed.info/sct")) {
String[] parts = v.split("\\/"); String[] parts = v.split("\\/");
@ -504,23 +507,23 @@ public class ValueSetRenderer extends TerminologyRenderer {
CanonicalResource cr = (CanonicalResource) getContext().getWorker().fetchResource(Resource.class, u, source); CanonicalResource cr = (CanonicalResource) getContext().getWorker().fetchResource(Resource.class, u, source);
if (cr != null) { if (cr != null) {
if (cr.hasWebPath()) { if (cr.hasWebPath()) {
x.ah(cr.getWebPath()).tx(cr.present()+" (no version) ("+cr.fhirType()+")"); x.ah(cr.getWebPath()).tx(t+" "+cr.present()+" (no version) ("+cr.fhirType()+")");
} else { } else {
x.tx(describeSystem(u)+" (no version) ("+cr.fhirType()+")"); x.tx(t+" "+describeSystem(u)+" (no version) ("+cr.fhirType()+")");
} }
} else { } else {
x.tx(describeSystem(u)+" (no version)"); x.tx(t+" "+describeSystem(u)+" (no version)");
} }
} else { } else {
CanonicalResource cr = (CanonicalResource) getContext().getWorker().fetchResource(Resource.class, u+"|"+v, source); CanonicalResource cr = (CanonicalResource) getContext().getWorker().fetchResource(Resource.class, u+"|"+v, source);
if (cr != null) { if (cr != null) {
if (cr.hasWebPath()) { if (cr.hasWebPath()) {
x.ah(cr.getWebPath()).tx(cr.present()+" v"+v+" ("+cr.fhirType()+")"); x.ah(cr.getWebPath()).tx(t+" "+cr.present()+" v"+v+" ("+cr.fhirType()+")");
} else { } else {
x.tx(describeSystem(u)+" v"+v+" ("+cr.fhirType()+")"); x.tx(t+" "+describeSystem(u)+" v"+v+" ("+cr.fhirType()+")");
} }
} else { } else {
x.tx(describeSystem(u)+" version "+v); x.tx(t+" "+describeSystem(u)+" version "+v);
} }
} }
} }

View File

@ -663,8 +663,8 @@ public class ValueSetExpander extends ValueSetProcessBase {
} }
if (vs.hasVersion() || REPORT_VERSION_ANYWAY) { if (vs.hasVersion() || REPORT_VERSION_ANYWAY) {
UriType u = new UriType(vs.getUrl() + (vs.hasVersion() ? "|"+vs.getVersion() : "")); UriType u = new UriType(vs.getUrl() + (vs.hasVersion() ? "|"+vs.getVersion() : ""));
if (!existsInParams(exp.getParameter(), "version", u)) if (!existsInParams(exp.getParameter(), "used-valueset", u))
exp.getParameter().add(new ValueSetExpansionParameterComponent().setName("version").setValue(u)); exp.getParameter().add(new ValueSetExpansionParameterComponent().setName("used-valueset").setValue(u));
} }
for (Extension ex : vso.getValueset().getExpansion().getExtension()) { for (Extension ex : vso.getValueset().getExpansion().getExtension()) {
if (ex.getUrl().equals(ToolingExtensions.EXT_EXP_TOOCOSTLY)) { if (ex.getUrl().equals(ToolingExtensions.EXT_EXP_TOOCOSTLY)) {
@ -777,8 +777,8 @@ public class ValueSetExpander extends ValueSetProcessBase {
ValueSet vs = vso.getValueset(); ValueSet vs = vso.getValueset();
if (vs.hasVersion() || REPORT_VERSION_ANYWAY) { if (vs.hasVersion() || REPORT_VERSION_ANYWAY) {
UriType u = new UriType(vs.getUrl() + (vs.hasVersion() ? "|"+vs.getVersion() : "")); UriType u = new UriType(vs.getUrl() + (vs.hasVersion() ? "|"+vs.getVersion() : ""));
if (!existsInParams(exp.getParameter(), "version", u)) { if (!existsInParams(exp.getParameter(), "used-valueset", u)) {
exp.getParameter().add(new ValueSetExpansionParameterComponent().setName("version").setValue(u)); exp.getParameter().add(new ValueSetExpansionParameterComponent().setName("used-valueset").setValue(u));
} }
} }
for (ValueSetExpansionParameterComponent p : vso.getValueset().getExpansion().getParameter()) { for (ValueSetExpansionParameterComponent p : vso.getValueset().getExpansion().getParameter()) {
@ -812,13 +812,14 @@ public class ValueSetExpander extends ValueSetProcessBase {
throw failTSE("Code system " + inc.getSystem().toString() + " is incomplete"); throw failTSE("Code system " + inc.getSystem().toString() + " is incomplete");
if (cs.hasVersion() || REPORT_VERSION_ANYWAY) { if (cs.hasVersion() || REPORT_VERSION_ANYWAY) {
UriType u = new UriType(cs.getUrl() + (cs.hasVersion() ? "|"+cs.getVersion() : "")); UriType u = new UriType(cs.getUrl() + (cs.hasVersion() ? "|"+cs.getVersion() : ""));
if (!existsInParams(exp.getParameter(), "version", u)) if (!existsInParams(exp.getParameter(), "used-codesystem", u))
exp.getParameter().add(new ValueSetExpansionParameterComponent().setName("version").setValue(u)); exp.getParameter().add(new ValueSetExpansionParameterComponent().setName("used-codesystem").setValue(u));
if (cs.hasUserData("supplements.installed")) { if (cs.hasUserData("supplements.installed")) {
for (String s : cs.getUserString("supplements.installed").split("\\,")) { for (String s : cs.getUserString("supplements.installed").split("\\,")) {
u = new UriType(s); u = new UriType(s);
if (!existsInParams(exp.getParameter(), "version", u)) if (!existsInParams(exp.getParameter(), "used-supplement", u)) {
exp.getParameter().add(new ValueSetExpansionParameterComponent().setName("version").setValue(u)); exp.getParameter().add(new ValueSetExpansionParameterComponent().setName("used-supplement").setValue(u));
}
} }
} }
} }

View File

@ -198,15 +198,15 @@ public class ValueSetValidator extends ValueSetProcessBase {
if (context.isNoTerminologyServer()) { if (context.isNoTerminologyServer()) {
if (c.hasVersion()) { if (c.hasVersion()) {
String msg = context.formatMessage(I18nConstants.UNKNOWN_CODESYSTEM_VERSION, c.getSystem(), c.getVersion() , resolveCodeSystemVersions(c.getSystem()).toString()); String msg = context.formatMessage(I18nConstants.UNKNOWN_CODESYSTEM_VERSION, c.getSystem(), c.getVersion() , resolveCodeSystemVersions(c.getSystem()).toString());
if (valueSetDependsOn(c.getSystem(), c.getVersion())) { // if (valueSetDependsOn(c.getSystem(), c.getVersion())) {
unknownSystems.add(c.getSystem()+"|"+c.getVersion()); unknownSystems.add(c.getSystem()+"|"+c.getVersion());
} // }
res = new ValidationResult(IssueSeverity.ERROR, msg, makeIssue(IssueSeverity.ERROR, IssueType.NOTFOUND, path+".coding["+i+"].system", msg)).setUnknownSystems(unknownSystems); res = new ValidationResult(IssueSeverity.ERROR, msg, makeIssue(IssueSeverity.ERROR, IssueType.NOTFOUND, path+".coding["+i+"].system", msg)).setUnknownSystems(unknownSystems);
} else { } else {
String msg = context.formatMessage(I18nConstants.UNKNOWN_CODESYSTEM, c.getSystem(), c.getVersion()); String msg = context.formatMessage(I18nConstants.UNKNOWN_CODESYSTEM, c.getSystem(), c.getVersion());
if (valueSetDependsOn(c.getSystem(), null)) { // if (valueSetDependsOn(c.getSystem(), null)) {
unknownSystems.add(c.getSystem()); unknownSystems.add(c.getSystem());
} // }
res = new ValidationResult(IssueSeverity.ERROR, msg, makeIssue(IssueSeverity.ERROR, IssueType.NOTFOUND, path+".coding["+i+"].system", msg)).setUnknownSystems(unknownSystems); res = new ValidationResult(IssueSeverity.ERROR, msg, makeIssue(IssueSeverity.ERROR, IssueType.NOTFOUND, path+".coding["+i+"].system", msg)).setUnknownSystems(unknownSystems);
} }
} else { } else {
@ -247,7 +247,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
info.getIssues().addAll(makeIssue(IssueSeverity.WARNING, unknownSystems.isEmpty() ? IssueType.CODEINVALID : IssueType.NOTFOUND, path, msg)); info.getIssues().addAll(makeIssue(IssueSeverity.WARNING, unknownSystems.isEmpty() ? IssueType.CODEINVALID : IssueType.NOTFOUND, path, msg));
} else if (!result) { } else if (!result) {
msg = context.formatMessagePlural(code.getCoding().size(), I18nConstants.NONE_OF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_, valueset.getVersionedUrl(), b.toString()); msg = context.formatMessagePlural(code.getCoding().size(), I18nConstants.NONE_OF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_, valueset.getVersionedUrl(), b.toString());
info.getIssues().addAll(makeIssue(IssueSeverity.ERROR, unknownSystems.isEmpty() ? IssueType.CODEINVALID : IssueType.NOTFOUND, path, msg)); info.getIssues().addAll(makeIssue(IssueSeverity.ERROR, IssueType.CODEINVALID, path, msg));
} }
} }
if (info.hasErrors()) { if (info.hasErrors()) {
@ -492,6 +492,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
res.setDefinition(null); res.setDefinition(null);
res.setSystem(null); res.setSystem(null);
res.setDisplay(null); res.setDisplay(null);
res.setUnknownSystems(unknownSystems);
// } // }
} else if (warningMessage!=null) { } else if (warningMessage!=null) {
String msg = context.formatMessage(I18nConstants.CODE_FOUND_IN_EXPANSION_HOWEVER_, warningMessage); String msg = context.formatMessage(I18nConstants.CODE_FOUND_IN_EXPANSION_HOWEVER_, warningMessage);
@ -698,10 +699,10 @@ public class ValueSetValidator extends ValueSetProcessBase {
} }
if (b.count() == 0) { if (b.count() == 0) {
String msg = context.formatMessagePlural(options.getLanguages().size(), I18nConstants.NO_VALID_DISPLAY_FOUND, code.getSystem(), code.getCode(), code.getDisplay(), options.langSummary()); String msg = context.formatMessagePlural(options.getLanguages().size(), I18nConstants.NO_VALID_DISPLAY_FOUND, code.getSystem(), code.getCode(), code.getDisplay(), options.langSummary());
return new ValidationResult(IssueSeverity.WARNING, msg, code.getSystem(), cs.getVersion(), cc, getPreferredDisplay(cc, cs), makeIssue(IssueSeverity.WARNING, IssueType.CODEINVALID, path+".display", msg)); return new ValidationResult(IssueSeverity.WARNING, msg, code.getSystem(), cs.getVersion(), cc, getPreferredDisplay(cc, cs), makeIssue(IssueSeverity.WARNING, IssueType.INVALID, path+".display", msg));
} else { } else {
String msg = context.formatMessagePlural(b.count(), ws ? I18nConstants.DISPLAY_NAME_WS_FOR__SHOULD_BE_ONE_OF__INSTEAD_OF : I18nConstants.DISPLAY_NAME_FOR__SHOULD_BE_ONE_OF__INSTEAD_OF, code.getSystem(), code.getCode(), b.toString(), code.getDisplay(), options.langSummary()); String msg = context.formatMessagePlural(b.count(), ws ? I18nConstants.DISPLAY_NAME_WS_FOR__SHOULD_BE_ONE_OF__INSTEAD_OF : I18nConstants.DISPLAY_NAME_FOR__SHOULD_BE_ONE_OF__INSTEAD_OF, code.getSystem(), code.getCode(), b.toString(), code.getDisplay(), options.langSummary());
return new ValidationResult(dispWarningStatus(), msg, code.getSystem(), cs.getVersion(), cc, getPreferredDisplay(cc, cs), makeIssue(dispWarning(), IssueType.CODEINVALID, path+".display", msg)); return new ValidationResult(dispWarningStatus(), msg, code.getSystem(), cs.getVersion(), cc, getPreferredDisplay(cc, cs), makeIssue(dispWarning(), IssueType.INVALID, path+".display", msg));
} }
} }

View File

@ -38,6 +38,7 @@ import java.util.Map;
import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.r5.context.IWorkerContext; import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.ElementDefinition; import org.hl7.fhir.r5.model.ElementDefinition;
import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent; import org.hl7.fhir.r5.model.ElementDefinition.TypeRefComponent;
import org.hl7.fhir.r5.model.Resource; import org.hl7.fhir.r5.model.Resource;
@ -48,6 +49,7 @@ public class DefinitionNavigator {
private IWorkerContext context; private IWorkerContext context;
private StructureDefinition structure; private StructureDefinition structure;
private int index; private int index;
private boolean indexMatches; //
private List<DefinitionNavigator> children; private List<DefinitionNavigator> children;
private List<DefinitionNavigator> typeChildren; private List<DefinitionNavigator> typeChildren;
private List<DefinitionNavigator> slices; private List<DefinitionNavigator> slices;
@ -63,7 +65,13 @@ public class DefinitionNavigator {
this.structure = structure; this.structure = structure;
this.index = 0; this.index = 0;
this.diff = diff; this.diff = diff;
this.path = current().getPath(); if (diff) {
this.path = structure.getType(); // fragile?
indexMatches = this.path.equals(list().get(0).getPath());
} else {
indexMatches = true;
this.path = current().getPath(); // first element
}
names.add(nameTail()); names.add(nameTail());
} }
@ -73,6 +81,7 @@ public class DefinitionNavigator {
this.structure = structure; this.structure = structure;
this.diff = diff; this.diff = diff;
this.index = index; this.index = index;
this.indexMatches = true;
if (type == null) if (type == null)
for (String name : names) for (String name : names)
this.names.add(name+"."+nameTail()); this.names.add(name+"."+nameTail());
@ -108,7 +117,7 @@ public class DefinitionNavigator {
} }
} }
public ElementDefinition current() { public ElementDefinition current() {
return list().get(index); return indexMatches ? list().get(index) : null;
} }
public List<DefinitionNavigator> slices() throws DefinitionException { public List<DefinitionNavigator> slices() throws DefinitionException {
@ -127,13 +136,17 @@ public class DefinitionNavigator {
private void loadChildren() throws DefinitionException { private void loadChildren() throws DefinitionException {
children = new ArrayList<DefinitionNavigator>(); children = new ArrayList<DefinitionNavigator>();
String prefix = current().getPath()+"."; String prefix = path+".";
Map<String, DefinitionNavigator> nameMap = new HashMap<String, DefinitionNavigator>(); Map<String, DefinitionNavigator> nameMap = new HashMap<String, DefinitionNavigator>();
for (int i = index + 1; i < list().size(); i++) { DefinitionNavigator last = null;
for (int i = indexMatches ? index + 1 : index; i < list().size(); i++) {
String path = list().get(i).getPath(); String path = list().get(i).getPath();
if (path.startsWith(prefix) && !path.substring(prefix.length()).contains(".")) { if (path.startsWith(prefix)) {
if (!path.substring(prefix.length()).contains(".")) {
// immediate child
DefinitionNavigator dn = new DefinitionNavigator(context, structure, diff, i, this.path+"."+tail(path), names, null); DefinitionNavigator dn = new DefinitionNavigator(context, structure, diff, i, this.path+"."+tail(path), names, null);
last = dn;
if (nameMap.containsKey(path)) { if (nameMap.containsKey(path)) {
DefinitionNavigator master = nameMap.get(path); DefinitionNavigator master = nameMap.get(path);
@ -147,6 +160,12 @@ public class DefinitionNavigator {
nameMap.put(path, dn); nameMap.put(path, dn);
children.add(dn); children.add(dn);
} }
} else if (last == null || !path.startsWith(last.path)) {
// implied child
DefinitionNavigator dn = new DefinitionNavigator(context, structure, diff, i, this.path+"."+tail(path), names, null);
nameMap.put(path, dn);
children.add(dn);
}
} else if (path.length() < prefix.length()) } else if (path.length() < prefix.length())
break; break;
} }
@ -222,5 +241,10 @@ public class DefinitionNavigator {
return current().getId(); return current().getId();
} }
public Base parent() {
// TODO Auto-generated method stub
return null;
}
} }

View File

@ -966,6 +966,7 @@ public class I18nConstants {
public static final String MSG_DEPENDS_ON_EXTENSION = "MSG_DEPENDS_ON_EXTENSION"; public static final String MSG_DEPENDS_ON_EXTENSION = "MSG_DEPENDS_ON_EXTENSION";
public static final String MSG_DEPENDS_ON_PROFILE = "MSG_DEPENDS_ON_PROFILE"; public static final String MSG_DEPENDS_ON_PROFILE = "MSG_DEPENDS_ON_PROFILE";
public static final String VALIDATION_VAL_STATUS_INCONSISTENT = "VALIDATION_VAL_STATUS_INCONSISTENT"; public static final String VALIDATION_VAL_STATUS_INCONSISTENT = "VALIDATION_VAL_STATUS_INCONSISTENT";
public static final String VALIDATION_VAL_STATUS_INCONSISTENT_HINT = "VALIDATION_VAL_STATUS_INCONSISTENT_HINT";
public static final String CODESYSTEM_CS_COUNT_COMPLETE_WRONG = "CODESYSTEM_CS_COUNT_COMPLETE_WRONG"; public static final String CODESYSTEM_CS_COUNT_COMPLETE_WRONG = "CODESYSTEM_CS_COUNT_COMPLETE_WRONG";
public static final String CODESYSTEM_CS_COUNT_FRAGMENT_WRONG = "CODESYSTEM_CS_COUNT_FRAGMENT_WRONG"; public static final String CODESYSTEM_CS_COUNT_FRAGMENT_WRONG = "CODESYSTEM_CS_COUNT_FRAGMENT_WRONG";
public static final String CODESYSTEM_CS_COUNT_NOTPRESENT_ZERO = "CODESYSTEM_CS_COUNT_NOTPRESENT_ZERO"; public static final String CODESYSTEM_CS_COUNT_NOTPRESENT_ZERO = "CODESYSTEM_CS_COUNT_NOTPRESENT_ZERO";

View File

@ -1025,6 +1025,7 @@ MSG_DEPENDS_ON_DRAFT = The {0} {1} is a draft resource
MSG_DEPENDS_ON_EXTENSION = extension MSG_DEPENDS_ON_EXTENSION = extension
MSG_DEPENDS_ON_PROFILE = profile MSG_DEPENDS_ON_PROFILE = profile
VALIDATION_VAL_STATUS_INCONSISTENT = The resource status ''{0}'' and the standards status ''{1}'' are not consistent VALIDATION_VAL_STATUS_INCONSISTENT = The resource status ''{0}'' and the standards status ''{1}'' are not consistent
VALIDATION_VAL_STATUS_INCONSISTENT_HINT = The resource status ''{0}'' and the standards status ''{1}'' may not be consistent and should be reviewed
CODESYSTEM_CS_COUNT_COMPLETE_WRONG = The code system is complete, but the number of concepts ({0}) does not match the stated total number ({1}) CODESYSTEM_CS_COUNT_COMPLETE_WRONG = The code system is complete, but the number of concepts ({0}) does not match the stated total number ({1})
CODESYSTEM_CS_COUNT_FRAGMENT_WRONG = The code system is a fragment/example, but the number of concepts ({0}) exceeds or matches the stated total number ({1}) CODESYSTEM_CS_COUNT_FRAGMENT_WRONG = The code system is a fragment/example, but the number of concepts ({0}) exceeds or matches the stated total number ({1})
CODESYSTEM_CS_COUNT_NOTPRESENT_ZERO = The code system has no content, but the exceeds the stated total number is 0 concepts - check that this isn't a complete code system that has no concepts, or update/remove the stated count CODESYSTEM_CS_COUNT_NOTPRESENT_ZERO = The code system has no content, but the exceeds the stated total number is 0 concepts - check that this isn't a complete code system that has no concepts, or update/remove the stated count

View File

@ -5144,7 +5144,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
String standardsStatus = base != null && base.isPrimitive() ? base.primitiveValue() : null; String standardsStatus = base != null && base.isPrimitive() ? base.primitiveValue() : null;
String status = element.getNamedChildValue("status"); String status = element.getNamedChildValue("status");
if (!Utilities.noString(status) && !Utilities.noString(standardsStatus)) { if (!Utilities.noString(status) && !Utilities.noString(standardsStatus)) {
warning(errors, "2023-08-14", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), statusCodesConsistent(status, standardsStatus), I18nConstants.VALIDATION_VAL_STATUS_INCONSISTENT, status, standardsStatus); if (warning(errors, "2023-08-14", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), statusCodesConsistent(status, standardsStatus), I18nConstants.VALIDATION_VAL_STATUS_INCONSISTENT, status, standardsStatus)) {
hint(errors, "2023-08-14", IssueType.BUSINESSRULE, element.line(), element.col(), stack.getLiteralPath(), statusCodesDeeplyConsistent(status, standardsStatus), I18nConstants.VALIDATION_VAL_STATUS_INCONSISTENT_HINT, status, standardsStatus);
}
} }
} }
if (element.getType().equals(BUNDLE)) { if (element.getType().equals(BUNDLE)) {
@ -5191,6 +5193,19 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
return true; return true;
} }
private boolean statusCodesDeeplyConsistent(String status, String standardsStatus) {
switch (standardsStatus) {
case "draft": return Utilities.existsInList(status, "draft");
case "normative": return Utilities.existsInList(status, "active");
case "trial-use": return Utilities.existsInList(status, "active");
case "informative": return Utilities.existsInList(status, "draft", "active");
case "deprecated": return Utilities.existsInList(status, "retired");
case "withdrawn": return Utilities.existsInList(status, "retired");
case "external": return Utilities.existsInList(status, "draft", "active");
}
return true;
}
private ResourceValidationTracker getResourceTracker(Element element) { private ResourceValidationTracker getResourceTracker(Element element) {
ResourceValidationTracker res = resourceTracker.get(element); ResourceValidationTracker res = resourceTracker.get(element);
if (res == null) { if (res == null) {

View File

@ -28,8 +28,8 @@ import org.hl7.fhir.r5.comparison.CapabilityStatementComparer.CapabilityStatemen
import org.hl7.fhir.r5.comparison.CodeSystemComparer; import org.hl7.fhir.r5.comparison.CodeSystemComparer;
import org.hl7.fhir.r5.comparison.CodeSystemComparer.CodeSystemComparison; import org.hl7.fhir.r5.comparison.CodeSystemComparer.CodeSystemComparison;
import org.hl7.fhir.r5.comparison.ComparisonSession; import org.hl7.fhir.r5.comparison.ComparisonSession;
import org.hl7.fhir.r5.comparison.ProfileComparer; import org.hl7.fhir.r5.comparison.StructureDefinitionComparer;
import org.hl7.fhir.r5.comparison.ProfileComparer.ProfileComparison; import org.hl7.fhir.r5.comparison.StructureDefinitionComparer.ProfileComparison;
import org.hl7.fhir.r5.comparison.ValueSetComparer; import org.hl7.fhir.r5.comparison.ValueSetComparer;
import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison; import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
@ -188,7 +188,7 @@ public class ComparisonTests {
ProfileUtilities utils = new ProfileUtilities(context, null, null); ProfileUtilities utils = new ProfileUtilities(context, null, null);
genSnapshot(utils, (StructureDefinition) left); genSnapshot(utils, (StructureDefinition) left);
genSnapshot(utils, (StructureDefinition) right); genSnapshot(utils, (StructureDefinition) right);
ProfileComparer pc = new ProfileComparer(session, utils, utils); StructureDefinitionComparer pc = new StructureDefinitionComparer(session, utils, utils);
ProfileComparison csc = pc.compare((StructureDefinition) left, (StructureDefinition) right); ProfileComparison csc = pc.compare((StructureDefinition) left, (StructureDefinition) right);
new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path("[tmp]", "comparison", name + "-union.json")), csc.getUnion()); new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path("[tmp]", "comparison", name + "-union.json")), csc.getUnion());
new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path("[tmp]", "comparison", name + "-intersection.json")), csc.getIntersection()); new org.hl7.fhir.r5.formats.JsonParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path("[tmp]", "comparison", name + "-intersection.json")), csc.getIntersection());