Merge pull request #1391 from hapifhir/2023-08-gg-rendering-overhaul
2023 08 gg rendering overhaul
This commit is contained in:
commit
ebd92e4d5f
|
@ -523,7 +523,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
||||||
return doValidateCode(options, code, vs, false);
|
return doValidateCode(options, code, vs, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValidationResult doValidateCode(ValidationOptions options, Coding code, ValueSet vs, boolean implySystem) {
|
public ValidationResult doValidateCode(ValidationOptions options, Coding code, ValueSet vs, boolean inferSystem) {
|
||||||
CacheToken cacheToken = txCache != null ? txCache.generateValidationToken(options, code, vs) : null;
|
CacheToken cacheToken = txCache != null ? txCache.generateValidationToken(options, code, vs) : null;
|
||||||
ValidationResult res = null;
|
ValidationResult res = null;
|
||||||
if (txCache != null)
|
if (txCache != null)
|
||||||
|
@ -553,8 +553,8 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
||||||
try {
|
try {
|
||||||
Parameters pIn = new Parameters();
|
Parameters pIn = new Parameters();
|
||||||
pIn.addParameter().setName("coding").setValue(code);
|
pIn.addParameter().setName("coding").setValue(code);
|
||||||
if (implySystem)
|
if (inferSystem)
|
||||||
pIn.addParameter().setName("implySystem").setValue(new BooleanType(true));
|
pIn.addParameter().setName("inferSystem").setValue(new BooleanType(true));
|
||||||
if (options != null)
|
if (options != null)
|
||||||
setTerminologyOptions(options, pIn);
|
setTerminologyOptions(options, pIn);
|
||||||
res = validateOnServer(vs, pIn);
|
res = validateOnServer(vs, pIn);
|
||||||
|
|
|
@ -914,7 +914,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
||||||
Parameters pIn = new Parameters();
|
Parameters pIn = new Parameters();
|
||||||
pIn.addParameter().setName("coding").setValue(t.getCoding());
|
pIn.addParameter().setName("coding").setValue(t.getCoding());
|
||||||
if (options.isGuessSystem()) {
|
if (options.isGuessSystem()) {
|
||||||
pIn.addParameter().setName("implySystem").setValue(new BooleanType(true));
|
pIn.addParameter().setName("inferSystem").setValue(new BooleanType(true));
|
||||||
}
|
}
|
||||||
if (vs != null) {
|
if (vs != null) {
|
||||||
pIn.addParameter().setName("valueSet").setResource(vs);
|
pIn.addParameter().setName("valueSet").setResource(vs);
|
||||||
|
@ -1030,7 +1030,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
||||||
Parameters pIn = new Parameters();
|
Parameters pIn = new Parameters();
|
||||||
pIn.addParameter().setName("coding").setValue(code);
|
pIn.addParameter().setName("coding").setValue(code);
|
||||||
if (options.isGuessSystem()) {
|
if (options.isGuessSystem()) {
|
||||||
pIn.addParameter().setName("implySystem").setValue(new BooleanType(true));
|
pIn.addParameter().setName("inferSystem").setValue(new BooleanType(true));
|
||||||
}
|
}
|
||||||
setTerminologyOptions(options, pIn);
|
setTerminologyOptions(options, pIn);
|
||||||
res = validateOnServer(vs, pIn, options);
|
res = validateOnServer(vs, pIn, options);
|
||||||
|
|
|
@ -11,6 +11,7 @@ import java.util.Set;
|
||||||
import org.hl7.fhir.exceptions.FHIRException;
|
import org.hl7.fhir.exceptions.FHIRException;
|
||||||
import org.hl7.fhir.r5.comparison.CanonicalResourceComparer.ChangeAnalysisState;
|
import org.hl7.fhir.r5.comparison.CanonicalResourceComparer.ChangeAnalysisState;
|
||||||
import org.hl7.fhir.r5.comparison.ResourceComparer.MessageCounts;
|
import org.hl7.fhir.r5.comparison.ResourceComparer.MessageCounts;
|
||||||
|
import org.hl7.fhir.r5.model.Base;
|
||||||
import org.hl7.fhir.r5.model.CanonicalResource;
|
import org.hl7.fhir.r5.model.CanonicalResource;
|
||||||
import org.hl7.fhir.r5.model.CanonicalType;
|
import org.hl7.fhir.r5.model.CanonicalType;
|
||||||
import org.hl7.fhir.r5.model.CapabilityStatement;
|
import org.hl7.fhir.r5.model.CapabilityStatement;
|
||||||
|
@ -52,7 +53,8 @@ public abstract class CanonicalResourceComparer extends ResourceComparer {
|
||||||
private ChangeAnalysisState changedContent = ChangeAnalysisState.Unknown;
|
private ChangeAnalysisState changedContent = ChangeAnalysisState.Unknown;
|
||||||
private ChangeAnalysisState changedContentInterpretation = ChangeAnalysisState.Unknown;
|
private ChangeAnalysisState changedContentInterpretation = ChangeAnalysisState.Unknown;
|
||||||
|
|
||||||
protected Map<String, StructuralMatch<String>> metadata = new HashMap<>();
|
protected Map<String, StructuralMatch<String>> metadata = new HashMap<>();
|
||||||
|
private List<String> chMetadataFields;
|
||||||
|
|
||||||
public CanonicalResourceComparison(T left, T right) {
|
public CanonicalResourceComparison(T left, T right) {
|
||||||
super(left.getId(), right.getId());
|
super(left.getId(), right.getId());
|
||||||
|
@ -133,8 +135,9 @@ public abstract class CanonicalResourceComparer extends ResourceComparer {
|
||||||
changedContentInterpretation = updateState(state, changedContentInterpretation);
|
changedContentInterpretation = updateState(state, changedContentInterpretation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updatedMetadataState(boolean state) {
|
public void updatedMetadataState(boolean state, List<String> chMetadataFields) {
|
||||||
changedMetadata = updateState(state ? ChangeAnalysisState.Changed : ChangeAnalysisState.NotChanged, changedMetadata);
|
changedMetadata = updateState(state ? ChangeAnalysisState.Changed : ChangeAnalysisState.NotChanged, changedMetadata);
|
||||||
|
this.chMetadataFields = chMetadataFields;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateDefinitionsState(boolean state) {
|
public void updateDefinitionsState(boolean state) {
|
||||||
|
@ -149,6 +152,27 @@ public abstract class CanonicalResourceComparer extends ResourceComparer {
|
||||||
changedContentInterpretation = updateState(state ? ChangeAnalysisState.Changed : ChangeAnalysisState.NotChanged, changedContentInterpretation);
|
changedContentInterpretation = updateState(state ? ChangeAnalysisState.Changed : ChangeAnalysisState.NotChanged, changedContentInterpretation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean anyUpdates() {
|
||||||
|
return changedMetadata.noteable() || changedDefinitions.noteable() || changedContent.noteable() || changedContentInterpretation.noteable();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public ChangeAnalysisState getChangedMetadata() {
|
||||||
|
return changedMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChangeAnalysisState getChangedDefinitions() {
|
||||||
|
return changedDefinitions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChangeAnalysisState getChangedContent() {
|
||||||
|
return changedContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChangeAnalysisState getChangedContentInterpretation() {
|
||||||
|
return changedContentInterpretation;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String toTable() {
|
protected String toTable() {
|
||||||
String s = "";
|
String s = "";
|
||||||
|
@ -198,30 +222,76 @@ public abstract class CanonicalResourceComparer extends ResourceComparer {
|
||||||
}
|
}
|
||||||
return (bc.length() == 0 ? "" : "Error Checking: "+bc.toString()+"; ")+ "Changed: "+b.toString();
|
return (bc.length() == 0 ? "" : "Error Checking: "+bc.toString()+"; ")+ "Changed: "+b.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getMetadataFieldsAsText() {
|
||||||
|
CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder();
|
||||||
|
if (chMetadataFields != null) {
|
||||||
|
for (String s : chMetadataFields) {
|
||||||
|
b.append(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
protected boolean compareMetadata(CanonicalResource left, CanonicalResource right, Map<String, StructuralMatch<String>> comp, CanonicalResourceComparison<? extends CanonicalResource> res, List<String> changes) {
|
||||||
var changed = false;
|
var changed = false;
|
||||||
changed = comparePrimitives("url", left.getUrlElement(), right.getUrlElement(), comp, IssueSeverity.ERROR, res) || changed;
|
if (comparePrimitives("url", left.getUrlElement(), right.getUrlElement(), comp, IssueSeverity.ERROR, res)) {
|
||||||
if (session.getForVersion() == null) {
|
changed = true;
|
||||||
changed = comparePrimitives("version", left.getVersionElement(), right.getVersionElement(), comp, IssueSeverity.ERROR, res) || changed;
|
changes.add("url");
|
||||||
}
|
}
|
||||||
changed = comparePrimitives("name", left.getNameElement(), right.getNameElement(), comp, IssueSeverity.INFORMATION, res) || changed;
|
|
||||||
changed = comparePrimitives("title", left.getTitleElement(), right.getTitleElement(), comp, IssueSeverity.INFORMATION, res) || changed;
|
|
||||||
changed = comparePrimitives("status", left.getStatusElement(), right.getStatusElement(), comp, IssueSeverity.INFORMATION, res) || changed;
|
|
||||||
changed = comparePrimitives("experimental", left.getExperimentalElement(), right.getExperimentalElement(), comp, IssueSeverity.WARNING, res) || changed;
|
|
||||||
if (session.getForVersion() == null) {
|
if (session.getForVersion() == null) {
|
||||||
changed = comparePrimitives("date", left.getDateElement(), right.getDateElement(), comp, IssueSeverity.INFORMATION, res) || changed;
|
if (comparePrimitives("version", left.getVersionElement(), right.getVersionElement(), comp, IssueSeverity.ERROR, res)) {
|
||||||
|
changed = true;
|
||||||
|
changes.add("version");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (comparePrimitives("name", left.getNameElement(), right.getNameElement(), comp, IssueSeverity.INFORMATION, res)) {
|
||||||
|
changed = true;
|
||||||
|
changes.add("name");
|
||||||
|
}
|
||||||
|
if (comparePrimitives("title", left.getTitleElement(), right.getTitleElement(), comp, IssueSeverity.INFORMATION, res)) {
|
||||||
|
changed = true;
|
||||||
|
changes.add("title");
|
||||||
|
}
|
||||||
|
if (comparePrimitives("status", left.getStatusElement(), right.getStatusElement(), comp, IssueSeverity.INFORMATION, res)) {
|
||||||
|
changed = true;
|
||||||
|
changes.add("status");
|
||||||
|
}
|
||||||
|
if (comparePrimitives("experimental", left.getExperimentalElement(), right.getExperimentalElement(), comp, IssueSeverity.WARNING, res)) {
|
||||||
|
changed = true;
|
||||||
|
changes.add("experimental");
|
||||||
|
}
|
||||||
|
if (session.getForVersion() == null) {
|
||||||
|
if (comparePrimitives("date", left.getDateElement(), right.getDateElement(), comp, IssueSeverity.INFORMATION, res)) {
|
||||||
|
changed = true;
|
||||||
|
changes.add("date");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (comparePrimitives("publisher", left.getPublisherElement(), right.getPublisherElement(), comp, IssueSeverity.INFORMATION, res)) {
|
||||||
|
changed = true;
|
||||||
|
changes.add("publisher");
|
||||||
|
}
|
||||||
|
if (comparePrimitives("description", left.getDescriptionElement(), right.getDescriptionElement(), comp, IssueSeverity.NULL, res)) {
|
||||||
|
changed = true;
|
||||||
|
changes.add("description");
|
||||||
|
}
|
||||||
|
if (comparePrimitives("purpose", left.getPurposeElement(), right.getPurposeElement(), comp, IssueSeverity.NULL, res)) {
|
||||||
|
changed = true;
|
||||||
|
changes.add("purpose");
|
||||||
|
}
|
||||||
|
if (comparePrimitives("copyright", left.getCopyrightElement(), right.getCopyrightElement(), comp, IssueSeverity.INFORMATION, res)) {
|
||||||
|
changed = true;
|
||||||
|
changes.add("copyright");
|
||||||
|
}
|
||||||
|
if (compareCodeableConceptList("jurisdiction", left.getJurisdiction(), right.getJurisdiction(), comp, IssueSeverity.INFORMATION, res, res.getUnion().getJurisdiction(), res.getIntersection().getJurisdiction())) {
|
||||||
|
changed = true;
|
||||||
|
changes.add("jurisdiction");
|
||||||
}
|
}
|
||||||
changed = comparePrimitives("publisher", left.getPublisherElement(), right.getPublisherElement(), comp, IssueSeverity.INFORMATION, res) || changed;
|
|
||||||
changed = comparePrimitives("description", left.getDescriptionElement(), right.getDescriptionElement(), comp, IssueSeverity.NULL, res) || changed;
|
|
||||||
changed = comparePrimitives("purpose", left.getPurposeElement(), right.getPurposeElement(), comp, IssueSeverity.NULL, res) || changed;
|
|
||||||
changed = comparePrimitives("copyright", left.getCopyrightElement(), right.getCopyrightElement(), comp, IssueSeverity.INFORMATION, res) || changed;
|
|
||||||
changed = compareCodeableConceptList("jurisdiction", left.getJurisdiction(), right.getJurisdiction(), comp, IssueSeverity.INFORMATION, res, res.getUnion().getJurisdiction(), res.getIntersection().getJurisdiction()) || changed;
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,6 +444,41 @@ public abstract class CanonicalResourceComparer extends ResourceComparer {
|
||||||
return match.isDifferent();
|
return match.isDifferent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
protected boolean comparePrimitivesWithTracking(String name, PrimitiveType l, PrimitiveType r, Map<String, StructuralMatch<String>> comp, IssueSeverity level, CanonicalResourceComparison<? extends CanonicalResource> res, Base parent, String version) {
|
||||||
|
StructuralMatch<String> match = null;
|
||||||
|
if (l.isEmpty() && r.isEmpty()) {
|
||||||
|
match = new StructuralMatch<>(null, null, null);
|
||||||
|
} else if (l.isEmpty()) {
|
||||||
|
match = new StructuralMatch<>(null, r.primitiveValue(), vmI(IssueSeverity.INFORMATION, "Added the item '"+r.primitiveValue()+"'", fhirType()+"."+name));
|
||||||
|
VersionComparisonAnnotation.markAdded(r, version);
|
||||||
|
} else if (r.isEmpty()) {
|
||||||
|
match = new StructuralMatch<>(l.primitiveValue(), null, vmI(IssueSeverity.INFORMATION, "Removed the item '"+l.primitiveValue()+"'", fhirType()+"."+name));
|
||||||
|
VersionComparisonAnnotation.markDeleted(parent, version, name, l);
|
||||||
|
} else if (!l.hasValue() && !r.hasValue()) {
|
||||||
|
match = new StructuralMatch<>(null, null, vmI(IssueSeverity.INFORMATION, "No Value", fhirType()+"."+name));
|
||||||
|
} else if (!l.hasValue()) {
|
||||||
|
match = new StructuralMatch<>(null, r.primitiveValue(), vmI(IssueSeverity.INFORMATION, "No Value on Left", fhirType()+"."+name));
|
||||||
|
VersionComparisonAnnotation.markAdded(r, version);
|
||||||
|
} else if (!r.hasValue()) {
|
||||||
|
match = new StructuralMatch<>(l.primitiveValue(), null, vmI(IssueSeverity.INFORMATION, "No Value on Right", fhirType()+"."+name));
|
||||||
|
VersionComparisonAnnotation.markDeleted(parent, version, name, l);
|
||||||
|
} else if (l.getValue().equals(r.getValue())) {
|
||||||
|
match = new StructuralMatch<>(l.primitiveValue(), r.primitiveValue(), null);
|
||||||
|
} else {
|
||||||
|
VersionComparisonAnnotation.markChanged(r, version);
|
||||||
|
match = new StructuralMatch<>(l.primitiveValue(), r.primitiveValue(), vmI(level, "Values Differ", fhirType()+"."+name));
|
||||||
|
if (level != IssueSeverity.NULL && res != null) {
|
||||||
|
res.getMessages().add(new ValidationMessage(Source.ProfileComparer, IssueType.INFORMATIONAL, fhirType()+"."+name, "Values for "+name+" differ: '"+l.primitiveValue()+"' vs '"+r.primitiveValue()+"'", level));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (comp != null) {
|
||||||
|
comp.put(name, match);
|
||||||
|
}
|
||||||
|
return match.isDifferent();
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract String fhirType();
|
protected abstract String fhirType();
|
||||||
|
|
||||||
public XhtmlNode renderMetadata(CanonicalResourceComparison<? extends CanonicalResource> comparison, String id, String prefix) throws FHIRException, IOException {
|
public XhtmlNode renderMetadata(CanonicalResourceComparison<? extends CanonicalResource> comparison, String id, String prefix) throws FHIRException, IOException {
|
||||||
|
|
|
@ -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);
|
compareMetadata(left, right, res.getMetadata(), res, new ArrayList<>());
|
||||||
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());
|
||||||
|
|
|
@ -10,7 +10,9 @@ 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.r5.comparison.ResourceComparer.MessageCounts;
|
import org.hl7.fhir.r5.comparison.ResourceComparer.MessageCounts;
|
||||||
|
import org.hl7.fhir.r5.model.Base;
|
||||||
import org.hl7.fhir.r5.model.CodeSystem;
|
import org.hl7.fhir.r5.model.CodeSystem;
|
||||||
|
import org.hl7.fhir.r5.model.CodeSystem.CodeSystemFilterComponent;
|
||||||
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
|
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
|
||||||
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionDesignationComponent;
|
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionDesignationComponent;
|
||||||
import org.hl7.fhir.r5.model.CodeSystem.ConceptPropertyComponent;
|
import org.hl7.fhir.r5.model.CodeSystem.ConceptPropertyComponent;
|
||||||
|
@ -31,6 +33,8 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
|
||||||
|
|
||||||
public class CodeSystemComparison extends CanonicalResourceComparison<CodeSystem> {
|
public class CodeSystemComparison extends CanonicalResourceComparison<CodeSystem> {
|
||||||
|
|
||||||
|
private StructuralMatch<PropertyComponent> properties;
|
||||||
|
private StructuralMatch<CodeSystemFilterComponent> filters;
|
||||||
private StructuralMatch<ConceptDefinitionComponent> combined;
|
private StructuralMatch<ConceptDefinitionComponent> combined;
|
||||||
private Map<String, String> propMap = new HashMap<>(); // right to left; left retains it's name
|
private Map<String, String> propMap = new HashMap<>(); // right to left; left retains it's name
|
||||||
public CodeSystemComparison(CodeSystem left, CodeSystem right) {
|
public CodeSystemComparison(CodeSystem left, CodeSystem right) {
|
||||||
|
@ -46,6 +50,14 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
|
||||||
return combined;
|
return combined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public StructuralMatch<PropertyComponent> getProperties() {
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StructuralMatch<CodeSystemFilterComponent> getFilters() {
|
||||||
|
return filters;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String abbreviation() {
|
protected String abbreviation() {
|
||||||
return "cs";
|
return "cs";
|
||||||
|
@ -87,7 +99,6 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
|
||||||
if (right == null)
|
if (right == null)
|
||||||
throw new DefinitionException("No CodeSystem provided (right)");
|
throw new DefinitionException("No CodeSystem provided (right)");
|
||||||
|
|
||||||
|
|
||||||
CodeSystemComparison res = new CodeSystemComparison(left, right);
|
CodeSystemComparison res = new CodeSystemComparison(left, right);
|
||||||
session.identify(res);
|
session.identify(res);
|
||||||
CodeSystem cs = new CodeSystem();
|
CodeSystem cs = new CodeSystem();
|
||||||
|
@ -119,18 +130,29 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
|
||||||
cs1.setDate(new Date());
|
cs1.setDate(new Date());
|
||||||
cs1.getProperty().addAll(cs.getProperty());
|
cs1.getProperty().addAll(cs.getProperty());
|
||||||
|
|
||||||
boolean ch = compareMetadata(left, right, res.getMetadata(), res);
|
|
||||||
ch = comparePrimitives("versionNeeded", left.getVersionNeededElement(), right.getVersionNeededElement(), res.getMetadata(), IssueSeverity.INFORMATION, res) || ch;
|
List<String> chMetadata = new ArrayList<>();
|
||||||
ch = comparePrimitives("compositional", left.getCompositionalElement(), right.getCompositionalElement(), res.getMetadata(), IssueSeverity.WARNING, res) || ch;
|
boolean ch = compareMetadata(left, right, res.getMetadata(), res, chMetadata);
|
||||||
res.updatedMetadataState(ch);
|
if (comparePrimitives("versionNeeded", left.getVersionNeededElement(), right.getVersionNeededElement(), res.getMetadata(), IssueSeverity.INFORMATION, res)) {
|
||||||
|
ch = true;
|
||||||
|
chMetadata.add("versionNeeded");
|
||||||
|
}
|
||||||
|
if (comparePrimitives("compositional", left.getCompositionalElement(), right.getCompositionalElement(), res.getMetadata(), IssueSeverity.WARNING, res)) {
|
||||||
|
ch = true;
|
||||||
|
chMetadata.add("compositional");
|
||||||
|
}
|
||||||
|
res.updatedMetadataState(ch, chMetadata);
|
||||||
ch = false;
|
ch = false;
|
||||||
ch = comparePrimitives("caseSensitive", left.getCaseSensitiveElement(), right.getCaseSensitiveElement(), res.getMetadata(), IssueSeverity.ERROR, res) || ch;
|
ch = comparePrimitivesWithTracking("caseSensitive", left.getCaseSensitiveElement(), right.getCaseSensitiveElement(), res.getMetadata(), IssueSeverity.ERROR, res, right, session.getForVersion()) || ch;
|
||||||
ch = comparePrimitives("hierarchyMeaning", left.getHierarchyMeaningElement(), right.getHierarchyMeaningElement(), res.getMetadata(), IssueSeverity.ERROR, res) || ch;
|
ch = comparePrimitivesWithTracking("hierarchyMeaning", left.getHierarchyMeaningElement(), right.getHierarchyMeaningElement(), res.getMetadata(), IssueSeverity.ERROR, res, right, session.getForVersion()) || ch;
|
||||||
ch = comparePrimitives("content", left.getContentElement(), right.getContentElement(), res.getMetadata(), IssueSeverity.WARNING, res);
|
ch = comparePrimitivesWithTracking("content", left.getContentElement(), right.getContentElement(), res.getMetadata(), IssueSeverity.WARNING, res, right, session.getForVersion());
|
||||||
|
|
||||||
ch = compareConcepts(left.getConcept(), right.getConcept(), res.getCombined(), res.getUnion().getConcept(), res.getIntersection().getConcept(), res.getUnion(), res.getIntersection(), res, "CodeSystem.concept") || ch;
|
ch = compareProperties(left.getProperty(), right.getProperty(), res.getProperties(), res.getUnion().getProperty(), res.getIntersection().getProperty(), res.getUnion(), res.getIntersection(), res, "CodeSystem.property", right) || ch;
|
||||||
|
ch = compareFilters(left.getFilter(), right.getFilter(), res.getFilters(), res.getUnion().getFilter(), res.getIntersection().getFilter(), res.getUnion(), res.getIntersection(), res, "CodeSystem.filter", right) || ch;
|
||||||
|
ch = compareConcepts(left.getConcept(), right.getConcept(), res.getCombined(), res.getUnion().getConcept(), res.getIntersection().getConcept(), res.getUnion(), res.getIntersection(), res, "CodeSystem.concept", right) || ch;
|
||||||
res.updateDefinitionsState(ch);
|
res.updateDefinitionsState(ch);
|
||||||
|
|
||||||
|
VersionComparisonAnnotation.annotate(right, session.getForVersion(), res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,10 +183,81 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean compareProperties(List<PropertyComponent> left, List<PropertyComponent> right, StructuralMatch<PropertyComponent> combined,
|
||||||
|
List<PropertyComponent> union, List<PropertyComponent> intersection, CodeSystem csU, CodeSystem csI, CodeSystemComparison res, String path, Base parent) {
|
||||||
|
boolean def = false;
|
||||||
|
List<PropertyComponent> matchR = new ArrayList<>();
|
||||||
|
for (PropertyComponent l : left) {
|
||||||
|
PropertyComponent r = findInList(right, l);
|
||||||
|
if (r == null) {
|
||||||
|
union.add(l);
|
||||||
|
res.updateContentState(true);
|
||||||
|
combined.getChildren().add(new StructuralMatch<CodeSystem.PropertyComponent>(l, vmI(IssueSeverity.INFORMATION, "Removed this concept", path)));
|
||||||
|
VersionComparisonAnnotation.markDeleted(parent, session.getForVersion(), "concept", l);
|
||||||
|
} else {
|
||||||
|
matchR.add(r);
|
||||||
|
PropertyComponent cdM = merge(l, r, res);
|
||||||
|
PropertyComponent cdI = intersect(l, r, res);
|
||||||
|
union.add(cdM);
|
||||||
|
intersection.add(cdI);
|
||||||
|
StructuralMatch<PropertyComponent> sm = new StructuralMatch<CodeSystem.PropertyComponent>(l, r);
|
||||||
|
if (compare(sm.getMessages(), l, r, path+".where(code='"+l.getCode()+"')", res, parent)) {
|
||||||
|
def = true;
|
||||||
|
}
|
||||||
|
combined.getChildren().add(sm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (PropertyComponent r : right) {
|
||||||
|
if (!matchR.contains(r)) {
|
||||||
|
union.add(r);
|
||||||
|
res.updateContentState(true);
|
||||||
|
combined.getChildren().add(new StructuralMatch<CodeSystem.PropertyComponent>(vmI(IssueSeverity.INFORMATION, "Added this concept", path), r));
|
||||||
|
VersionComparisonAnnotation.markAdded(r, session.getForVersion());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private boolean compareFilters(List<CodeSystemFilterComponent> left, List<CodeSystemFilterComponent> right, StructuralMatch<CodeSystemFilterComponent> combined,
|
||||||
|
List<CodeSystemFilterComponent> union, List<CodeSystemFilterComponent> intersection, CodeSystem csU, CodeSystem csI, CodeSystemComparison res, String path, Base parent) {
|
||||||
|
boolean def = false;
|
||||||
|
List<CodeSystemFilterComponent> matchR = new ArrayList<>();
|
||||||
|
for (CodeSystemFilterComponent l : left) {
|
||||||
|
CodeSystemFilterComponent r = findInList(right, l);
|
||||||
|
if (r == null) {
|
||||||
|
union.add(l);
|
||||||
|
res.updateContentState(true);
|
||||||
|
combined.getChildren().add(new StructuralMatch<CodeSystem.CodeSystemFilterComponent>(l, vmI(IssueSeverity.INFORMATION, "Removed this concept", path)));
|
||||||
|
VersionComparisonAnnotation.markDeleted(parent, session.getForVersion(), "concept", l);
|
||||||
|
} else {
|
||||||
|
matchR.add(r);
|
||||||
|
CodeSystemFilterComponent cdM = merge(l, r, res);
|
||||||
|
CodeSystemFilterComponent cdI = intersect(l, r, res);
|
||||||
|
union.add(cdM);
|
||||||
|
intersection.add(cdI);
|
||||||
|
StructuralMatch<CodeSystemFilterComponent> sm = new StructuralMatch<CodeSystem.CodeSystemFilterComponent>(l, r);
|
||||||
|
if (compare(sm.getMessages(), l, r, path+".where(code='"+l.getCode()+"')", res, parent)) {
|
||||||
|
def = true;
|
||||||
|
}
|
||||||
|
combined.getChildren().add(sm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (CodeSystemFilterComponent r : right) {
|
||||||
|
if (!matchR.contains(r)) {
|
||||||
|
union.add(r);
|
||||||
|
res.updateContentState(true);
|
||||||
|
combined.getChildren().add(new StructuralMatch<CodeSystem.CodeSystemFilterComponent>(vmI(IssueSeverity.INFORMATION, "Added this concept", path), r));
|
||||||
|
VersionComparisonAnnotation.markAdded(r, session.getForVersion());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private boolean compareConcepts(List<ConceptDefinitionComponent> left, List<ConceptDefinitionComponent> right, StructuralMatch<ConceptDefinitionComponent> combined,
|
private boolean compareConcepts(List<ConceptDefinitionComponent> left, List<ConceptDefinitionComponent> right, StructuralMatch<ConceptDefinitionComponent> combined,
|
||||||
List<ConceptDefinitionComponent> union, List<ConceptDefinitionComponent> intersection, CodeSystem csU, CodeSystem csI, CodeSystemComparison res, String path) {
|
List<ConceptDefinitionComponent> union, List<ConceptDefinitionComponent> intersection, CodeSystem csU, CodeSystem csI, CodeSystemComparison res, String path, Base parent) {
|
||||||
boolean result = false;
|
boolean def = false;
|
||||||
List<ConceptDefinitionComponent> matchR = new ArrayList<>();
|
List<ConceptDefinitionComponent> matchR = new ArrayList<>();
|
||||||
for (ConceptDefinitionComponent l : left) {
|
for (ConceptDefinitionComponent l : left) {
|
||||||
ConceptDefinitionComponent r = findInList(right, l);
|
ConceptDefinitionComponent r = findInList(right, l);
|
||||||
|
@ -172,6 +265,7 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
|
||||||
union.add(l);
|
union.add(l);
|
||||||
res.updateContentState(true);
|
res.updateContentState(true);
|
||||||
combined.getChildren().add(new StructuralMatch<CodeSystem.ConceptDefinitionComponent>(l, vmI(IssueSeverity.INFORMATION, "Removed this concept", path)));
|
combined.getChildren().add(new StructuralMatch<CodeSystem.ConceptDefinitionComponent>(l, vmI(IssueSeverity.INFORMATION, "Removed this concept", path)));
|
||||||
|
VersionComparisonAnnotation.markDeleted(parent, session.getForVersion(), "concept", l);
|
||||||
} else {
|
} else {
|
||||||
matchR.add(r);
|
matchR.add(r);
|
||||||
ConceptDefinitionComponent cdM = merge(l, r, csU.getProperty(), res);
|
ConceptDefinitionComponent cdM = merge(l, r, csU.getProperty(), res);
|
||||||
|
@ -179,12 +273,12 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
|
||||||
union.add(cdM);
|
union.add(cdM);
|
||||||
intersection.add(cdI);
|
intersection.add(cdI);
|
||||||
StructuralMatch<ConceptDefinitionComponent> sm = new StructuralMatch<CodeSystem.ConceptDefinitionComponent>(l, r);
|
StructuralMatch<ConceptDefinitionComponent> sm = new StructuralMatch<CodeSystem.ConceptDefinitionComponent>(l, r);
|
||||||
if (compare(sm.getMessages(), l, r, path+".where(code='"+l.getCode()+"')", res)) {
|
if (compare(sm.getMessages(), l, r, path+".where(code='"+l.getCode()+"')", res, parent)) {
|
||||||
result = true;
|
def = true;
|
||||||
}
|
}
|
||||||
combined.getChildren().add(sm);
|
combined.getChildren().add(sm);
|
||||||
if (compareConcepts(l.getConcept(), r.getConcept(), sm, cdM.getConcept(), cdI.getConcept(), csU, csI, res, path+".where(code='"+l.getCode()+"').concept")) {
|
if (compareConcepts(l.getConcept(), r.getConcept(), sm, cdM.getConcept(), cdI.getConcept(), csU, csI, res, path+".where(code='"+l.getCode()+"').concept", r)) {
|
||||||
result = true;
|
def = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -192,11 +286,22 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
|
||||||
if (!matchR.contains(r)) {
|
if (!matchR.contains(r)) {
|
||||||
union.add(r);
|
union.add(r);
|
||||||
res.updateContentState(true);
|
res.updateContentState(true);
|
||||||
combined.getChildren().add(new StructuralMatch<CodeSystem.ConceptDefinitionComponent>(vmI(IssueSeverity.INFORMATION, "Added this concept", path), r));
|
combined.getChildren().add(new StructuralMatch<CodeSystem.ConceptDefinitionComponent>(vmI(IssueSeverity.INFORMATION, "Added this concept", path), r));
|
||||||
|
VersionComparisonAnnotation.markAdded(r, session.getForVersion());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return def;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private CodeSystemFilterComponent findInList(List<CodeSystemFilterComponent> list, CodeSystemFilterComponent item) {
|
||||||
|
for (CodeSystemFilterComponent t : list) {
|
||||||
|
if (t.getCode().equals(item.getCode())) {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private ConceptDefinitionComponent findInList(List<ConceptDefinitionComponent> list, ConceptDefinitionComponent item) {
|
private ConceptDefinitionComponent findInList(List<ConceptDefinitionComponent> list, ConceptDefinitionComponent item) {
|
||||||
for (ConceptDefinitionComponent t : list) {
|
for (ConceptDefinitionComponent t : list) {
|
||||||
|
@ -207,27 +312,58 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean compare(List<ValidationMessage> msgs, ConceptDefinitionComponent l, ConceptDefinitionComponent r, String path, CodeSystemComparison res) {
|
|
||||||
|
private PropertyComponent findInList(List<PropertyComponent> list, PropertyComponent item) {
|
||||||
|
for (PropertyComponent t : list) {
|
||||||
|
if (t.getCode().equals(item.getCode())) {
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean compare(List<ValidationMessage> msgs, ConceptDefinitionComponent l, ConceptDefinitionComponent r, String path, CodeSystemComparison res, Base parent) {
|
||||||
boolean result = false;
|
boolean result = false;
|
||||||
result = compareStrings(path, msgs, l.getDisplay(), r.getDisplay(), "display", IssueSeverity.WARNING, res) || result;
|
result = compareStrings(path, msgs, l.getDisplay(), r.getDisplay(), "display", IssueSeverity.WARNING, res, parent, l.getDisplayElement(), r.getDisplayElement()) || result;
|
||||||
result = compareStrings(path, msgs, l.getDefinition(), r.getDefinition(), "definition", IssueSeverity.INFORMATION, res) || result;
|
result = compareStrings(path, msgs, l.getDefinition(), r.getDefinition(), "definition", IssueSeverity.INFORMATION, res, parent, l.getDefinitionElement(), r.getDefinitionElement()) || result;
|
||||||
|
// todo: designations, properties
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean compareStrings(String path, List<ValidationMessage> msgs, String left, String right, String name, IssueSeverity level, CodeSystemComparison res) {
|
private boolean compare(List<ValidationMessage> msgs, PropertyComponent l, PropertyComponent r, String path, CodeSystemComparison res, Base parent) {
|
||||||
|
boolean result = false;
|
||||||
|
result = compareStrings(path, msgs, l.getUri(), r.getUri(), "uri", IssueSeverity.WARNING, res, parent, l.getUriElement(), r.getUriElement()) || result;
|
||||||
|
result = compareStrings(path, msgs, l.hasType() ? l.getType().toCode() : null, r.hasType() ? r.getType().toCode() : null, "type", IssueSeverity.ERROR, res, parent, l.getTypeElement(), r.getTypeElement()) || result;
|
||||||
|
result = compareStrings(path, msgs, l.getDescription(), r.getDescription(), "description", IssueSeverity.WARNING, res, parent, l.getDescriptionElement(), r.getDescriptionElement()) || result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean compare(List<ValidationMessage> msgs, CodeSystemFilterComponent l, CodeSystemFilterComponent r, String path, CodeSystemComparison res, Base parent) {
|
||||||
|
boolean result = false;
|
||||||
|
result = compareStrings(path, msgs, l.getDescription(), r.getDescription(), "description", IssueSeverity.WARNING, res, parent, l.getDescriptionElement(), r.getDescriptionElement()) || result;
|
||||||
|
// todo: repeating
|
||||||
|
// result = compareStrings(path, msgs, l.hasOperator() ? l.getOperator().toCode() : null, r.hasType() ? r.getType().toCode() : null, "type", IssueSeverity.ERROR, res, parent, l.getTypeElement(), r.getTypeElement()) || result;
|
||||||
|
result = compareStrings(path, msgs, l.getValue(), r.getValue(), "value", IssueSeverity.WARNING, res, parent, l.getValueElement(), r.getValueElement()) || result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean compareStrings(String path, List<ValidationMessage> msgs, String left, String right, String name, IssueSeverity level, CodeSystemComparison res, Base parent, Base l, Base r) {
|
||||||
if (!Utilities.noString(right)) {
|
if (!Utilities.noString(right)) {
|
||||||
if (Utilities.noString(left)) {
|
if (Utilities.noString(left)) {
|
||||||
msgs.add(vmI(level, "Value for "+name+" added", path));
|
msgs.add(vmI(level, "Value for "+name+" added", path));
|
||||||
|
VersionComparisonAnnotation.markAdded(r, session.getForVersion());
|
||||||
return true;
|
return true;
|
||||||
} else if (!left.equals(right)) {
|
} else if (!left.equals(right)) {
|
||||||
if (level != IssueSeverity.NULL) {
|
if (level != IssueSeverity.NULL) {
|
||||||
res.getMessages().add(new ValidationMessage(Source.ProfileComparer, IssueType.INFORMATIONAL, path+"."+name, "Changed value for "+name+": '"+left+"' vs '"+right+"'", level));
|
res.getMessages().add(new ValidationMessage(Source.ProfileComparer, IssueType.INFORMATIONAL, path+"."+name, "Changed value for "+name+": '"+left+"' vs '"+right+"'", level));
|
||||||
}
|
}
|
||||||
msgs.add(vmI(level, name+" changed from left to right", path));
|
msgs.add(vmI(level, name+" changed from left to right", path));
|
||||||
|
VersionComparisonAnnotation.markChanged(r, session.getForVersion());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (!Utilities.noString(left)) {
|
} else if (!Utilities.noString(left)) {
|
||||||
msgs.add(vmI(level, "Value for "+name+" removed", path));
|
msgs.add(vmI(level, "Value for "+name+" removed", path));
|
||||||
|
VersionComparisonAnnotation.markDeleted(parent, session.getForVersion(), "concept", l);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -246,6 +382,23 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
|
||||||
return cd;
|
return cd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private PropertyComponent merge(PropertyComponent l, PropertyComponent r, CodeSystemComparison res) {
|
||||||
|
PropertyComponent cd = l.copy();
|
||||||
|
if (!l.hasDescription() && r.hasDescription()) {
|
||||||
|
cd.setDescription(r.getDescription());
|
||||||
|
}
|
||||||
|
return cd;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private CodeSystemFilterComponent merge(CodeSystemFilterComponent l, CodeSystemFilterComponent r, CodeSystemComparison res) {
|
||||||
|
CodeSystemFilterComponent cd = l.copy();
|
||||||
|
if (!l.hasDescription() && r.hasDescription()) {
|
||||||
|
cd.setDescription(r.getDescription());
|
||||||
|
}
|
||||||
|
return cd;
|
||||||
|
}
|
||||||
|
|
||||||
private ConceptDefinitionComponent intersect(ConceptDefinitionComponent l, ConceptDefinitionComponent r, CodeSystemComparison res) {
|
private ConceptDefinitionComponent intersect(ConceptDefinitionComponent l, ConceptDefinitionComponent r, CodeSystemComparison res) {
|
||||||
ConceptDefinitionComponent cd = l.copy();
|
ConceptDefinitionComponent cd = l.copy();
|
||||||
if (l.hasDisplay() && !r.hasDisplay()) {
|
if (l.hasDisplay() && !r.hasDisplay()) {
|
||||||
|
@ -259,6 +412,22 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
|
||||||
return cd;
|
return cd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private PropertyComponent intersect(PropertyComponent l, PropertyComponent r, CodeSystemComparison res) {
|
||||||
|
PropertyComponent cd = l.copy();
|
||||||
|
if (l.hasDescription() && !r.hasDescription()) {
|
||||||
|
cd.setDescription(null);
|
||||||
|
}
|
||||||
|
return cd;
|
||||||
|
}
|
||||||
|
|
||||||
|
private CodeSystemFilterComponent intersect(CodeSystemFilterComponent l, CodeSystemFilterComponent r, CodeSystemComparison res) {
|
||||||
|
CodeSystemFilterComponent cd = l.copy();
|
||||||
|
if (l.hasDescription() && !r.hasDescription()) {
|
||||||
|
cd.setDescription(null);
|
||||||
|
}
|
||||||
|
return cd;
|
||||||
|
}
|
||||||
|
|
||||||
private void mergeDesignations(ConceptDefinitionComponent cd, ConceptDefinitionComponent l, ConceptDefinitionComponent r) {
|
private void mergeDesignations(ConceptDefinitionComponent cd, ConceptDefinitionComponent l, ConceptDefinitionComponent r) {
|
||||||
for (ConceptDefinitionDesignationComponent td : l.getDesignation()) {
|
for (ConceptDefinitionDesignationComponent td : l.getDesignation()) {
|
||||||
if (hasDesignation(td, r.getDesignation())) {
|
if (hasDesignation(td, r.getDesignation())) {
|
||||||
|
@ -341,7 +510,8 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
|
||||||
|
|
||||||
private ConceptPropertyComponent findRightProp(List<ConceptPropertyComponent> rightProperties, ConceptPropertyComponent lp, CodeSystemComparison res) {
|
private ConceptPropertyComponent findRightProp(List<ConceptPropertyComponent> rightProperties, ConceptPropertyComponent lp, CodeSystemComparison res) {
|
||||||
for (ConceptPropertyComponent p : rightProperties) {
|
for (ConceptPropertyComponent p : rightProperties) {
|
||||||
if (res.getPropMap().get(p.getCode()).equals(lp.getCode())) {
|
String rp = res.getPropMap().get(p.getCode());
|
||||||
|
if (rp != null && rp.equals(lp.getCode())) {
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,9 +107,9 @@ public class ComparisonSession {
|
||||||
throw new FHIRException("Unable to compare resources of type "+left.fhirType()+" and "+right.fhirType());
|
throw new FHIRException("Unable to compare resources of type "+left.fhirType()+" and "+right.fhirType());
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
if (debug) {
|
// if (debug) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
// }
|
||||||
ResourceComparer.PlaceHolderComparison csc = new ResourceComparer.PlaceHolderComparison(left, right, e);
|
ResourceComparer.PlaceHolderComparison csc = new ResourceComparer.PlaceHolderComparison(left, right, e);
|
||||||
compares.put(key, csc);
|
compares.put(key, csc);
|
||||||
return csc;
|
return csc;
|
||||||
|
|
|
@ -5,10 +5,12 @@ import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
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.CanonicalResourceComparer.CanonicalResourceComparison;
|
||||||
import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison;
|
import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison;
|
||||||
import org.hl7.fhir.r5.conformance.profile.BindingResolution;
|
import org.hl7.fhir.r5.conformance.profile.BindingResolution;
|
||||||
import org.hl7.fhir.r5.conformance.profile.ProfileKnowledgeProvider;
|
import org.hl7.fhir.r5.conformance.profile.ProfileKnowledgeProvider;
|
||||||
|
@ -17,6 +19,7 @@ import org.hl7.fhir.r5.context.IWorkerContext;
|
||||||
import org.hl7.fhir.r5.formats.IParser;
|
import org.hl7.fhir.r5.formats.IParser;
|
||||||
import org.hl7.fhir.r5.formats.JsonParser;
|
import org.hl7.fhir.r5.formats.JsonParser;
|
||||||
import org.hl7.fhir.r5.model.Base;
|
import org.hl7.fhir.r5.model.Base;
|
||||||
|
import org.hl7.fhir.r5.model.CanonicalResource;
|
||||||
import org.hl7.fhir.r5.model.Coding;
|
import org.hl7.fhir.r5.model.Coding;
|
||||||
import org.hl7.fhir.r5.model.DataType;
|
import org.hl7.fhir.r5.model.DataType;
|
||||||
import org.hl7.fhir.r5.model.ElementDefinition;
|
import org.hl7.fhir.r5.model.ElementDefinition;
|
||||||
|
@ -143,20 +146,39 @@ public class ProfileComparer extends CanonicalResourceComparer implements Profil
|
||||||
sd1.setStatus(left.getStatus());
|
sd1.setStatus(left.getStatus());
|
||||||
sd1.setDate(new Date());
|
sd1.setDate(new Date());
|
||||||
|
|
||||||
compareMetadata(left, right, res.getMetadata(), res);
|
List<String> chMetadata = new ArrayList<>();
|
||||||
comparePrimitives("fhirVersion", left.getFhirVersionElement(), right.getFhirVersionElement(), res.getMetadata(), IssueSeverity.WARNING, res);
|
boolean ch = compareMetadata(left, right, res.getMetadata(), res, chMetadata);
|
||||||
comparePrimitives("kind", left.getKindElement(), right.getKindElement(), res.getMetadata(), IssueSeverity.WARNING, res);
|
if (comparePrimitives("fhirVersion", left.getFhirVersionElement(), right.getFhirVersionElement(), res.getMetadata(), IssueSeverity.WARNING, res)) {
|
||||||
comparePrimitives("abstract", left.getAbstractElement(), right.getAbstractElement(), res.getMetadata(), IssueSeverity.WARNING, res);
|
ch = true;
|
||||||
comparePrimitives("type", left.getTypeElement(), right.getTypeElement(), res.getMetadata(), IssueSeverity.ERROR, res);
|
chMetadata.add("fhirVersion");
|
||||||
comparePrimitives("baseDefinition", left.getBaseDefinitionElement(), right.getBaseDefinitionElement(), res.getMetadata(), IssueSeverity.ERROR, res);
|
}
|
||||||
|
if (comparePrimitives("kind", left.getKindElement(), right.getKindElement(), res.getMetadata(), IssueSeverity.WARNING, res)) {
|
||||||
|
ch = true;
|
||||||
|
chMetadata.add("kind");
|
||||||
|
}
|
||||||
|
if (comparePrimitives("abstract", left.getAbstractElement(), right.getAbstractElement(), res.getMetadata(), IssueSeverity.WARNING, res)) {
|
||||||
|
ch = true;
|
||||||
|
chMetadata.add("abstract");
|
||||||
|
}
|
||||||
|
res.updatedMetadataState(ch, chMetadata);
|
||||||
|
|
||||||
|
ch = false;
|
||||||
|
ch = comparePrimitives("type", left.getTypeElement(), right.getTypeElement(), res.getMetadata(), IssueSeverity.ERROR, res) || ch;
|
||||||
|
ch = comparePrimitives("baseDefinition", left.getBaseDefinitionElement(), right.getBaseDefinitionElement(), res.getMetadata(), IssueSeverity.ERROR, res) || ch;
|
||||||
if (left.getType().equals(right.getType())) {
|
if (left.getType().equals(right.getType())) {
|
||||||
DefinitionNavigator ln = new DefinitionNavigator(session.getContextLeft(), left);
|
DefinitionNavigator ln = new DefinitionNavigator(session.getContextLeft(), left, false);
|
||||||
DefinitionNavigator rn = new DefinitionNavigator(session.getContextRight(), right);
|
DefinitionNavigator rn = new DefinitionNavigator(session.getContextRight(), right, false);
|
||||||
StructuralMatch<ElementDefinitionNode> sm = new StructuralMatch<ElementDefinitionNode>(new ElementDefinitionNode(left, ln.current()), new ElementDefinitionNode(right, rn.current()));
|
StructuralMatch<ElementDefinitionNode> sm = new StructuralMatch<ElementDefinitionNode>(new ElementDefinitionNode(left, ln.current()), new ElementDefinitionNode(right, rn.current()));
|
||||||
compareElements(res, sm, ln.path(), null, ln, rn);
|
compareElements(res, sm, ln.path(), null, ln, rn);
|
||||||
res.combined = sm;
|
res.combined = sm;
|
||||||
|
ln = new DefinitionNavigator(session.getContextLeft(), left, true);
|
||||||
|
rn = new DefinitionNavigator(session.getContextRight(), right, true);
|
||||||
|
ch = compareDiff(ln.path(), null, ln, rn) || ch;
|
||||||
|
// we don't preserve the differences - we only want the annotations
|
||||||
}
|
}
|
||||||
|
res.updateDefinitionsState(ch);
|
||||||
|
|
||||||
|
VersionComparisonAnnotation.annotate(right, session.getForVersion(), res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,12 +195,14 @@ public class ProfileComparer extends CanonicalResourceComparer implements Profil
|
||||||
throw new DefinitionException("StructureDefinition snapshot is empty ("+name+": "+sd.getName()+")");
|
throw new DefinitionException("StructureDefinition snapshot is empty ("+name+": "+sd.getName()+")");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void compareElements(ProfileComparison comp, StructuralMatch<ElementDefinitionNode> res, String path, String sliceName, DefinitionNavigator left, DefinitionNavigator right) throws DefinitionException, FHIRFormatError, IOException {
|
private boolean compareElements(ProfileComparison comp, StructuralMatch<ElementDefinitionNode> res, String path, String sliceName, DefinitionNavigator left, DefinitionNavigator right) throws DefinitionException, FHIRFormatError, IOException {
|
||||||
assert(path != null);
|
assert(path != null);
|
||||||
assert(left != null);
|
assert(left != null);
|
||||||
assert(right != null);
|
assert(right != null);
|
||||||
assert(left.path().equals(right.path()));
|
assert(left.path().equals(right.path()));
|
||||||
|
|
||||||
|
boolean def = false;
|
||||||
|
|
||||||
if (session.isDebug()) {
|
if (session.isDebug()) {
|
||||||
System.out.println("Compare elements at "+path);
|
System.out.println("Compare elements at "+path);
|
||||||
}
|
}
|
||||||
|
@ -196,7 +220,6 @@ public class ProfileComparer extends CanonicalResourceComparer implements Profil
|
||||||
if (sliceName != null)
|
if (sliceName != null)
|
||||||
subset.setSliceName(sliceName);
|
subset.setSliceName(sliceName);
|
||||||
|
|
||||||
|
|
||||||
subset.getRepresentation().addAll(left.current().getRepresentation()); // can't be bothered even testing this one
|
subset.getRepresentation().addAll(left.current().getRepresentation()); // can't be bothered even testing this one
|
||||||
subset.setDefaultValue(left.current().getDefaultValue());
|
subset.setDefaultValue(left.current().getDefaultValue());
|
||||||
subset.setMeaningWhenMissing(left.current().getMeaningWhenMissing());
|
subset.setMeaningWhenMissing(left.current().getMeaningWhenMissing());
|
||||||
|
@ -205,10 +228,20 @@ public class ProfileComparer extends CanonicalResourceComparer implements Profil
|
||||||
|
|
||||||
// descriptive properties from ElementDefinition - merge them:
|
// descriptive properties from ElementDefinition - merge them:
|
||||||
subset.setLabel(mergeText(comp, res, path, "label", left.current().getLabel(), right.current().getLabel(), false));
|
subset.setLabel(mergeText(comp, res, path, "label", left.current().getLabel(), right.current().getLabel(), false));
|
||||||
|
comparePrimitivesWithTracking("label", left.current().getLabelElement(), right.current().getLabelElement(), null, IssueSeverity.INFORMATION, comp, right.current(), session.getForVersion());
|
||||||
|
|
||||||
subset.setShort(mergeText(comp, res, path, "short", left.current().getShort(), right.current().getShort(), false));
|
subset.setShort(mergeText(comp, res, path, "short", left.current().getShort(), right.current().getShort(), false));
|
||||||
|
def = comparePrimitivesWithTracking("short", left.current().getShortElement(), right.current().getShortElement(), null, IssueSeverity.INFORMATION, comp, right.current(), session.getForVersion()) || def;
|
||||||
|
|
||||||
subset.setDefinition(mergeText(comp, res, path, "definition", left.current().getDefinition(), right.current().getDefinition(), false));
|
subset.setDefinition(mergeText(comp, res, path, "definition", left.current().getDefinition(), right.current().getDefinition(), false));
|
||||||
|
def = comparePrimitivesWithTracking("definition", left.current().getDefinitionElement(), right.current().getDefinitionElement(), null, IssueSeverity.INFORMATION, comp, right.current(), session.getForVersion()) || def;
|
||||||
|
|
||||||
subset.setComment(mergeText(comp, res, path, "comments", left.current().getComment(), right.current().getComment(), false));
|
subset.setComment(mergeText(comp, res, path, "comments", left.current().getComment(), right.current().getComment(), false));
|
||||||
|
def = comparePrimitivesWithTracking("comment", left.current().getCommentElement(), right.current().getCommentElement(), null, IssueSeverity.INFORMATION, comp, right.current(), session.getForVersion()) || def;
|
||||||
|
|
||||||
subset.setRequirements(mergeText(comp, res, path, "requirements", left.current().getRequirements(), right.current().getRequirements(), false));
|
subset.setRequirements(mergeText(comp, res, path, "requirements", left.current().getRequirements(), right.current().getRequirements(), false));
|
||||||
|
def = comparePrimitivesWithTracking("requirements", left.current().getRequirementsElement(), right.current().getRequirementsElement(), null, IssueSeverity.INFORMATION, comp, right.current(), session.getForVersion()) || def;
|
||||||
|
|
||||||
subset.getCode().addAll(mergeCodings(left.current().getCode(), right.current().getCode()));
|
subset.getCode().addAll(mergeCodings(left.current().getCode(), right.current().getCode()));
|
||||||
subset.getAlias().addAll(mergeStrings(left.current().getAlias(), right.current().getAlias()));
|
subset.getAlias().addAll(mergeStrings(left.current().getAlias(), right.current().getAlias()));
|
||||||
subset.getMapping().addAll(mergeMappings(left.current().getMapping(), right.current().getMapping()));
|
subset.getMapping().addAll(mergeMappings(left.current().getMapping(), right.current().getMapping()));
|
||||||
|
@ -220,14 +253,18 @@ public class ProfileComparer extends CanonicalResourceComparer implements Profil
|
||||||
|
|
||||||
}
|
}
|
||||||
subset.setMustSupport(left.current().getMustSupport() || right.current().getMustSupport());
|
subset.setMustSupport(left.current().getMustSupport() || right.current().getMustSupport());
|
||||||
|
def = comparePrimitivesWithTracking("mustSupport", left.current().getMustSupportElement(), right.current().getMustSupportElement(), null, IssueSeverity.INFORMATION, null, right.current(), session.getForVersion()) || def;
|
||||||
|
|
||||||
ElementDefinition superset = subset.copy();
|
ElementDefinition superset = subset.copy();
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
// compare and intersect
|
// compare and intersect
|
||||||
int leftMin = left.current().getMin();
|
int leftMin = left.current().getMin();
|
||||||
int rightMin = right.current().getMin();
|
int rightMin = right.current().getMin();
|
||||||
int leftMax = "*".equals(left.current().getMax()) ? Integer.MAX_VALUE : Integer.parseInt(left.current().getMax());
|
int leftMax = "*".equals(left.current().getMax()) ? Integer.MAX_VALUE : Utilities.parseInt(left.current().getMax(), -1);
|
||||||
int rightMax = "*".equals(right.current().getMax()) ? Integer.MAX_VALUE : Integer.parseInt(right.current().getMax());
|
int rightMax = "*".equals(right.current().getMax()) ? Integer.MAX_VALUE : Utilities.parseInt(right.current().getMax(), -1);
|
||||||
|
|
||||||
checkMinMax(comp, res, path, leftMin, rightMin, leftMax, rightMax);
|
checkMinMax(comp, res, path, leftMin, rightMin, leftMax, rightMax);
|
||||||
superset.setMin(unionMin(leftMin, rightMin));
|
superset.setMin(unionMin(leftMin, rightMin));
|
||||||
|
@ -252,7 +289,7 @@ public class ProfileComparer extends CanonicalResourceComparer implements Profil
|
||||||
comp.getUnion().getSnapshot().getElement().add(superset);
|
comp.getUnion().getSnapshot().getElement().add(superset);
|
||||||
|
|
||||||
// add the children
|
// add the children
|
||||||
compareChildren(comp, res, path, left, right);
|
def = compareChildren(comp, res, path, left, right) || def;
|
||||||
//
|
//
|
||||||
// // now process the slices
|
// // now process the slices
|
||||||
// if (left.current().hasSlicing() || right.current().hasSlicing()) {
|
// if (left.current().hasSlicing() || right.current().hasSlicing()) {
|
||||||
|
@ -312,10 +349,13 @@ public class ProfileComparer extends CanonicalResourceComparer implements Profil
|
||||||
//
|
//
|
||||||
// // TODO Auto-generated method stub
|
// // TODO Auto-generated method stub
|
||||||
// return null;
|
// return null;
|
||||||
|
return def;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private boolean compareChildren(ProfileComparison comp, StructuralMatch<ElementDefinitionNode> res, String path, DefinitionNavigator left, DefinitionNavigator right) throws DefinitionException, IOException, FHIRFormatError {
|
||||||
private void compareChildren(ProfileComparison comp, StructuralMatch<ElementDefinitionNode> res, String path, DefinitionNavigator left, DefinitionNavigator right) throws DefinitionException, IOException, FHIRFormatError {
|
boolean def = false;
|
||||||
|
|
||||||
List<DefinitionNavigator> lc = left.children();
|
List<DefinitionNavigator> lc = left.children();
|
||||||
List<DefinitionNavigator> rc = right.children();
|
List<DefinitionNavigator> rc = right.children();
|
||||||
// it's possible that one of these profiles walks into a data type and the other doesn't
|
// it's possible that one of these profiles walks into a data type and the other doesn't
|
||||||
|
@ -336,7 +376,7 @@ public class ProfileComparer extends CanonicalResourceComparer implements Profil
|
||||||
matchR.add(r);
|
matchR.add(r);
|
||||||
StructuralMatch<ElementDefinitionNode> sm = new StructuralMatch<ElementDefinitionNode>(new ElementDefinitionNode(l.getStructure(), l.current()), new ElementDefinitionNode(r.getStructure(), r.current()));
|
StructuralMatch<ElementDefinitionNode> sm = new StructuralMatch<ElementDefinitionNode>(new ElementDefinitionNode(l.getStructure(), l.current()), new ElementDefinitionNode(r.getStructure(), r.current()));
|
||||||
res.getChildren().add(sm);
|
res.getChildren().add(sm);
|
||||||
compareElements(comp, sm, l.path(), null, l, r);
|
def = compareElements(comp, sm, l.path(), null, l, r) || def;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (DefinitionNavigator r : rc) {
|
for (DefinitionNavigator r : rc) {
|
||||||
|
@ -345,6 +385,127 @@ public class ProfileComparer extends CanonicalResourceComparer implements Profil
|
||||||
res.getChildren().add(new StructuralMatch<ElementDefinitionNode>(vmI(IssueSeverity.INFORMATION, "Added this element", path), new ElementDefinitionNode(r.getStructure(), r.current())));
|
res.getChildren().add(new StructuralMatch<ElementDefinitionNode>(vmI(IssueSeverity.INFORMATION, "Added this element", path), new ElementDefinitionNode(r.getStructure(), r.current())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private boolean compareDiff(String path, String sliceName, DefinitionNavigator left, DefinitionNavigator right) throws DefinitionException, FHIRFormatError, IOException {
|
||||||
|
assert(path != null);
|
||||||
|
assert(left != null);
|
||||||
|
assert(right != null);
|
||||||
|
assert(left.path().equals(right.path()));
|
||||||
|
|
||||||
|
boolean def = false;
|
||||||
|
|
||||||
|
// not allowed to be different:
|
||||||
|
// ruleEqual(comp, res, left.current().getDefaultValue(), right.current().getDefaultValue(), "defaultValue", path);
|
||||||
|
// ruleEqual(comp, res, left.current().getMeaningWhenMissingElement(), right.current().getMeaningWhenMissingElement(), "meaningWhenMissing", path);
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// descriptive properties from ElementDefinition - merge them:
|
||||||
|
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("definition", left.current().getDefinitionElement(), right.current().getDefinitionElement(), null, IssueSeverity.INFORMATION, null, right.current(), session.getForVersion()) || def;
|
||||||
|
def = comparePrimitivesWithTracking("comment", left.current().getCommentElement(), right.current().getCommentElement(), null, IssueSeverity.INFORMATION, null, right.current(), session.getForVersion()) || def;
|
||||||
|
def = comparePrimitivesWithTracking("requirements", left.current().getRequirementsElement(), right.current().getRequirementsElement(), 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("max", left.current().getMaxElement(), right.current().getMaxElement(), null, IssueSeverity.INFORMATION, null, right.current(), session.getForVersion()) || def;
|
||||||
|
|
||||||
|
// add the children
|
||||||
|
def = compareDiffChildren(path, left, right) || def;
|
||||||
|
//
|
||||||
|
// // now process the slices
|
||||||
|
// if (left.current().hasSlicing() || right.current().hasSlicing()) {
|
||||||
|
// assert sliceName == null;
|
||||||
|
// if (isExtension(left.path()))
|
||||||
|
// return compareExtensions(outcome, path, superset, subset, left, right);
|
||||||
|
// // return true;
|
||||||
|
// else {
|
||||||
|
// ElementDefinitionSlicingComponent slicingL = left.current().getSlicing();
|
||||||
|
// ElementDefinitionSlicingComponent slicingR = right.current().getSlicing();
|
||||||
|
// // well, this is tricky. If one is sliced, and the other is not, then in general, the union just ignores the slices, and the intersection is the slices.
|
||||||
|
// if (left.current().hasSlicing() && !right.current().hasSlicing()) {
|
||||||
|
// // the super set is done. Any restrictions in the slices are irrelevant to what the super set says, except that we're going sum up the value sets if we can (for documentation purposes) (todo)
|
||||||
|
// // the minimum set is the slicing specified in the slicer
|
||||||
|
// subset.setSlicing(slicingL);
|
||||||
|
// // stick everything from the right to do with the slices to the subset
|
||||||
|
// copySlices(outcome.subset.getSnapshot().getElement(), left.getStructure().getSnapshot().getElement(), left.slices());
|
||||||
|
// } else if (!left.current().hasSlicing() && right.current().hasSlicing()) {
|
||||||
|
// // the super set is done. Any restrictions in the slices are irrelevant to what the super set says, except that we're going sum up the value sets if we can (for documentation purposes) (todo)
|
||||||
|
// // the minimum set is the slicing specified in the slicer
|
||||||
|
// subset.setSlicing(slicingR);
|
||||||
|
// // stick everything from the right to do with the slices to the subset
|
||||||
|
// copySlices(outcome.subset.getSnapshot().getElement(), right.getStructure().getSnapshot().getElement(), right.slices());
|
||||||
|
// } else if (isTypeSlicing(slicingL) || isTypeSlicing(slicingR)) {
|
||||||
|
// superset.getSlicing().setRules(SlicingRules.OPEN).setOrdered(false).addDiscriminator().setType(DiscriminatorType.TYPE).setPath("$this");
|
||||||
|
// subset.getSlicing().setRules(slicingL.getRules() == SlicingRules.CLOSED || slicingR.getRules() == SlicingRules.CLOSED ? SlicingRules.OPEN : SlicingRules.CLOSED).setOrdered(false).addDiscriminator().setType(DiscriminatorType.TYPE).setPath("$this");
|
||||||
|
//
|
||||||
|
// // the superset is the union of the types
|
||||||
|
// // the subset is the intersection of them
|
||||||
|
// List<DefinitionNavigator> handled = new ArrayList<>();
|
||||||
|
// for (DefinitionNavigator t : left.slices()) {
|
||||||
|
// DefinitionNavigator r = findMatchingSlice(right.slices(), t);
|
||||||
|
// if (r == null) {
|
||||||
|
// copySlice(outcome.superset.getSnapshot().getElement(), left.getStructure().getSnapshot().getElement(), t);
|
||||||
|
// } else {
|
||||||
|
// handled.add(r);
|
||||||
|
// ret = compareElements(outcome, path+":"+t.current().getSliceName(), t, r, t.current().getSliceName()) && ret;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// for (DefinitionNavigator t : right.slices()) {
|
||||||
|
// if (!handled.contains(t)) {
|
||||||
|
// copySlice(outcome.superset.getSnapshot().getElement(), right.getStructure().getSnapshot().getElement(), t);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } else if (slicingMatches(slicingL, slicingR)) {
|
||||||
|
// // if it's the same, we can try matching the slices - though we might have to give up without getting matches correct
|
||||||
|
// // there amy be implied consistency we can't reason about
|
||||||
|
// throw new DefinitionException("Slicing matches but is not handled yet at "+left.current().getId()+": ("+ProfileUtilities.summarizeSlicing(slicingL)+")");
|
||||||
|
// } else {
|
||||||
|
// // if the slicing is different, we can't compare them - or can we?
|
||||||
|
// throw new DefinitionException("Slicing doesn't match at "+left.current().getId()+": ("+ProfileUtilities.summarizeSlicing(slicingL)+" / "+ProfileUtilities.summarizeSlicing(slicingR)+")");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// // todo: name
|
||||||
|
// }
|
||||||
|
// return ret;
|
||||||
|
//
|
||||||
|
// // TODO Auto-generated method stub
|
||||||
|
// return null;
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private boolean compareDiffChildren(String path, DefinitionNavigator left, DefinitionNavigator right) throws DefinitionException, IOException, FHIRFormatError {
|
||||||
|
boolean def = false;
|
||||||
|
|
||||||
|
List<DefinitionNavigator> lc = left.children();
|
||||||
|
List<DefinitionNavigator> rc = right.children();
|
||||||
|
// it's possible that one of these profiles walks into a data type and the other doesn't
|
||||||
|
// if it does, we have to load the children for that data into the profile that doesn't
|
||||||
|
// walk into it
|
||||||
|
if (lc.isEmpty() && !rc.isEmpty() && right.current().getType().size() == 1 && left.hasTypeChildren(right.current().getType().get(0), left.getStructure()))
|
||||||
|
lc = left.childrenFromType(right.current().getType().get(0), right.getStructure());
|
||||||
|
if (rc.isEmpty() && !lc.isEmpty() && left.current().getType().size() == 1 && right.hasTypeChildren(left.current().getType().get(0), right.getStructure()))
|
||||||
|
rc = right.childrenFromType(left.current().getType().get(0), left.getStructure());
|
||||||
|
|
||||||
|
List<DefinitionNavigator> matchR = new ArrayList<>();
|
||||||
|
for (DefinitionNavigator l : lc) {
|
||||||
|
DefinitionNavigator r = findInList(rc, l);
|
||||||
|
if (r == null) {
|
||||||
|
// todo
|
||||||
|
} else {
|
||||||
|
def = compareDiff(l.path(), null, l, r) || def;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (DefinitionNavigator r : rc) {
|
||||||
|
if (!matchR.contains(r)) {
|
||||||
|
// todo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return def;
|
||||||
}
|
}
|
||||||
|
|
||||||
private DefinitionNavigator findInList(List<DefinitionNavigator> rc, DefinitionNavigator l) {
|
private DefinitionNavigator findInList(List<DefinitionNavigator> rc, DefinitionNavigator l) {
|
||||||
|
@ -356,18 +517,18 @@ public class ProfileComparer extends CanonicalResourceComparer implements Profil
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ruleEqual(ProfileComparison comp, StructuralMatch<ElementDefinitionNode> res, DataType vLeft, DataType vRight, String name, String path) throws IOException {
|
// private void ruleEqual(ProfileComparison comp, StructuralMatch<ElementDefinitionNode> res, DataType vLeft, DataType vRight, String name, String path) throws IOException {
|
||||||
if (vLeft == null && vRight == null) {
|
// if (vLeft == null && vRight == null) {
|
||||||
// nothing
|
// // nothing
|
||||||
} else if (vLeft == null) {
|
// } else if (vLeft == null) {
|
||||||
vm(IssueSeverity.ERROR, "Added "+name, path, comp.getMessages(), res.getMessages());
|
// vm(IssueSeverity.ERROR, "Added "+name, path, comp.getMessages(), res.getMessages());
|
||||||
} else if (vRight == null) {
|
// } else if (vRight == null) {
|
||||||
vm(IssueSeverity.ERROR, "Removed "+name, path, comp.getMessages(), res.getMessages());
|
// vm(IssueSeverity.ERROR, "Removed "+name, path, comp.getMessages(), res.getMessages());
|
||||||
} else if (!Base.compareDeep(vLeft, vRight, false)) {
|
// } else if (!Base.compareDeep(vLeft, vRight, false)) {
|
||||||
vm(IssueSeverity.ERROR, name+" must be the same ("+toString(vLeft, true)+"/"+toString(vRight, false)+")", path, comp.getMessages(), res.getMessages());
|
// vm(IssueSeverity.ERROR, name+" must be the same ("+toString(vLeft, true)+"/"+toString(vRight, false)+")", path, comp.getMessages(), res.getMessages());
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
private String toString(DataType val, boolean left) throws IOException {
|
private String toString(DataType val, boolean left) throws IOException {
|
||||||
if (val instanceof PrimitiveType)
|
if (val instanceof PrimitiveType)
|
||||||
return "'" + ((PrimitiveType) val).getValueAsString()+"'";
|
return "'" + ((PrimitiveType) val).getValueAsString()+"'";
|
||||||
|
@ -406,9 +567,6 @@ public class ProfileComparer extends CanonicalResourceComparer implements Profil
|
||||||
right = stripLinks(right);
|
right = stripLinks(right);
|
||||||
if (left.equalsIgnoreCase(right))
|
if (left.equalsIgnoreCase(right))
|
||||||
return left;
|
return left;
|
||||||
if (path != null) {
|
|
||||||
vm(isError ? IssueSeverity.ERROR : IssueSeverity.WARNING, "Elements differ in "+name+": '"+left+"' vs '"+right+"'", path, comp.getMessages(), res.getMessages());
|
|
||||||
}
|
|
||||||
return "left: "+left+"; right: "+right;
|
return "left: "+left+"; right: "+right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,18 +124,26 @@ public class ValueSetComparer extends CanonicalResourceComparer {
|
||||||
vs1.setStatus(left.getStatus());
|
vs1.setStatus(left.getStatus());
|
||||||
vs1.setDate(new Date());
|
vs1.setDate(new Date());
|
||||||
|
|
||||||
var ch = compareMetadata(left, right, res.getMetadata(), res);
|
List<String> chMetadata = new ArrayList<>();
|
||||||
|
var ch = compareMetadata(left, right, res.getMetadata(), res, chMetadata);
|
||||||
var def = false;
|
var def = false;
|
||||||
ch = comparePrimitives("immutable", left.getImmutableElement(), right.getImmutableElement(), res.getMetadata(), IssueSeverity.WARNING, res) || ch;
|
if (comparePrimitives("immutable", left.getImmutableElement(), right.getImmutableElement(), res.getMetadata(), IssueSeverity.WARNING, res)) {
|
||||||
|
ch = true;
|
||||||
|
chMetadata.add("immutable");
|
||||||
|
}
|
||||||
if (left.hasCompose() || right.hasCompose()) {
|
if (left.hasCompose() || right.hasCompose()) {
|
||||||
ch = comparePrimitives("compose.lockedDate", left.getCompose().getLockedDateElement(), right.getCompose().getLockedDateElement(), res.getMetadata(), IssueSeverity.WARNING, res) || ch;
|
if (comparePrimitives("compose.lockedDate", left.getCompose().getLockedDateElement(), right.getCompose().getLockedDateElement(), res.getMetadata(), IssueSeverity.WARNING, res)) {
|
||||||
|
ch = true;
|
||||||
|
chMetadata.add("compose.lockedDate");
|
||||||
|
}
|
||||||
def = comparePrimitives("compose.inactive", left.getCompose().getInactiveElement(), right.getCompose().getInactiveElement(), res.getMetadata(), IssueSeverity.WARNING, res) || def;
|
def = comparePrimitives("compose.inactive", left.getCompose().getInactiveElement(), right.getCompose().getInactiveElement(), res.getMetadata(), IssueSeverity.WARNING, res) || def;
|
||||||
}
|
}
|
||||||
res.updatedMetadataState(ch);
|
res.updatedMetadataState(ch, chMetadata);
|
||||||
|
|
||||||
def = compareCompose(left.getCompose(), right.getCompose(), res, res.getUnion().getCompose(), res.getIntersection().getCompose()) || def;
|
def = compareCompose(left.getCompose(), right.getCompose(), res, res.getUnion().getCompose(), res.getIntersection().getCompose()) || def;
|
||||||
res.updateDefinitionsState(def);
|
res.updateDefinitionsState(def);
|
||||||
compareExpansions(left, right, res);
|
compareExpansions(left, right, res);
|
||||||
|
VersionComparisonAnnotation.annotate(right, session.getForVersion(), res);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,9 +157,7 @@ public class ValueSetComparer extends CanonicalResourceComparer {
|
||||||
union.getInclude().add(l);
|
union.getInclude().add(l);
|
||||||
res.updateContentState(true);
|
res.updateContentState(true);
|
||||||
res.getIncludes().getChildren().add(new StructuralMatch<Element>(l, vmI(IssueSeverity.INFORMATION, "Removed Include", "ValueSet.compose.include")));
|
res.getIncludes().getChildren().add(new StructuralMatch<Element>(l, vmI(IssueSeverity.INFORMATION, "Removed Include", "ValueSet.compose.include")));
|
||||||
if (session.isAnnotate()) {
|
VersionComparisonAnnotation.markDeleted(right, session.getForVersion(), "include", l);
|
||||||
VersionComparisonAnnotation.markDeleted(right, session.getForVersion(), "include", l);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
matchR.add(r);
|
matchR.add(r);
|
||||||
ConceptSetComponent csM = new ConceptSetComponent();
|
ConceptSetComponent csM = new ConceptSetComponent();
|
||||||
|
@ -168,9 +174,7 @@ public class ValueSetComparer extends CanonicalResourceComparer {
|
||||||
union.getInclude().add(r);
|
union.getInclude().add(r);
|
||||||
res.updateContentState(true);
|
res.updateContentState(true);
|
||||||
res.getIncludes().getChildren().add(new StructuralMatch<Element>(vmI(IssueSeverity.INFORMATION, "Added Include", "ValueSet.compose.include"), r));
|
res.getIncludes().getChildren().add(new StructuralMatch<Element>(vmI(IssueSeverity.INFORMATION, "Added Include", "ValueSet.compose.include"), r));
|
||||||
if (session.isAnnotate()) {
|
VersionComparisonAnnotation.markAdded(r, session.getForVersion());
|
||||||
VersionComparisonAnnotation.markAdded(r, session.getForVersion());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,6 +251,9 @@ public class ValueSetComparer extends CanonicalResourceComparer {
|
||||||
union.getValueSet().add(l);
|
union.getValueSet().add(l);
|
||||||
res.updateContentState(true);
|
res.updateContentState(true);
|
||||||
combined.getChildren().add(new StructuralMatch<Element>(l, vmI(IssueSeverity.INFORMATION, "Removed ValueSet", "ValueSet.compose.include.valueSet")));
|
combined.getChildren().add(new StructuralMatch<Element>(l, vmI(IssueSeverity.INFORMATION, "Removed ValueSet", "ValueSet.compose.include.valueSet")));
|
||||||
|
if (session.isAnnotate()) {
|
||||||
|
VersionComparisonAnnotation.markDeleted(right, session.getForVersion(), "valueset", l);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
matchVSR.add(r);
|
matchVSR.add(r);
|
||||||
if (l.getValue().equals(r.getValue())) {
|
if (l.getValue().equals(r.getValue())) {
|
||||||
|
@ -260,7 +267,11 @@ public class ValueSetComparer extends CanonicalResourceComparer {
|
||||||
union.getValueSet().add(r);
|
union.getValueSet().add(r);
|
||||||
res.updateContentState(true);
|
res.updateContentState(true);
|
||||||
StructuralMatch<Element> sm = new StructuralMatch<Element>(l, r, vmI(IssueSeverity.INFORMATION, "Values are different", "ValueSet.compose.include.valueSet"));
|
StructuralMatch<Element> sm = new StructuralMatch<Element>(l, r, vmI(IssueSeverity.INFORMATION, "Values are different", "ValueSet.compose.include.valueSet"));
|
||||||
combined.getChildren().add(sm);
|
combined.getChildren().add(sm);
|
||||||
|
if (session.isAnnotate()) {
|
||||||
|
VersionComparisonAnnotation.markChanged(r, session.getForVersion());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -268,7 +279,8 @@ public class ValueSetComparer extends CanonicalResourceComparer {
|
||||||
if (!matchVSR.contains(r)) {
|
if (!matchVSR.contains(r)) {
|
||||||
union.getValueSet().add(r);
|
union.getValueSet().add(r);
|
||||||
res.updateContentState(true);
|
res.updateContentState(true);
|
||||||
combined.getChildren().add(new StructuralMatch<Element>(vmI(IssueSeverity.INFORMATION, "Add ValueSet", "ValueSet.compose.include.valueSet"), r));
|
combined.getChildren().add(new StructuralMatch<Element>(vmI(IssueSeverity.INFORMATION, "Add ValueSet", "ValueSet.compose.include.valueSet"), r));
|
||||||
|
VersionComparisonAnnotation.markAdded(r, session.getForVersion());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,6 +291,7 @@ public class ValueSetComparer extends CanonicalResourceComparer {
|
||||||
union.getConcept().add(l);
|
union.getConcept().add(l);
|
||||||
res.updateContentState(true);
|
res.updateContentState(true);
|
||||||
combined.getChildren().add(new StructuralMatch<Element>(l, vmI(IssueSeverity.INFORMATION, "Removed this Concept", "ValueSet.compose.include.concept")));
|
combined.getChildren().add(new StructuralMatch<Element>(l, vmI(IssueSeverity.INFORMATION, "Removed this Concept", "ValueSet.compose.include.concept")));
|
||||||
|
VersionComparisonAnnotation.markDeleted(right, session.getForVersion(), "concept", l);
|
||||||
} else {
|
} else {
|
||||||
matchCR.add(r);
|
matchCR.add(r);
|
||||||
if (l.getCode().equals(r.getCode())) {
|
if (l.getCode().equals(r.getCode())) {
|
||||||
|
@ -297,6 +310,7 @@ public class ValueSetComparer extends CanonicalResourceComparer {
|
||||||
combined.getChildren().add(sm);
|
combined.getChildren().add(sm);
|
||||||
res.updateContentState(true);
|
res.updateContentState(true);
|
||||||
compareConcepts(l, r, sm, null, null);
|
compareConcepts(l, r, sm, null, null);
|
||||||
|
VersionComparisonAnnotation.markChanged(r, session.getForVersion());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -304,7 +318,8 @@ public class ValueSetComparer extends CanonicalResourceComparer {
|
||||||
if (!matchCR.contains(r)) {
|
if (!matchCR.contains(r)) {
|
||||||
union.getConcept().add(r);
|
union.getConcept().add(r);
|
||||||
res.updateContentState(true);
|
res.updateContentState(true);
|
||||||
combined.getChildren().add(new StructuralMatch<Element>(vmI(IssueSeverity.INFORMATION, "Added this Concept", "ValueSet.compose.include.concept"), r));
|
combined.getChildren().add(new StructuralMatch<Element>(vmI(IssueSeverity.INFORMATION, "Added this Concept", "ValueSet.compose.include.concept"), r));
|
||||||
|
VersionComparisonAnnotation.markAdded(r, session.getForVersion());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,6 +330,7 @@ public class ValueSetComparer extends CanonicalResourceComparer {
|
||||||
union.getFilter().add(l);
|
union.getFilter().add(l);
|
||||||
res.updateContentState(true);
|
res.updateContentState(true);
|
||||||
combined.getChildren().add(new StructuralMatch<Element>(l, vmI(IssueSeverity.INFORMATION, "Removed this item", "ValueSet.compose.include.filter")));
|
combined.getChildren().add(new StructuralMatch<Element>(l, vmI(IssueSeverity.INFORMATION, "Removed this item", "ValueSet.compose.include.filter")));
|
||||||
|
VersionComparisonAnnotation.markDeleted(right, session.getForVersion(), "filter", l);
|
||||||
} else {
|
} else {
|
||||||
matchFR.add(r);
|
matchFR.add(r);
|
||||||
if (l.getProperty().equals(r.getProperty()) && l.getOp().equals(r.getOp())) {
|
if (l.getProperty().equals(r.getProperty()) && l.getOp().equals(r.getOp())) {
|
||||||
|
@ -325,7 +341,8 @@ public class ValueSetComparer extends CanonicalResourceComparer {
|
||||||
StructuralMatch<Element> sm = new StructuralMatch<Element>(l, r);
|
StructuralMatch<Element> sm = new StructuralMatch<Element>(l, r);
|
||||||
combined.getChildren().add(sm);
|
combined.getChildren().add(sm);
|
||||||
if (!compareFilters(l, r, sm, cu, ci)) {
|
if (!compareFilters(l, r, sm, cu, ci)) {
|
||||||
res.updateContentState(true);
|
res.updateContentState(true);
|
||||||
|
VersionComparisonAnnotation.markChanged(r, session.getForVersion());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
union.getFilter().add(l);
|
union.getFilter().add(l);
|
||||||
|
@ -341,7 +358,8 @@ public class ValueSetComparer extends CanonicalResourceComparer {
|
||||||
if (!matchFR.contains(r)) {
|
if (!matchFR.contains(r)) {
|
||||||
union.getFilter().add(r);
|
union.getFilter().add(r);
|
||||||
res.updateContentState(true);
|
res.updateContentState(true);
|
||||||
combined.getChildren().add(new StructuralMatch<Element>(vmI(IssueSeverity.INFORMATION, "Added this item", "ValueSet.compose.include.filter"), r));
|
combined.getChildren().add(new StructuralMatch<Element>(vmI(IssueSeverity.INFORMATION, "Added this item", "ValueSet.compose.include.filter"), r));
|
||||||
|
VersionComparisonAnnotation.markAdded(r, session.getForVersion());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return def;
|
return def;
|
||||||
|
|
|
@ -1,69 +1,80 @@
|
||||||
package org.hl7.fhir.r5.comparison;
|
package org.hl7.fhir.r5.comparison;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.hl7.fhir.r5.comparison.CanonicalResourceComparer.CanonicalResourceComparison;
|
||||||
|
import org.hl7.fhir.r5.comparison.CanonicalResourceComparer.ChangeAnalysisState;
|
||||||
import org.hl7.fhir.r5.model.Base;
|
import org.hl7.fhir.r5.model.Base;
|
||||||
import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
|
import org.hl7.fhir.r5.model.CanonicalResource;
|
||||||
import org.hl7.fhir.r5.model.ValueSet.ValueSetComposeComponent;
|
import org.hl7.fhir.r5.model.ValueSet;
|
||||||
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
||||||
|
|
||||||
public class VersionComparisonAnnotation {
|
public class VersionComparisonAnnotation {
|
||||||
|
|
||||||
public enum AnotationType {
|
public enum AnotationType {
|
||||||
Added, Changed, Deleted;
|
NoChange, Added, Changed, Deleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final String USER_DATA_NAME = "version-annotation";
|
public static final String USER_DATA_NAME = "version-annotation";
|
||||||
|
|
||||||
private AnotationType type;
|
private AnotationType type;
|
||||||
// private String comment;
|
|
||||||
// private String link;
|
|
||||||
private Map<String, List<Base>> deletedChildren;
|
private Map<String, List<Base>> deletedChildren;
|
||||||
|
|
||||||
private String version;
|
private String version;
|
||||||
|
|
||||||
|
private CanonicalResourceComparison<? extends CanonicalResource> comp;
|
||||||
|
|
||||||
private VersionComparisonAnnotation(AnotationType type, String version) {
|
private VersionComparisonAnnotation(AnotationType type, String version) {
|
||||||
super();
|
super();
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.version = version;
|
this.version = version;
|
||||||
}
|
}
|
||||||
//
|
|
||||||
// private VersionComparisonAnnotation(AnotationType type, String comment) {
|
|
||||||
// super();
|
public static void annotate(Base base, String version, CanonicalResourceComparison<? extends CanonicalResource> comp) {
|
||||||
// this.type = type;
|
if (version != null) {
|
||||||
// this.comment = comment;
|
VersionComparisonAnnotation vca = new VersionComparisonAnnotation(comp.noChange() ? AnotationType.NoChange : AnotationType.Added, version);
|
||||||
// }
|
vca.comp = comp;
|
||||||
// private VersionComparisonAnnotation(AnotationType type, String comment, String link) {
|
base.setUserData(USER_DATA_NAME, vca);
|
||||||
// super();
|
}
|
||||||
// this.type = type;
|
}
|
||||||
// this.comment = comment;
|
|
||||||
// this.link = link;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
public static void markAdded(Base focus, String version) {
|
public static void markAdded(Base focus, String version) {
|
||||||
focus.setUserData(USER_DATA_NAME, new VersionComparisonAnnotation(AnotationType.Added, version));
|
if (version != null) {
|
||||||
|
focus.setUserData(USER_DATA_NAME, new VersionComparisonAnnotation(AnotationType.Added, version));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void markChanged(Base focus, String version) {
|
||||||
|
if (version != null) {
|
||||||
|
focus.setUserData(USER_DATA_NAME, new VersionComparisonAnnotation(AnotationType.Changed, version));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void markDeleted(Base parent, String version, String name, Base other) {
|
public static void markDeleted(Base parent, String version, String name, Base other) {
|
||||||
VersionComparisonAnnotation vca = null;
|
if (version != null) {
|
||||||
if (parent.hasUserData(USER_DATA_NAME)) {
|
VersionComparisonAnnotation vca = null;
|
||||||
vca = (VersionComparisonAnnotation) parent.getUserData(USER_DATA_NAME);
|
if (parent.hasUserData(USER_DATA_NAME)) {
|
||||||
assert vca.type != AnotationType.Added;
|
vca = (VersionComparisonAnnotation) parent.getUserData(USER_DATA_NAME);
|
||||||
} else {
|
assert vca.type != AnotationType.Added;
|
||||||
vca = new VersionComparisonAnnotation(AnotationType.Changed, version);
|
} else {
|
||||||
parent.setUserData(USER_DATA_NAME, vca);
|
vca = new VersionComparisonAnnotation(AnotationType.Changed, version);
|
||||||
|
parent.setUserData(USER_DATA_NAME, vca);
|
||||||
|
}
|
||||||
|
if (vca.deletedChildren == null) {
|
||||||
|
vca.deletedChildren = new HashMap<>();
|
||||||
|
}
|
||||||
|
if (!vca.deletedChildren.containsKey(name)) {
|
||||||
|
vca.deletedChildren.put(name, new ArrayList<>());
|
||||||
|
}
|
||||||
|
other.setUserData(USER_DATA_NAME, new VersionComparisonAnnotation(AnotationType.Deleted, version));
|
||||||
|
vca.deletedChildren.get(name).add(other);
|
||||||
}
|
}
|
||||||
if (vca.deletedChildren == null) {
|
|
||||||
vca.deletedChildren = new HashMap<>();
|
|
||||||
}
|
|
||||||
if (!vca.deletedChildren.containsKey(name)) {
|
|
||||||
vca.deletedChildren.put(name, new ArrayList<>());
|
|
||||||
}
|
|
||||||
other.setUserData(USER_DATA_NAME, new VersionComparisonAnnotation(AnotationType.Deleted, version));
|
|
||||||
vca.deletedChildren.get(name).add(other);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public AnotationType getType() {
|
public AnotationType getType() {
|
||||||
|
@ -73,19 +84,6 @@ public class VersionComparisonAnnotation {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
// public String getComment() {
|
|
||||||
// return comment;
|
|
||||||
// }
|
|
||||||
// public void setComment(String comment) {
|
|
||||||
// this.comment = comment;
|
|
||||||
// }
|
|
||||||
// public String getLink() {
|
|
||||||
// return link;
|
|
||||||
// }
|
|
||||||
// public void setLink(String link) {
|
|
||||||
// this.link = link;
|
|
||||||
// }
|
|
||||||
|
|
||||||
public static XhtmlNode render(Base b, XhtmlNode x) {
|
public static XhtmlNode render(Base b, XhtmlNode x) {
|
||||||
if (b.hasUserData(USER_DATA_NAME)) {
|
if (b.hasUserData(USER_DATA_NAME)) {
|
||||||
VersionComparisonAnnotation self = (VersionComparisonAnnotation) b.getUserData(USER_DATA_NAME);
|
VersionComparisonAnnotation self = (VersionComparisonAnnotation) b.getUserData(USER_DATA_NAME);
|
||||||
|
@ -98,20 +96,57 @@ public class VersionComparisonAnnotation {
|
||||||
private XhtmlNode render(XhtmlNode x) {
|
private XhtmlNode render(XhtmlNode x) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Added:
|
case Added:
|
||||||
XhtmlNode span = x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This content has been added since "+version);
|
XhtmlNode spanOuter = x.span("border: solid 1px #dddddd; margin: 2px; padding: 2px", null);
|
||||||
span.img("icon-change-add.png", "icon");
|
XhtmlNode spanInner = spanOuter.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This content has been added since "+version);
|
||||||
span.tx(" Added:");
|
spanInner.img("icon-change-add.png", "icon");
|
||||||
return x;
|
spanInner.tx(" Added:");
|
||||||
|
return spanOuter;
|
||||||
case Changed:
|
case Changed:
|
||||||
span = x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This content has been changed since version "+version);
|
spanOuter = x.span("border: solid 1px #dddddd; margin: 2px; padding: 2px", null);
|
||||||
span.img("icon-change-edit.png", "icon");
|
spanInner = spanOuter.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This content has been added since "+version);
|
||||||
span.tx(" Changed:");
|
spanInner.img("icon-change-edit.png", "icon");
|
||||||
return x;
|
spanInner.tx(" Changed:");
|
||||||
|
return spanOuter;
|
||||||
case Deleted:
|
case Deleted:
|
||||||
span = x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This content has been removed since version "+version);
|
spanOuter = x.span("border: solid 1px #dddddd; margin: 2px; padding: 2px", null);
|
||||||
span.img("icon-change-remove.png", "icon");
|
spanInner = spanOuter.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This content has been added since "+version);
|
||||||
span.tx(" Removed:");
|
spanInner.img("icon-change-remove.png", "icon");
|
||||||
return x.strikethrough();
|
spanInner.tx(" Removed:");
|
||||||
|
return spanOuter.strikethrough();
|
||||||
|
default:
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static XhtmlNode renderDiv(Base b, XhtmlNode x) {
|
||||||
|
if (b.hasUserData(USER_DATA_NAME)) {
|
||||||
|
VersionComparisonAnnotation self = (VersionComparisonAnnotation) b.getUserData(USER_DATA_NAME);
|
||||||
|
return self.renderDiv(x);
|
||||||
|
} else {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private XhtmlNode renderDiv(XhtmlNode x) {
|
||||||
|
switch (type) {
|
||||||
|
case Added:
|
||||||
|
XhtmlNode divOuter = x.div("border: solid 1px #dddddd; margin: 2px; padding: 2px");
|
||||||
|
XhtmlNode spanInner = divOuter.para().style("margin: 0").span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This content has been added since "+version);
|
||||||
|
spanInner.img("icon-change-add.png", "icon");
|
||||||
|
spanInner.tx(" Added:");
|
||||||
|
return divOuter;
|
||||||
|
case Changed:
|
||||||
|
divOuter = x.div("border: solid 1px #dddddd; margin: 2px; padding: 2px");
|
||||||
|
spanInner = divOuter.para().style("margin: 0").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.tx(" Changed:");
|
||||||
|
return divOuter;
|
||||||
|
case Deleted:
|
||||||
|
divOuter = x.div("border: solid 1px #dddddd; margin: 2px; padding: 2px");
|
||||||
|
spanInner = divOuter.para().style("margin: 0").span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This content has been added since "+version);
|
||||||
|
spanInner.img("icon-change-remove.png", "icon");
|
||||||
|
spanInner.tx(" Removed:");
|
||||||
|
return divOuter.strikethrough();
|
||||||
default:
|
default:
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
@ -142,5 +177,14 @@ public class VersionComparisonAnnotation {
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static CanonicalResourceComparison<? extends CanonicalResource> artifactComparison(Base base) {
|
||||||
|
if (base.hasUserData(USER_DATA_NAME)) {
|
||||||
|
VersionComparisonAnnotation self = (VersionComparisonAnnotation) base.getUserData(USER_DATA_NAME);
|
||||||
|
return self.comp;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1271,7 +1271,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
||||||
Parameters pIn = new Parameters();
|
Parameters pIn = new Parameters();
|
||||||
pIn.addParameter().setName("coding").setValue(coding);
|
pIn.addParameter().setName("coding").setValue(coding);
|
||||||
if (options.isGuessSystem()) {
|
if (options.isGuessSystem()) {
|
||||||
pIn.addParameter().setName("implySystem").setValue(new BooleanType(true));
|
pIn.addParameter().setName("inferSystem").setValue(new BooleanType(true));
|
||||||
}
|
}
|
||||||
setTerminologyOptions(options, pIn);
|
setTerminologyOptions(options, pIn);
|
||||||
return pIn;
|
return pIn;
|
||||||
|
@ -1288,7 +1288,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
||||||
Parameters pIn = new Parameters();
|
Parameters pIn = new Parameters();
|
||||||
pIn.addParameter().setName("coding").setValue(codingValidationRequest.getCoding());
|
pIn.addParameter().setName("coding").setValue(codingValidationRequest.getCoding());
|
||||||
if (options.isGuessSystem()) {
|
if (options.isGuessSystem()) {
|
||||||
pIn.addParameter().setName("implySystem").setValue(new BooleanType(true));
|
pIn.addParameter().setName("inferSystem").setValue(new BooleanType(true));
|
||||||
}
|
}
|
||||||
if (valueSet != null) {
|
if (valueSet != null) {
|
||||||
pIn.addParameter().setName("valueSet").setResource(valueSet);
|
pIn.addParameter().setName("valueSet").setResource(valueSet);
|
||||||
|
@ -1301,7 +1301,7 @@ public abstract class BaseWorkerContext extends I18nBase implements IWorkerConte
|
||||||
Parameters pIn = new Parameters();
|
Parameters pIn = new Parameters();
|
||||||
pIn.addParameter().setName("coding").setValue(codingValidationRequest.getCoding());
|
pIn.addParameter().setName("coding").setValue(codingValidationRequest.getCoding());
|
||||||
if (options.isGuessSystem()) {
|
if (options.isGuessSystem()) {
|
||||||
pIn.addParameter().setName("implySystem").setValue(new BooleanType(true));
|
pIn.addParameter().setName("inferSystem").setValue(new BooleanType(true));
|
||||||
}
|
}
|
||||||
if (vsUrl != null) {
|
if (vsUrl != null) {
|
||||||
pIn.addParameter().setName("url").setValue(new CanonicalType(vsUrl));
|
pIn.addParameter().setName("url").setValue(new CanonicalType(vsUrl));
|
||||||
|
|
|
@ -1344,7 +1344,7 @@ public class Element extends Base {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error("Unrecognised name "+name+" on "+this.name);
|
throw new Error("Unrecognised property '"+name+"' on "+this.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -9,9 +9,12 @@ 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.VersionComparisonAnnotation;
|
||||||
|
import org.hl7.fhir.r5.model.BooleanType;
|
||||||
import org.hl7.fhir.r5.model.CodeSystem;
|
import org.hl7.fhir.r5.model.CodeSystem;
|
||||||
import org.hl7.fhir.r5.model.Enumerations.CodeSystemContentMode;
|
import org.hl7.fhir.r5.model.Enumerations.CodeSystemContentMode;
|
||||||
import org.hl7.fhir.r5.model.CodeSystem.CodeSystemFilterComponent;
|
import org.hl7.fhir.r5.model.CodeSystem.CodeSystemFilterComponent;
|
||||||
|
import org.hl7.fhir.r5.model.CodeSystem.CodeSystemHierarchyMeaning;
|
||||||
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
|
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
|
||||||
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionDesignationComponent;
|
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionDesignationComponent;
|
||||||
import org.hl7.fhir.r5.model.CodeSystem.ConceptPropertyComponent;
|
import org.hl7.fhir.r5.model.CodeSystem.ConceptPropertyComponent;
|
||||||
|
@ -29,6 +32,7 @@ import org.hl7.fhir.r5.utils.ToolingExtensions;
|
||||||
import org.hl7.fhir.utilities.LoincLinker;
|
import org.hl7.fhir.utilities.LoincLinker;
|
||||||
import org.hl7.fhir.utilities.Utilities;
|
import org.hl7.fhir.utilities.Utilities;
|
||||||
import org.hl7.fhir.utilities.i18n.I18nConstants;
|
import org.hl7.fhir.utilities.i18n.I18nConstants;
|
||||||
|
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||||
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
||||||
|
|
||||||
public class CodeSystemRenderer extends TerminologyRenderer {
|
public class CodeSystemRenderer extends TerminologyRenderer {
|
||||||
|
@ -84,12 +88,12 @@ public class CodeSystemRenderer extends TerminologyRenderer {
|
||||||
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Value", getContext().getLang()));
|
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Value", getContext().getLang()));
|
||||||
for (CodeSystemFilterComponent f : cs.getFilter()) {
|
for (CodeSystemFilterComponent f : cs.getFilter()) {
|
||||||
tr = tbl.tr();
|
tr = tbl.tr();
|
||||||
tr.td().tx(f.getCode());
|
VersionComparisonAnnotation.render(f, tr.td()).tx(f.getCode());
|
||||||
tr.td().tx(f.getDescription());
|
VersionComparisonAnnotation.render(f.getDescriptionElement(), tr.td()).tx(f.getDescription());
|
||||||
XhtmlNode td = tr.td();
|
XhtmlNode td = tr.td();
|
||||||
for (Enumeration<org.hl7.fhir.r5.model.Enumerations.FilterOperator> t : f.getOperator())
|
for (Enumeration<org.hl7.fhir.r5.model.Enumerations.FilterOperator> t : f.getOperator())
|
||||||
td.tx(t.asStringValue()+" ");
|
VersionComparisonAnnotation.render(t, td).tx(t.asStringValue()+" ");
|
||||||
tr.td().tx(f.getValue());
|
VersionComparisonAnnotation.render(f.getValueElement(), tr.td()).tx(f.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,13 +129,13 @@ public class CodeSystemRenderer extends TerminologyRenderer {
|
||||||
if (hasRendered) {
|
if (hasRendered) {
|
||||||
tr.td().tx(ToolingExtensions.getPresentation(p, p.getCodeElement()));
|
tr.td().tx(ToolingExtensions.getPresentation(p, p.getCodeElement()));
|
||||||
}
|
}
|
||||||
tr.td().tx(p.getCode());
|
VersionComparisonAnnotation.render(p, tr.td()).tx(p.getCode());
|
||||||
if (hasURI) {
|
if (hasURI) {
|
||||||
tr.td().tx(p.getUri());
|
VersionComparisonAnnotation.render(p.getUriElement(), tr.td()).tx(p.getUri());
|
||||||
}
|
}
|
||||||
tr.td().tx(p.hasType() ? p.getType().toCode() : "");
|
VersionComparisonAnnotation.render(p.getTypeElement(), tr.td()).tx(p.hasType() ? p.getType().toCode() : "");
|
||||||
if (hasDescription) {
|
if (hasDescription) {
|
||||||
tr.td().tx(p.getDescription());
|
VersionComparisonAnnotation.render(p.getDescriptionElement(), tr.td()).tx(p.getDescription());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -160,8 +164,9 @@ public class CodeSystemRenderer extends TerminologyRenderer {
|
||||||
features = "features"; // ?
|
features = "features"; // ?
|
||||||
}
|
}
|
||||||
return context.getContext().formatMessage(I18nConstants.RND_CS_CONTENT_SUPPLEMENT, features);
|
return context.getContext().formatMessage(I18nConstants.RND_CS_CONTENT_SUPPLEMENT, features);
|
||||||
|
default:
|
||||||
|
throw new FHIRException("Unknown CodeSystemContentMode mode");
|
||||||
}
|
}
|
||||||
throw new FHIRException("Unknown CodeSystemContentMode mode");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean generateCodeSystemContent(XhtmlNode x, CodeSystem cs, boolean hasExtensions, List<UsedConceptMap> maps, boolean props) throws FHIRFormatError, DefinitionException, IOException {
|
private boolean generateCodeSystemContent(XhtmlNode x, CodeSystem cs, boolean hasExtensions, List<UsedConceptMap> maps, boolean props) throws FHIRFormatError, DefinitionException, IOException {
|
||||||
|
@ -169,7 +174,10 @@ public class CodeSystemRenderer extends TerminologyRenderer {
|
||||||
x.para().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Concepts", getContext().getLang()));
|
x.para().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Concepts", getContext().getLang()));
|
||||||
}
|
}
|
||||||
XhtmlNode p = x.para();
|
XhtmlNode p = x.para();
|
||||||
p.param("cs").code().tx(cs.getUrl());
|
VersionComparisonAnnotation.render(cs.getUrlElement(), p.param("cs")).code().tx(cs.getUrl());
|
||||||
|
makeCasedParam(p.param("cased"), cs, cs.getCaseSensitiveElement());
|
||||||
|
makeHierarchyParam(p.param("h"), cs, cs.getHierarchyMeaningElement());
|
||||||
|
|
||||||
p.paramValue("code-count", CodeSystemUtilities.countCodes(cs));
|
p.paramValue("code-count", CodeSystemUtilities.countCodes(cs));
|
||||||
p.sentenceForParams(sentenceForContent(cs.getContent(), cs));
|
p.sentenceForParams(sentenceForContent(cs.getContent(), cs));
|
||||||
if (cs.getContent() == CodeSystemContentMode.NOTPRESENT) {
|
if (cs.getContent() == CodeSystemContentMode.NOTPRESENT) {
|
||||||
|
@ -236,6 +244,30 @@ public class CodeSystemRenderer extends TerminologyRenderer {
|
||||||
return hasExtensions;
|
return hasExtensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void makeHierarchyParam(XhtmlNode x, CodeSystem cs, Enumeration<CodeSystemHierarchyMeaning> hm) {
|
||||||
|
if (hm.hasValue()) {
|
||||||
|
String s = hm.getValue().getDisplay();
|
||||||
|
VersionComparisonAnnotation.render(hm, x).tx(" in a "+s+" heirarchy");
|
||||||
|
} else if (VersionComparisonAnnotation.hasDeleted(cs, "hierarchyMeaning")) {
|
||||||
|
makeHierarchyParam(x, null, (Enumeration<CodeSystemHierarchyMeaning>) VersionComparisonAnnotation.getDeleted(cs, "hierarchyMeaning").get(0));
|
||||||
|
} else if (CodeSystemUtilities.hasHierarchy(cs)) {
|
||||||
|
x.tx(" in an undefined heirarchy");
|
||||||
|
} else {
|
||||||
|
x.tx("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void makeCasedParam(XhtmlNode x, CodeSystem cs, BooleanType caseSensitiveElement) {
|
||||||
|
if (caseSensitiveElement.hasValue()) {
|
||||||
|
String s = caseSensitiveElement.getValue() == true? "case-sensitive" : "case-insensitive";
|
||||||
|
VersionComparisonAnnotation.render(caseSensitiveElement, x).tx(s);
|
||||||
|
} else if (VersionComparisonAnnotation.hasDeleted(cs, "caseSensitive")) {
|
||||||
|
makeCasedParam(x, null, (BooleanType) VersionComparisonAnnotation.getDeleted(cs, "caseSensitive").get(0));
|
||||||
|
} else {
|
||||||
|
x.tx("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void listConceptLanguages(CodeSystem cs, ConceptDefinitionComponent c, List<String> langs) {
|
private void listConceptLanguages(CodeSystem cs, ConceptDefinitionComponent c, List<String> langs) {
|
||||||
for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) {
|
for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) {
|
||||||
if (cd.hasLanguage() && !langs.contains(cd.getLanguage()) && (!cs.hasLanguage() || !cs.getLanguage().equals(cd.getLanguage()))) {
|
if (cd.hasLanguage() && !langs.contains(cd.getLanguage()) && (!cs.hasLanguage() || !cs.getLanguage().equals(cd.getLanguage()))) {
|
||||||
|
@ -377,7 +409,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
|
||||||
if (link != null) {
|
if (link != null) {
|
||||||
td.ah(link).attribute("style", "white-space:nowrap").addText(c.getCode());
|
td.ah(link).attribute("style", "white-space:nowrap").addText(c.getCode());
|
||||||
} else {
|
} else {
|
||||||
td.attribute("style", "white-space:nowrap").addText(c.getCode());
|
VersionComparisonAnnotation.render(c, td.attribute("style", "white-space:nowrap")).addText(c.getCode());
|
||||||
}
|
}
|
||||||
XhtmlNode a;
|
XhtmlNode a;
|
||||||
if (c.hasCodeElement()) {
|
if (c.hasCodeElement()) {
|
||||||
|
@ -390,13 +422,13 @@ public class CodeSystemRenderer extends TerminologyRenderer {
|
||||||
}
|
}
|
||||||
if (hasDefinitions) {
|
if (hasDefinitions) {
|
||||||
td = tr.td();
|
td = tr.td();
|
||||||
if (c != null &&
|
if (c != null &&c.hasDefinitionElement()) {
|
||||||
c.hasDefinitionElement()) {
|
|
||||||
if (getContext().getLang() == null) {
|
if (getContext().getLang() == null) {
|
||||||
if (hasMarkdownInDefinitions(cs))
|
if (hasMarkdownInDefinitions(cs)) {
|
||||||
addMarkdown(td, c.getDefinition());
|
addMarkdown(VersionComparisonAnnotation.renderDiv(c.getDefinitionElement(), td), c.getDefinition());
|
||||||
else
|
} else {
|
||||||
td.addText(c.getDefinition());
|
VersionComparisonAnnotation.render(c.getDefinitionElement(), td).addText(c.getDefinition());
|
||||||
|
}
|
||||||
} else if (getContext().getLang().equals("*")) {
|
} else if (getContext().getLang().equals("*")) {
|
||||||
boolean sl = false;
|
boolean sl = false;
|
||||||
for (ConceptDefinitionDesignationComponent cd : c.getDesignation())
|
for (ConceptDefinitionDesignationComponent cd : c.getDesignation())
|
||||||
|
@ -404,9 +436,9 @@ public class CodeSystemRenderer extends TerminologyRenderer {
|
||||||
sl = true;
|
sl = true;
|
||||||
td.addText((sl ? cs.getLanguage("en")+": " : ""));
|
td.addText((sl ? cs.getLanguage("en")+": " : ""));
|
||||||
if (hasMarkdownInDefinitions(cs))
|
if (hasMarkdownInDefinitions(cs))
|
||||||
addMarkdown(td, c.getDefinition());
|
addMarkdown(VersionComparisonAnnotation.renderDiv(c.getDefinitionElement(), td), c.getDefinition());
|
||||||
else
|
else
|
||||||
td.addText(c.getDefinition());
|
VersionComparisonAnnotation.render(c.getDefinitionElement(), td).addText(c.getDefinition());
|
||||||
for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) {
|
for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) {
|
||||||
if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && !c.getDefinition().equalsIgnoreCase(cd.getValue())) {
|
if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && !c.getDefinition().equalsIgnoreCase(cd.getValue())) {
|
||||||
td.br();
|
td.br();
|
||||||
|
@ -414,7 +446,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (getContext().getLang().equals(cs.getLanguage()) || (getContext().getLang().equals("en") && !cs.hasLanguage())) {
|
} else if (getContext().getLang().equals(cs.getLanguage()) || (getContext().getLang().equals("en") && !cs.hasLanguage())) {
|
||||||
td.addText(c.getDefinition());
|
VersionComparisonAnnotation.render(c.getDefinitionElement(), td).addText(c.getDefinition());
|
||||||
} else {
|
} else {
|
||||||
for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) {
|
for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) {
|
||||||
if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && cd.getLanguage().equals(getContext().getLang())) {
|
if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && cd.getLanguage().equals(getContext().getLang())) {
|
||||||
|
@ -591,7 +623,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
|
||||||
public void renderDisplayName(ConceptDefinitionComponent c, CodeSystem cs, XhtmlNode td) {
|
public void renderDisplayName(ConceptDefinitionComponent c, CodeSystem cs, XhtmlNode td) {
|
||||||
if (c.hasDisplayElement()) {
|
if (c.hasDisplayElement()) {
|
||||||
if (getContext().getLang() == null) {
|
if (getContext().getLang() == null) {
|
||||||
td.addText(c.getDisplay());
|
VersionComparisonAnnotation.render(c.getDisplayElement(), td).addText(c.getDisplay());
|
||||||
} else if (getContext().getLang().equals("*")) {
|
} else if (getContext().getLang().equals("*")) {
|
||||||
boolean sl = false;
|
boolean sl = false;
|
||||||
for (ConceptDefinitionDesignationComponent cd : c.getDesignation())
|
for (ConceptDefinitionDesignationComponent cd : c.getDesignation())
|
||||||
|
@ -605,7 +637,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (getContext().getLang().equals(cs.getLanguage()) || (getContext().getLang().equals("en") && !cs.hasLanguage())) {
|
} else if (getContext().getLang().equals(cs.getLanguage()) || (getContext().getLang().equals("en") && !cs.hasLanguage())) {
|
||||||
td.addText(c.getDisplay());
|
VersionComparisonAnnotation.render(c.getDisplayElement(), td).addText(c.getDisplay());
|
||||||
} else {
|
} else {
|
||||||
for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) {
|
for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) {
|
||||||
if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "display") && cd.hasLanguage() && cd.getLanguage().equals(getContext().getLang())) {
|
if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "display") && cd.hasLanguage() && cd.getLanguage().equals(getContext().getLang())) {
|
||||||
|
|
|
@ -2727,30 +2727,24 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
|
||||||
return ed.getPath().substring(ed.getPath().indexOf(".")+1);
|
return ed.getPath().substring(ed.getPath().indexOf(".")+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String formatTypeSpecifiers(IWorkerContext context, ElementDefinition d) {
|
public XhtmlNode formatTypeSpecifiers(IWorkerContext context, ElementDefinition d) {
|
||||||
StringBuilder b = new StringBuilder();
|
XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
for (Extension e : d.getExtensionsByUrl(ToolingExtensions.EXT_TYPE_SPEC)) {
|
for (Extension e : d.getExtensionsByUrl(ToolingExtensions.EXT_TYPE_SPEC)) {
|
||||||
if (first) first = false; else b.append("<br/>");
|
if (first) first = false; else x.br();
|
||||||
String cond = ToolingExtensions.readStringExtension(e, "condition");
|
String cond = ToolingExtensions.readStringExtension(e, "condition");
|
||||||
String type = ToolingExtensions.readStringExtension(e, "type");
|
String type = ToolingExtensions.readStringExtension(e, "type");
|
||||||
b.append("If <code>");
|
x.tx("If ");
|
||||||
b.append(Utilities.escapeXml(cond));
|
x.code().tx(cond);
|
||||||
b.append("</code> then the type is ");
|
x.tx(" then the type is ");
|
||||||
StructureDefinition sd = context.fetchTypeDefinition(type);
|
StructureDefinition sd = context.fetchTypeDefinition(type);
|
||||||
if (sd == null) {
|
if (sd == null) {
|
||||||
b.append("<code>");
|
x.code().tx(type);
|
||||||
b.append(Utilities.escapeXml(type));
|
|
||||||
b.append("</code>");
|
|
||||||
} else {
|
} else {
|
||||||
b.append("<a href=\"");
|
x.ah(sd.getWebPath()).tx(sd.getTypeName());
|
||||||
b.append(sd.getWebPath());
|
|
||||||
b.append("\">");
|
|
||||||
b.append(Utilities.escapeXml(sd.getTypeName()));
|
|
||||||
b.append("</a>");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return b.toString();
|
return first ? null : x;
|
||||||
}
|
}
|
||||||
|
|
||||||
public XhtmlNode generateExtensionTable(String defFile, StructureDefinition ed, String imageFolder, boolean inlineGraphics, boolean full, String corePath, String imagePath, Set<String> outputTracker, RenderingContext rc) throws IOException, FHIRException {
|
public XhtmlNode generateExtensionTable(String defFile, StructureDefinition ed, String imageFolder, boolean inlineGraphics, boolean full, String corePath, String imagePath, Set<String> outputTracker, RenderingContext rc) throws IOException, FHIRException {
|
||||||
|
|
|
@ -1234,33 +1234,34 @@ public class ValueSetRenderer extends TerminologyRenderer {
|
||||||
li.tx(", ");
|
li.tx(", ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
XhtmlNode wli = VersionComparisonAnnotation.render(f, li);
|
||||||
if (f.getOp() == FilterOperator.EXISTS) {
|
if (f.getOp() == FilterOperator.EXISTS) {
|
||||||
if (f.getValue().equals("true")) {
|
if (f.getValue().equals("true")) {
|
||||||
li.tx(f.getProperty()+" exists");
|
wli.tx(f.getProperty()+" exists");
|
||||||
} else {
|
} else {
|
||||||
li.tx(f.getProperty()+" doesn't exist");
|
wli.tx(f.getProperty()+" doesn't exist");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
li.tx(f.getProperty()+" "+describe(f.getOp())+" ");
|
wli.tx(f.getProperty()+" "+describe(f.getOp())+" ");
|
||||||
if (e != null && codeExistsInValueSet(e, f.getValue())) {
|
if (e != null && codeExistsInValueSet(e, f.getValue())) {
|
||||||
String href = getContext().fixReference(getCsRef(e));
|
String href = getContext().fixReference(getCsRef(e));
|
||||||
if (href.contains("#"))
|
if (href.contains("#"))
|
||||||
href = href + "-"+Utilities.nmtokenize(f.getValue());
|
href = href + "-"+Utilities.nmtokenize(f.getValue());
|
||||||
else
|
else
|
||||||
href = href + "#"+e.getId()+"-"+Utilities.nmtokenize(f.getValue());
|
href = href + "#"+e.getId()+"-"+Utilities.nmtokenize(f.getValue());
|
||||||
li.ah(href).addText(f.getValue());
|
wli.ah(href).addText(f.getValue());
|
||||||
} else if ("concept".equals(f.getProperty()) && inc.hasSystem()) {
|
} else if ("concept".equals(f.getProperty()) && inc.hasSystem()) {
|
||||||
li.addText(f.getValue());
|
wli.addText(f.getValue());
|
||||||
ValidationResult vr = getContext().getWorker().validateCode(getContext().getTerminologyServiceOptions(), inc.getSystem(), inc.getVersion(), f.getValue(), null);
|
ValidationResult vr = getContext().getWorker().validateCode(getContext().getTerminologyServiceOptions(), inc.getSystem(), inc.getVersion(), f.getValue(), null);
|
||||||
if (vr.isOk()) {
|
if (vr.isOk()) {
|
||||||
li.tx(" ("+vr.getDisplay()+")");
|
wli.tx(" ("+vr.getDisplay()+")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
li.addText(f.getValue());
|
wli.addText(f.getValue());
|
||||||
String disp = ToolingExtensions.getDisplayHint(f);
|
String disp = ToolingExtensions.getDisplayHint(f);
|
||||||
if (disp != null)
|
if (disp != null)
|
||||||
li.tx(" ("+disp+")");
|
wli.tx(" ("+disp+")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1273,7 +1274,8 @@ public class ValueSetRenderer extends TerminologyRenderer {
|
||||||
first = false;
|
first = false;
|
||||||
else
|
else
|
||||||
li.tx(", ");
|
li.tx(", ");
|
||||||
AddVsRef(vs.asStringValue(), li, vsRes);
|
XhtmlNode wli = VersionComparisonAnnotation.render(vs, li);
|
||||||
|
AddVsRef(vs.asStringValue(), wli, vsRes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (inc.hasExtension(ToolingExtensions.EXT_EXPAND_RULES) || inc.hasExtension(ToolingExtensions.EXT_EXPAND_GROUP)) {
|
if (inc.hasExtension(ToolingExtensions.EXT_EXPAND_RULES) || inc.hasExtension(ToolingExtensions.EXT_EXPAND_GROUP)) {
|
||||||
|
@ -1289,12 +1291,14 @@ public class ValueSetRenderer extends TerminologyRenderer {
|
||||||
first = false;
|
first = false;
|
||||||
else
|
else
|
||||||
li.tx(", ");
|
li.tx(", ");
|
||||||
AddVsRef(vs.asStringValue(), li, vsRes);
|
XhtmlNode wli = VersionComparisonAnnotation.render(vs, li);
|
||||||
|
AddVsRef(vs.asStringValue(), wli, vsRes);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
XhtmlNode xul = li.ul();
|
XhtmlNode xul = li.ul();
|
||||||
for (UriType vs : inc.getValueSet()) {
|
for (UriType vs : inc.getValueSet()) {
|
||||||
AddVsRef(vs.asStringValue(), xul.li(), vsRes);
|
XhtmlNode wli = VersionComparisonAnnotation.render(vs, xul.li());
|
||||||
|
AddVsRef(vs.asStringValue(), wli, vsRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -244,10 +244,10 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
||||||
}
|
}
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
msg = context.formatMessage(I18nConstants.UNABLE_TO_CHECK_IF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_, valueset.getVersionedUrl(), b.toString());
|
msg = context.formatMessage(I18nConstants.UNABLE_TO_CHECK_IF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_, valueset.getVersionedUrl(), b.toString());
|
||||||
info.getIssues().addAll(makeIssue(IssueSeverity.WARNING, unknownSystems.isEmpty() ? IssueType.INVALID : 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.INVALID : IssueType.NOTFOUND, path, msg));
|
info.getIssues().addAll(makeIssue(IssueSeverity.ERROR, unknownSystems.isEmpty() ? IssueType.CODEINVALID : IssueType.NOTFOUND, path, msg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (info.hasErrors()) {
|
if (info.hasErrors()) {
|
||||||
|
@ -488,7 +488,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
||||||
// {
|
// {
|
||||||
String msg = context.formatMessagePlural(1, I18nConstants.NONE_OF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_, valueset.getVersionedUrl(), code.toString());
|
String msg = context.formatMessagePlural(1, I18nConstants.NONE_OF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_, valueset.getVersionedUrl(), code.toString());
|
||||||
res.addToMessage(msg).setSeverity(IssueSeverity.ERROR);
|
res.addToMessage(msg).setSeverity(IssueSeverity.ERROR);
|
||||||
res.getIssues().addAll(makeIssue(IssueSeverity.ERROR, IssueType.INVALID, path, msg));
|
res.getIssues().addAll(makeIssue(IssueSeverity.ERROR, IssueType.CODEINVALID, path, msg));
|
||||||
res.setDefinition(null);
|
res.setDefinition(null);
|
||||||
res.setSystem(null);
|
res.setSystem(null);
|
||||||
res.setDisplay(null);
|
res.setDisplay(null);
|
||||||
|
@ -507,7 +507,7 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
||||||
} else if ((res != null && !res.isOk())) {
|
} else if ((res != null && !res.isOk())) {
|
||||||
String msg = context.formatMessagePlural(1, I18nConstants.NONE_OF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_, valueset.getVersionedUrl(), code.toString());
|
String msg = context.formatMessagePlural(1, I18nConstants.NONE_OF_THE_PROVIDED_CODES_ARE_IN_THE_VALUE_SET_, valueset.getVersionedUrl(), code.toString());
|
||||||
res.setMessage(res.getMessage()+"; "+msg);
|
res.setMessage(res.getMessage()+"; "+msg);
|
||||||
res.getIssues().addAll(makeIssue(IssueSeverity.ERROR, IssueType.INVALID, path, msg));
|
res.getIssues().addAll(makeIssue(IssueSeverity.ERROR, IssueType.CODEINVALID, path, msg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (res != null && res.getSeverity() == IssueSeverity.INFORMATION) {
|
if (res != null && res.getSeverity() == IssueSeverity.INFORMATION) {
|
||||||
|
@ -638,10 +638,10 @@ public class ValueSetValidator extends ValueSetProcessBase {
|
||||||
if (cc == null) {
|
if (cc == null) {
|
||||||
if (cs.getContent() == CodeSystemContentMode.FRAGMENT) {
|
if (cs.getContent() == CodeSystemContentMode.FRAGMENT) {
|
||||||
String msg = context.formatMessage(I18nConstants.UNKNOWN_CODE__IN_FRAGMENT, code.getCode(), cs.getUrl());
|
String msg = context.formatMessage(I18nConstants.UNKNOWN_CODE__IN_FRAGMENT, code.getCode(), cs.getUrl());
|
||||||
return new ValidationResult(IssueSeverity.WARNING, msg, makeIssue(IssueSeverity.ERROR, IssueType.INVALID, path+".code", msg));
|
return new ValidationResult(IssueSeverity.WARNING, msg, makeIssue(IssueSeverity.ERROR, IssueType.CODEINVALID, path+".code", msg));
|
||||||
} else {
|
} else {
|
||||||
String msg = context.formatMessage(I18nConstants.UNKNOWN_CODE__IN_, code.getCode(), cs.getUrl());
|
String msg = context.formatMessage(I18nConstants.UNKNOWN_CODE__IN_, code.getCode(), cs.getUrl());
|
||||||
return new ValidationResult(IssueSeverity.ERROR, msg, makeIssue(IssueSeverity.ERROR, IssueType.INVALID, path+".code", msg));
|
return new ValidationResult(IssueSeverity.ERROR, msg, makeIssue(IssueSeverity.ERROR, IssueType.CODEINVALID, path+".code", msg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Coding vc = new Coding().setCode(cc.getCode()).setSystem(cs.getUrl()).setVersion(cs.getVersion()).setDisplay(getPreferredDisplay(cc, cs));
|
Coding vc = new Coding().setCode(cc.getCode()).setSystem(cs.getUrl()).setVersion(cs.getVersion()).setDisplay(getPreferredDisplay(cc, cs));
|
||||||
|
@ -698,10 +698,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.INVALID, path+".display", msg));
|
return new ValidationResult(IssueSeverity.WARNING, msg, code.getSystem(), cs.getVersion(), cc, getPreferredDisplay(cc, cs), makeIssue(IssueSeverity.WARNING, IssueType.CODEINVALID, 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.INVALID, path+".display", msg));
|
return new ValidationResult(dispWarningStatus(), msg, code.getSystem(), cs.getVersion(), cc, getPreferredDisplay(cc, cs), makeIssue(dispWarning(), IssueType.CODEINVALID, path+".display", msg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -316,7 +316,7 @@ public class CompareUtilities extends BaseTestingUtilities {
|
||||||
if (i == expectedArray.size() - 1 && isOptional(expectedArray.get(i))) {
|
if (i == expectedArray.size() - 1 && isOptional(expectedArray.get(i))) {
|
||||||
return null; // this is OK
|
return null; // this is OK
|
||||||
} else {
|
} else {
|
||||||
return "One or more array items did not match at "+path;
|
return "One or more array items did not match at "+path+" starting at index "+i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
String s = compareNodes(path + "[" + Integer.toString(i) + "]", expectedArray.get(i), actualArray.get(c));
|
String s = compareNodes(path + "[" + Integer.toString(i) + "]", expectedArray.get(i), actualArray.get(c));
|
||||||
|
|
|
@ -54,21 +54,24 @@ public class DefinitionNavigator {
|
||||||
private List<String> names = new ArrayList<String>();
|
private List<String> names = new ArrayList<String>();
|
||||||
private TypeRefComponent typeOfChildren;
|
private TypeRefComponent typeOfChildren;
|
||||||
private String path;
|
private String path;
|
||||||
|
private boolean diff;
|
||||||
|
|
||||||
public DefinitionNavigator(IWorkerContext context, StructureDefinition structure) throws DefinitionException {
|
public DefinitionNavigator(IWorkerContext context, StructureDefinition structure, boolean diff) throws DefinitionException {
|
||||||
if (!structure.hasSnapshot())
|
if (!diff && !structure.hasSnapshot())
|
||||||
throw new DefinitionException("Snapshot required");
|
throw new DefinitionException("Snapshot required");
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.structure = structure;
|
this.structure = structure;
|
||||||
this.index = 0;
|
this.index = 0;
|
||||||
|
this.diff = diff;
|
||||||
this.path = current().getPath();
|
this.path = current().getPath();
|
||||||
names.add(nameTail());
|
names.add(nameTail());
|
||||||
}
|
}
|
||||||
|
|
||||||
private DefinitionNavigator(IWorkerContext context, StructureDefinition structure, int index, String path, List<String> names, String type) {
|
private DefinitionNavigator(IWorkerContext context, StructureDefinition structure, boolean diff, int index, String path, List<String> names, String type) {
|
||||||
this.path = path;
|
this.path = path;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.structure = structure;
|
this.structure = structure;
|
||||||
|
this.diff = diff;
|
||||||
this.index = index;
|
this.index = index;
|
||||||
if (type == null)
|
if (type == null)
|
||||||
for (String name : names)
|
for (String name : names)
|
||||||
|
@ -96,8 +99,16 @@ public class DefinitionNavigator {
|
||||||
public List<String> getNames() {
|
public List<String> getNames() {
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<ElementDefinition> list() {
|
||||||
|
if (diff) {
|
||||||
|
return structure.getDifferential().getElement();
|
||||||
|
} else {
|
||||||
|
return structure.getSnapshot().getElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
public ElementDefinition current() {
|
public ElementDefinition current() {
|
||||||
return structure.getSnapshot().getElement().get(index);
|
return list().get(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<DefinitionNavigator> slices() throws DefinitionException {
|
public List<DefinitionNavigator> slices() throws DefinitionException {
|
||||||
|
@ -119,14 +130,15 @@ public class DefinitionNavigator {
|
||||||
String prefix = current().getPath()+".";
|
String prefix = current().getPath()+".";
|
||||||
Map<String, DefinitionNavigator> nameMap = new HashMap<String, DefinitionNavigator>();
|
Map<String, DefinitionNavigator> nameMap = new HashMap<String, DefinitionNavigator>();
|
||||||
|
|
||||||
for (int i = index + 1; i < structure.getSnapshot().getElement().size(); i++) {
|
for (int i = index + 1; i < list().size(); i++) {
|
||||||
String path = structure.getSnapshot().getElement().get(i).getPath();
|
String path = list().get(i).getPath();
|
||||||
if (path.startsWith(prefix) && !path.substring(prefix.length()).contains(".")) {
|
if (path.startsWith(prefix) && !path.substring(prefix.length()).contains(".")) {
|
||||||
DefinitionNavigator dn = new DefinitionNavigator(context, structure, i, this.path+"."+tail(path), names, null);
|
DefinitionNavigator dn = new DefinitionNavigator(context, structure, diff, i, this.path+"."+tail(path), names, null);
|
||||||
|
|
||||||
if (nameMap.containsKey(path)) {
|
if (nameMap.containsKey(path)) {
|
||||||
DefinitionNavigator master = nameMap.get(path);
|
DefinitionNavigator master = nameMap.get(path);
|
||||||
if (!master.current().hasSlicing())
|
ElementDefinition cm = master.current();
|
||||||
|
if (!cm.hasSlicing())
|
||||||
throw new DefinitionException("Found slices with no slicing details at "+dn.current().getPath());
|
throw new DefinitionException("Found slices with no slicing details at "+dn.current().getPath());
|
||||||
if (master.slices == null)
|
if (master.slices == null)
|
||||||
master.slices = new ArrayList<DefinitionNavigator>();
|
master.slices = new ArrayList<DefinitionNavigator>();
|
||||||
|
@ -180,7 +192,7 @@ public class DefinitionNavigator {
|
||||||
typeOfChildren = null;
|
typeOfChildren = null;
|
||||||
StructureDefinition sd = context.fetchResource(StructureDefinition.class, /* GF#13465 : this somehow needs to be revisited type.hasProfile() ? type.getProfile() : */ type.getWorkingCode(), src);
|
StructureDefinition sd = context.fetchResource(StructureDefinition.class, /* GF#13465 : this somehow needs to be revisited type.hasProfile() ? type.getProfile() : */ type.getWorkingCode(), src);
|
||||||
if (sd != null) {
|
if (sd != null) {
|
||||||
DefinitionNavigator dn = new DefinitionNavigator(context, sd, 0, path, names, sd.getType());
|
DefinitionNavigator dn = new DefinitionNavigator(context, sd, diff, 0, path, names, sd.getType());
|
||||||
typeChildren = dn.children();
|
typeChildren = dn.children();
|
||||||
} else
|
} else
|
||||||
throw new DefinitionException("Unable to find definition for "+type.getWorkingCode()+(type.hasProfile() ? "("+type.getProfile()+")" : ""));
|
throw new DefinitionException("Unable to find definition for "+type.getWorkingCode()+(type.hasProfile() ? "("+type.getProfile()+")" : ""));
|
||||||
|
|
|
@ -965,6 +965,7 @@ public class I18nConstants {
|
||||||
public static final String MSG_DEPENDS_ON_DRAFT = "MSG_DEPENDS_ON_DRAFT";
|
public static final String MSG_DEPENDS_ON_DRAFT = "MSG_DEPENDS_ON_DRAFT";
|
||||||
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";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,6 @@ public class CommonPackages {
|
||||||
public static final String VER_XVER = "0.0.12";
|
public static final String VER_XVER = "0.0.12";
|
||||||
|
|
||||||
public static final String ID_PUBPACK = "hl7.fhir.pubpack";
|
public static final String ID_PUBPACK = "hl7.fhir.pubpack";
|
||||||
public static final String VER_PUBPACK = "0.1.4";
|
public static final String VER_PUBPACK = "0.1.5";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -371,9 +371,13 @@ public class XhtmlComposer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String compose(XhtmlNodeList childNodes) {
|
public String compose(XhtmlNodeList nodes) throws IOException {
|
||||||
// TODO Auto-generated method stub
|
StringWriter sdst = new StringWriter();
|
||||||
return null;
|
dst = sdst;
|
||||||
|
for (XhtmlNode node : nodes) {
|
||||||
|
writeNode("", node, false);
|
||||||
|
}
|
||||||
|
return sdst.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -65,6 +65,13 @@ public abstract class XhtmlFluent {
|
||||||
return addTag("div");
|
return addTag("div");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public XhtmlNode div(String style) {
|
||||||
|
XhtmlNode x = addTag("div");
|
||||||
|
if (!Utilities.noString(style))
|
||||||
|
x.attribute("style", style);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
public XhtmlNode para() {
|
public XhtmlNode para() {
|
||||||
return addTag("p");
|
return addTag("p");
|
||||||
}
|
}
|
||||||
|
@ -110,7 +117,15 @@ public abstract class XhtmlFluent {
|
||||||
}
|
}
|
||||||
|
|
||||||
public XhtmlNode ah(String href) {
|
public XhtmlNode ah(String href) {
|
||||||
return addTag("a").attribute("href", href);
|
if (href == null) {
|
||||||
|
if (this instanceof XhtmlNode) {
|
||||||
|
return (XhtmlNode) this;
|
||||||
|
} else {
|
||||||
|
return addTag("span");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return addTag("a").attribute("href", href);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public XhtmlNode ah(String href, String title) {
|
public XhtmlNode ah(String href, String title) {
|
||||||
|
@ -121,6 +136,17 @@ public abstract class XhtmlFluent {
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public XhtmlNode ahWithText(String preText, String href, String title, String text, String postText) {
|
||||||
|
tx(preText);
|
||||||
|
XhtmlNode x = addTag("a").attribute("href", href);
|
||||||
|
if (title != null) {
|
||||||
|
x.attribute("title", title);
|
||||||
|
}
|
||||||
|
x.tx(text);
|
||||||
|
tx(postText);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* make it a code if it's not a link
|
* make it a code if it's not a link
|
||||||
* @param href
|
* @param href
|
||||||
|
@ -168,7 +194,32 @@ public abstract class XhtmlFluent {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public XhtmlNode span(String style) {
|
||||||
|
XhtmlNode res = addTag("span");
|
||||||
|
if (!Utilities.noString(style))
|
||||||
|
res.attribute("style", style);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public XhtmlNode span() {
|
||||||
|
return addTag("span");
|
||||||
|
}
|
||||||
|
|
||||||
|
public XhtmlNode spanClss(String clssName) {
|
||||||
|
XhtmlNode res = addTag("span");
|
||||||
|
if (!Utilities.noString(clssName))
|
||||||
|
res.attribute("class", clssName);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void codeWithText(String preText, String text, String postText) {
|
||||||
|
tx(preText);
|
||||||
|
XhtmlNode code = addTag("code");
|
||||||
|
code.tx(text);
|
||||||
|
tx(postText);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public XhtmlNode code(String text) {
|
public XhtmlNode code(String text) {
|
||||||
XhtmlNode code = addTag("code");
|
XhtmlNode code = addTag("code");
|
||||||
code.tx(text);
|
code.tx(text);
|
||||||
|
|
|
@ -872,4 +872,24 @@ public class XhtmlNode extends XhtmlFluent implements IBaseXhtml {
|
||||||
return addTag("s");
|
return addTag("s");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public XhtmlNode svg() {
|
||||||
|
return addTag("svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public XhtmlNode path(String value) {
|
||||||
|
return addTag("path").attribute("d", value);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void copyAllContent(XhtmlNode other) {
|
||||||
|
getChildNodes().addAll(other.getChildNodes());
|
||||||
|
getAttributes().putAll(other.getAttributes());
|
||||||
|
if (!Utilities.noString(other.getContent())) {
|
||||||
|
tx(other.getContent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -947,10 +947,10 @@ SD_OBGLIGATION_INHERITS_PROFILE_NO_TARGET = Unable to read a value from this ext
|
||||||
SD_OBGLIGATION_INHERITS_PROFILE_TARGET_NOT_FOUND = The profile ''{0}'' could not be found
|
SD_OBGLIGATION_INHERITS_PROFILE_TARGET_NOT_FOUND = The profile ''{0}'' could not be found
|
||||||
SD_OBGLIGATION_INHERITS_PROFILE_NOT_RIGHT_TYPE = The profile ''{0}'' is not marked as an obligation profile
|
SD_OBGLIGATION_INHERITS_PROFILE_NOT_RIGHT_TYPE = The profile ''{0}'' is not marked as an obligation profile
|
||||||
SD_OBGLIGATION_INHERITS_PROFILE_NOT_RIGHT_BASE = The profile ''{0}'' has a different base ''{1}'' from that expected ''{2}''
|
SD_OBGLIGATION_INHERITS_PROFILE_NOT_RIGHT_BASE = The profile ''{0}'' has a different base ''{1}'' from that expected ''{2}''
|
||||||
RND_CS_CONTENT_COMPLETE = This code system <param name="cs"/> defines the following code<if test="code-count != 1">s</if>:
|
RND_CS_CONTENT_COMPLETE = This <param name="cased"/> code system <param name="cs"/> defines the following code<if test="code-count != 1">s</if><param name="h"/>:
|
||||||
RND_CS_CONTENT_EXAMPLE = This code system <param name="cs"/> provides some example code<if test="code-count != 1">s</if>:
|
RND_CS_CONTENT_EXAMPLE = This <param name="cased"/> code system <param name="cs"/> provides some example code<if test="code-count != 1">s</if><param name="h"/>:
|
||||||
RND_CS_CONTENT_FRAGMENT = This code system <param name="cs"/> provides a fragment that includes following code<if test="code-count != 1">s</if>:
|
RND_CS_CONTENT_FRAGMENT = This <param name="cased"/> code system <param name="cs"/> provides a fragment that includes following code<if test="code-count != 1">s</if><param name="h"/>:
|
||||||
RND_CS_CONTENT_NOTPRESENT = This code system <param name="cs"/> defines codes, but no codes are represented here
|
RND_CS_CONTENT_NOTPRESENT = This <param name="cased"/> code system <param name="cs"/> defines codes<param name="h"/>, but no codes are represented here
|
||||||
RND_CS_CONTENT_SUPPLEMENT = This code system <param name="cs"/> defines {0} on the following code<if test="code-count != 1">s</if>:
|
RND_CS_CONTENT_SUPPLEMENT = This code system <param name="cs"/> defines {0} on the following code<if test="code-count != 1">s</if>:
|
||||||
QUESTIONNAIRE_Q_UNKNOWN_DERIVATION = The questionnaire ''{0}'' referred to in the derivation could not be found
|
QUESTIONNAIRE_Q_UNKNOWN_DERIVATION = The questionnaire ''{0}'' referred to in the derivation could not be found
|
||||||
QUESTIONNAIRE_Q_NO_DERIVATION_TYPE = The questionnaire ''{0}'' has no derivation type specified using the ''http://hl7.org/fhir/StructureDefinition/questionnaire-derivationType'' extension, so derivation has not been checked
|
QUESTIONNAIRE_Q_NO_DERIVATION_TYPE = The questionnaire ''{0}'' has no derivation type specified using the ''http://hl7.org/fhir/StructureDefinition/questionnaire-derivationType'' extension, so derivation has not been checked
|
||||||
|
@ -1015,7 +1015,8 @@ MSG_RETIRED = Reference to retired item {0}
|
||||||
MSG_EXPERIMENTAL = Reference to experimental item {0}
|
MSG_EXPERIMENTAL = Reference to experimental item {0}
|
||||||
MSG_DRAFT = Reference to draft item {0}
|
MSG_DRAFT = Reference to draft item {0}
|
||||||
INACTIVE_CODE_WARNING = The code ''{0}'' is valid but is not active
|
INACTIVE_CODE_WARNING = The code ''{0}'' is valid but is not active
|
||||||
SD_ED_TYPE_PROFILE_WRONG_TYPE = The type {0} is not in the list of allowed types {1} in the profile {2}
|
SD_ED_TYPE_PROFILE_WRONG_TYPE_one = The type {0} is not in the list of allowed type {1} in the profile {2}
|
||||||
|
SD_ED_TYPE_PROFILE_WRONG_TYPE_other = The type {0} is not in the list of allowed types {1} in the profile {2}
|
||||||
MSG_DEPENDS_ON_DEPRECATED = The {0} {1} is deprecated
|
MSG_DEPENDS_ON_DEPRECATED = The {0} {1} is deprecated
|
||||||
MSG_DEPENDS_ON_WITHDRAWN = The {0} {1} is withdrawn
|
MSG_DEPENDS_ON_WITHDRAWN = The {0} {1} is withdrawn
|
||||||
MSG_DEPENDS_ON_RETIRED = The {0} {1} is retired
|
MSG_DEPENDS_ON_RETIRED = The {0} {1} is retired
|
||||||
|
@ -1023,3 +1024,5 @@ MSG_DEPENDS_ON_EXPERIMENTAL = The {0} {1} is an experimental resource
|
||||||
MSG_DEPENDS_ON_DRAFT = The {0} {1} is a draft resource
|
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}'' amd the standards status ''{1}'' are not consistent
|
||||||
|
|
|
@ -835,3 +835,6 @@ UNICODE_XML_BAD_CHARS_other =
|
||||||
Display_Name_WS_for__should_be_one_of__instead_of_one =
|
Display_Name_WS_for__should_be_one_of__instead_of_one =
|
||||||
Display_Name_WS_for__should_be_one_of__instead_of_many =
|
Display_Name_WS_for__should_be_one_of__instead_of_many =
|
||||||
Display_Name_WS_for__should_be_one_of__instead_of_other =
|
Display_Name_WS_for__should_be_one_of__instead_of_other =
|
||||||
|
SD_ED_TYPE_PROFILE_WRONG_TYPE_one =
|
||||||
|
SD_ED_TYPE_PROFILE_WRONG_TYPE_many =
|
||||||
|
SD_ED_TYPE_PROFILE_WRONG_TYPE_other =
|
||||||
|
|
|
@ -5139,7 +5139,14 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean checkSpecials(ValidatorHostContext hostContext, List<ValidationMessage> errors, Element element, NodeStack stack, boolean checkSpecials, PercentageTracker pct, ValidationMode mode) {
|
public boolean checkSpecials(ValidatorHostContext hostContext, List<ValidationMessage> errors, Element element, NodeStack stack, boolean checkSpecials, PercentageTracker pct, ValidationMode mode) {
|
||||||
// specific known special validations
|
if (VersionUtilities.getCanonicalResourceNames(context.getVersion()).contains(element.getType())) {
|
||||||
|
Base base = element.getExtensionValue(ToolingExtensions.EXT_STANDARDS_STATUS);
|
||||||
|
String standardsStatus = base != null && base.isPrimitive() ? base.primitiveValue() : null;
|
||||||
|
String status = element.getNamedChildValue("status");
|
||||||
|
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 (element.getType().equals(BUNDLE)) {
|
if (element.getType().equals(BUNDLE)) {
|
||||||
return new BundleValidator(this, serverBase).validateBundle(errors, element, stack, checkSpecials, hostContext, pct, mode);
|
return new BundleValidator(this, serverBase).validateBundle(errors, element, stack, checkSpecials, hostContext, pct, mode);
|
||||||
} else if (element.getType().equals("Observation")) {
|
} else if (element.getType().equals("Observation")) {
|
||||||
|
@ -5171,6 +5178,19 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean statusCodesConsistent(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, "draft", "active");
|
||||||
|
case "informative": return Utilities.existsInList(status, "draft", "active", "retired");
|
||||||
|
case "deprecated": return Utilities.existsInList(status, "retired");
|
||||||
|
case "withdrawn": return Utilities.existsInList(status, "retired");
|
||||||
|
case "external": return Utilities.existsInList(status, "draft", "active", "retired");
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
|
|
@ -181,7 +181,7 @@ public class TerminologyServiceTests {
|
||||||
e.setCode(IssueType.BUSINESSRULE);
|
e.setCode(IssueType.BUSINESSRULE);
|
||||||
break;
|
break;
|
||||||
case CODESYSTEM_UNSUPPORTED:
|
case CODESYSTEM_UNSUPPORTED:
|
||||||
e.setCode(IssueType.INVALID);
|
e.setCode(IssueType.CODEINVALID);
|
||||||
break;
|
break;
|
||||||
case INTERNAL_ERROR:
|
case INTERNAL_ERROR:
|
||||||
e.setCode(IssueType.EXCEPTION);
|
e.setCode(IssueType.EXCEPTION);
|
||||||
|
|
|
@ -158,3 +158,19 @@ v: {
|
||||||
"system" : "urn:ietf:bcp:13"
|
"system" : "urn:ietf:bcp:13"
|
||||||
}
|
}
|
||||||
-------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------
|
||||||
|
{"code" : {
|
||||||
|
"system" : "http://unstats.un.org/unsd/methods/m49/m49.htm",
|
||||||
|
"code" : "001"
|
||||||
|
}, "url": "http://hl7.org/fhir/ValueSet/jurisdiction", "version": "5.0.0", "langs":"[en]", "useServer":"true", "useClient":"true", "guessSystem":"false", "valueSetMode":"NO_MEMBERSHIP_CHECK", "displayWarningMode":"false", "versionFlexible":"false", "profile": {
|
||||||
|
"resourceType" : "Parameters",
|
||||||
|
"parameter" : [{
|
||||||
|
"name" : "profile-url",
|
||||||
|
"valueString" : "http://hl7.org/fhir/ExpansionProfile/dc8fd4bc-091a-424a-8a3b-6198ef146891"
|
||||||
|
}]
|
||||||
|
}}####
|
||||||
|
v: {
|
||||||
|
"display" : "World",
|
||||||
|
"code" : "001",
|
||||||
|
"system" : "http://unstats.un.org/unsd/methods/m49/m49.htm"
|
||||||
|
}
|
||||||
|
-------------------------------------------------------------------------------------
|
||||||
|
|
Loading…
Reference in New Issue