rework comparison and related rendering

This commit is contained in:
Grahame Grieve 2023-08-17 18:14:12 +10:00
parent bb7d43393f
commit 0d1072616e
30 changed files with 833 additions and 474 deletions

View File

@ -9,15 +9,13 @@ import java.util.Map;
import java.util.Set;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.comparison.CanonicalResourceComparer.ChangeAnalysisState;
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.CanonicalType;
import org.hl7.fhir.r5.model.CapabilityStatement;
import org.hl7.fhir.r5.model.CodeType;
import org.hl7.fhir.r5.model.CodeableConcept;
import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.DataType;
import org.hl7.fhir.r5.model.PrimitiveType;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.Utilities;
@ -257,53 +255,53 @@ public abstract class CanonicalResourceComparer extends ResourceComparer {
super(session);
}
protected boolean compareMetadata(CanonicalResource left, CanonicalResource right, Map<String, StructuralMatch<String>> comp, CanonicalResourceComparison<? extends CanonicalResource> res, List<String> changes, Base parent, String version) {
protected boolean compareMetadata(CanonicalResource left, CanonicalResource right, Map<String, StructuralMatch<String>> comp, CanonicalResourceComparison<? extends CanonicalResource> res, List<String> changes, Base parent) {
var changed = false;
if (comparePrimitivesWithTracking("url", left.getUrlElement(), right.getUrlElement(), comp, IssueSeverity.ERROR, res, parent, version)) {
if (comparePrimitivesWithTracking("url", left.getUrlElement(), right.getUrlElement(), comp, IssueSeverity.ERROR, res, parent)) {
changed = true;
changes.add("url");
}
if (session.getForVersion() == null) {
if (comparePrimitivesWithTracking("version", left.getVersionElement(), right.getVersionElement(), comp, IssueSeverity.ERROR, res, parent, version)) {
if (!session.isAnnotate()) {
if (comparePrimitivesWithTracking("version", left.getVersionElement(), right.getVersionElement(), comp, IssueSeverity.ERROR, res, parent)) {
changed = true;
changes.add("version");
}
}
if (comparePrimitivesWithTracking("name", left.getNameElement(), right.getNameElement(), comp, IssueSeverity.INFORMATION, res, parent, version)) {
if (comparePrimitivesWithTracking("name", left.getNameElement(), right.getNameElement(), comp, IssueSeverity.INFORMATION, res, parent)) {
changed = true;
changes.add("name");
}
if (comparePrimitivesWithTracking("title", left.getTitleElement(), right.getTitleElement(), comp, IssueSeverity.INFORMATION, res, parent, version)) {
if (comparePrimitivesWithTracking("title", left.getTitleElement(), right.getTitleElement(), comp, IssueSeverity.INFORMATION, res, parent)) {
changed = true;
changes.add("title");
}
if (comparePrimitivesWithTracking("status", left.getStatusElement(), right.getStatusElement(), comp, IssueSeverity.INFORMATION, res, parent, version)) {
if (comparePrimitivesWithTracking("status", left.getStatusElement(), right.getStatusElement(), comp, IssueSeverity.INFORMATION, res, parent)) {
changed = true;
changes.add("status");
}
if (comparePrimitivesWithTracking("experimental", left.getExperimentalElement(), right.getExperimentalElement(), comp, IssueSeverity.WARNING, res, parent, version)) {
if (comparePrimitivesWithTracking("experimental", left.getExperimentalElement(), right.getExperimentalElement(), comp, IssueSeverity.WARNING, res, parent)) {
changed = true;
changes.add("experimental");
}
if (session.getForVersion() == null) {
if (comparePrimitivesWithTracking("date", left.getDateElement(), right.getDateElement(), comp, IssueSeverity.INFORMATION, res, parent, version)) {
if (!session.isAnnotate()) {
if (comparePrimitivesWithTracking("date", left.getDateElement(), right.getDateElement(), comp, IssueSeverity.INFORMATION, res, parent)) {
changed = true;
changes.add("date");
}
}
if (comparePrimitivesWithTracking("publisher", left.getPublisherElement(), right.getPublisherElement(), comp, IssueSeverity.INFORMATION, res, parent, version)) {
if (comparePrimitivesWithTracking("publisher", left.getPublisherElement(), right.getPublisherElement(), comp, IssueSeverity.INFORMATION, res, parent)) {
changed = true;
changes.add("publisher");
}
if (comparePrimitivesWithTracking("description", left.getDescriptionElement(), right.getDescriptionElement(), comp, IssueSeverity.NULL, res, parent, version)) {
if (comparePrimitivesWithTracking("description", left.getDescriptionElement(), right.getDescriptionElement(), comp, IssueSeverity.NULL, res, parent)) {
changed = true;
changes.add("description");
}
if (comparePrimitivesWithTracking("purpose", left.getPurposeElement(), right.getPurposeElement(), comp, IssueSeverity.NULL, res, parent, version)) {
if (comparePrimitivesWithTracking("purpose", left.getPurposeElement(), right.getPurposeElement(), comp, IssueSeverity.NULL, res, parent)) {
changed = true;
changes.add("purpose");
}
if (comparePrimitivesWithTracking("copyright", left.getCopyrightElement(), right.getCopyrightElement(), comp, IssueSeverity.INFORMATION, res, parent, version)) {
if (comparePrimitivesWithTracking("copyright", left.getCopyrightElement(), right.getCopyrightElement(), comp, IssueSeverity.INFORMATION, res, parent)) {
changed = true;
changes.add("copyright");
}
@ -464,29 +462,59 @@ public abstract class CanonicalResourceComparer extends ResourceComparer {
}
protected boolean comparePrimitivesWithTracking(String name, List< ? extends PrimitiveType> ll, List<? extends PrimitiveType> rl, Map<String, StructuralMatch<String>> comp, IssueSeverity level, CanonicalResourceComparison<? extends CanonicalResource> res, Base parent) {
boolean def = false;
List<PrimitiveType> matchR = new ArrayList<>();
for (PrimitiveType l : ll) {
PrimitiveType r = findInList(rl, l);
if (r == null) {
session.markDeleted(parent, "element", l);
} else {
matchR.add(r);
def = comparePrimitivesWithTracking(name, l, r, comp, level, res, parent) || def;
}
}
for (PrimitiveType r : rl) {
if (!matchR.contains(r)) {
session.markAdded(r);
}
}
return def;
}
private PrimitiveType findInList(List<? extends PrimitiveType> rl, PrimitiveType l) {
for (PrimitiveType r : rl) {
if (r.equalsDeep(l)) {
return r;
}
}
return null;
}
@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) {
protected boolean comparePrimitivesWithTracking(String name, PrimitiveType l, PrimitiveType r, Map<String, StructuralMatch<String>> comp, IssueSeverity level, CanonicalResourceComparison<? extends CanonicalResource> res, Base parent) {
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);
session.markAdded(r);
} 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);
session.markDeleted(parent, 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);
session.markAdded(r);
} 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);
session.markDeleted(parent, name, l);
} else if (l.getValue().equals(r.getValue())) {
match = new StructuralMatch<>(l.primitiveValue(), r.primitiveValue(), null);
} else {
VersionComparisonAnnotation.markChanged(r, version);
session.markChanged(r, l);
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));
@ -497,6 +525,65 @@ public abstract class CanonicalResourceComparer extends ResourceComparer {
}
return match.isDifferent();
}
protected boolean compareDataTypesWithTracking(String name, List< ? extends DataType> ll, List<? extends DataType> rl, Map<String, StructuralMatch<String>> comp, IssueSeverity level, CanonicalResourceComparison<? extends CanonicalResource> res, Base parent) {
boolean def = false;
List<DataType> matchR = new ArrayList<>();
for (DataType l : ll) {
DataType r = findInList(rl, l);
if (r == null) {
session.markDeleted(parent, "element", l);
} else {
matchR.add(r);
def = compareDataTypesWithTracking(name, l, r, comp, level, res, parent) || def;
}
}
for (DataType r : rl) {
if (!matchR.contains(r)) {
session.markAdded(r);
}
}
return def;
}
private DataType findInList(List<? extends DataType> rl, DataType l) {
for (DataType r : rl) {
if (r.equalsDeep(l)) {
return r;
}
}
return null;
}
@SuppressWarnings("rawtypes")
protected boolean compareDataTypesWithTracking(String name, DataType l, DataType r, Map<String, StructuralMatch<String>> comp, IssueSeverity level, CanonicalResourceComparison<? extends CanonicalResource> res, Base parent) {
StructuralMatch<String> match = null;
boolean le = l == null || l.isEmpty();
boolean re = r == null || r.isEmpty();
if (le && re) {
match = new StructuralMatch<>(null, null, null);
} else if (le) {
match = new StructuralMatch<>(null, r.primitiveValue(), vmI(IssueSeverity.INFORMATION, "Added the item '"+r.fhirType()+"'", fhirType()+"."+name));
session.markAdded(r);
} else if (re) {
match = new StructuralMatch<>(l.primitiveValue(), null, vmI(IssueSeverity.INFORMATION, "Removed the item '"+l.fhirType()+"'", fhirType()+"."+name));
session.markDeleted(parent, name, l);
} else if (l.equalsDeep(r)) {
match = new StructuralMatch<>(l.primitiveValue(), r.primitiveValue(), null);
} else {
session.markChanged(r, l);
match = new StructuralMatch<>(l.fhirType(), r.fhirType(), 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.fhirType()+"' vs '"+r.fhirType()+"'", level));
}
}
if (comp != null) {
comp.put(name, match);
}
return match.isDifferent();
}
protected abstract String fhirType();

View File

@ -3,17 +3,13 @@ package org.hl7.fhir.r5.comparison;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.comparison.StructureDefinitionComparer.ProfileComparison;
import org.hl7.fhir.r5.comparison.ResourceComparer.MessageCounts;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.model.BackboneElement;
import org.hl7.fhir.r5.model.BooleanType;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.CanonicalType;
@ -24,13 +20,10 @@ import org.hl7.fhir.r5.model.CapabilityStatement.CapabilityStatementRestResource
import org.hl7.fhir.r5.model.CapabilityStatement.CapabilityStatementRestResourceSearchParamComponent;
import org.hl7.fhir.r5.model.CapabilityStatement.CapabilityStatementRestSecurityComponent;
import org.hl7.fhir.r5.model.CapabilityStatement.ResourceInteractionComponent;
import org.hl7.fhir.r5.model.CapabilityStatement.ResourceVersionPolicy;
import org.hl7.fhir.r5.model.CodeType;
import org.hl7.fhir.r5.model.CodeableConcept;
import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.DataType;
import org.hl7.fhir.r5.model.Element;
import org.hl7.fhir.r5.model.Enumeration;
import org.hl7.fhir.r5.model.Extension;
import org.hl7.fhir.r5.model.PrimitiveType;
import org.hl7.fhir.r5.model.Resource;
@ -114,7 +107,7 @@ public class CapabilityStatementComparer extends CanonicalResourceComparer {
cs1.setStatus(left.getStatus());
cs1.setDate(new Date());
compareMetadata(left, right, res.getMetadata(), res, new ArrayList<>(), right, session.getForVersion());
compareMetadata(left, right, res.getMetadata(), res, new ArrayList<>(), right);
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("imports", left.getImports(), right.getImports(), res.getMetadata(), IssueSeverity.ERROR, res, cs.getImports(), cs1.getImports());

View File

@ -9,7 +9,6 @@ import java.util.Map;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
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.CodeSystemFilterComponent;
@ -132,7 +131,7 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
List<String> chMetadata = new ArrayList<>();
boolean ch = compareMetadata(left, right, res.getMetadata(), res, chMetadata, right, session.getForVersion());
boolean ch = compareMetadata(left, right, res.getMetadata(), res, chMetadata, right);
if (comparePrimitives("versionNeeded", left.getVersionNeededElement(), right.getVersionNeededElement(), res.getMetadata(), IssueSeverity.INFORMATION, res)) {
ch = true;
chMetadata.add("versionNeeded");
@ -143,16 +142,16 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
}
res.updatedMetadataState(ch, chMetadata);
ch = false;
ch = comparePrimitivesWithTracking("caseSensitive", left.getCaseSensitiveElement(), right.getCaseSensitiveElement(), res.getMetadata(), IssueSeverity.ERROR, res, right, session.getForVersion()) || ch;
ch = comparePrimitivesWithTracking("hierarchyMeaning", left.getHierarchyMeaningElement(), right.getHierarchyMeaningElement(), res.getMetadata(), IssueSeverity.ERROR, res, right, session.getForVersion()) || ch;
ch = comparePrimitivesWithTracking("content", left.getContentElement(), right.getContentElement(), res.getMetadata(), IssueSeverity.WARNING, res, right, session.getForVersion());
ch = comparePrimitivesWithTracking("caseSensitive", left.getCaseSensitiveElement(), right.getCaseSensitiveElement(), res.getMetadata(), IssueSeverity.ERROR, res, right) || ch;
ch = comparePrimitivesWithTracking("hierarchyMeaning", left.getHierarchyMeaningElement(), right.getHierarchyMeaningElement(), res.getMetadata(), IssueSeverity.ERROR, res, right) || ch;
ch = comparePrimitivesWithTracking("content", left.getContentElement(), right.getContentElement(), res.getMetadata(), IssueSeverity.WARNING, res, right);
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);
VersionComparisonAnnotation.annotate(right, session.getForVersion(), res);
session.annotate(right, res);
return res;
}
@ -193,7 +192,7 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
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);
session.markDeleted(parent, "concept", l);
} else {
matchR.add(r);
PropertyComponent cdM = merge(l, r, res);
@ -212,7 +211,7 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
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());
session.markAdded(r);
}
}
return def;
@ -229,7 +228,7 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
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);
session.markDeleted(parent, "concept", l);
} else {
matchR.add(r);
CodeSystemFilterComponent cdM = merge(l, r, res);
@ -248,7 +247,7 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
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());
session.markAdded(r);
}
}
return def;
@ -265,7 +264,7 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
union.add(l);
res.updateContentState(true);
combined.getChildren().add(new StructuralMatch<CodeSystem.ConceptDefinitionComponent>(l, vmI(IssueSeverity.INFORMATION, "Removed this concept", path)));
VersionComparisonAnnotation.markDeleted(parent, session.getForVersion(), "concept", l);
session.markDeleted(parent, "concept", l);
} else {
matchR.add(r);
ConceptDefinitionComponent cdM = merge(l, r, csU.getProperty(), res);
@ -287,7 +286,7 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
union.add(r);
res.updateContentState(true);
combined.getChildren().add(new StructuralMatch<CodeSystem.ConceptDefinitionComponent>(vmI(IssueSeverity.INFORMATION, "Added this concept", path), r));
VersionComparisonAnnotation.markAdded(r, session.getForVersion());
session.markAdded(r);
}
}
return def;
@ -351,19 +350,19 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
if (!Utilities.noString(right)) {
if (Utilities.noString(left)) {
msgs.add(vmI(level, "Value for "+name+" added", path));
VersionComparisonAnnotation.markAdded(r, session.getForVersion());
session.markAdded(r);
return true;
} else if (!left.equals(right)) {
if (level != IssueSeverity.NULL) {
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));
VersionComparisonAnnotation.markChanged(r, session.getForVersion());
session.markChanged(r, l);
return true;
}
} else if (!Utilities.noString(left)) {
msgs.add(vmI(level, "Value for "+name+" removed", path));
VersionComparisonAnnotation.markDeleted(parent, session.getForVersion(), "concept", l);
session.markDeleted(parent, "concept", l);
return true;
}
return false;

View File

@ -16,11 +16,10 @@ import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.PathEngineException;
import org.hl7.fhir.r5.comparison.CapabilityStatementComparer.CapabilityStatementComparison;
import org.hl7.fhir.r5.comparison.CodeSystemComparer.CodeSystemComparison;
import org.hl7.fhir.r5.comparison.StructureDefinitionComparer.ProfileComparison;
import org.hl7.fhir.r5.comparison.ResourceComparer.PlaceHolderComparison;
import org.hl7.fhir.r5.comparison.ResourceComparer.ResourceComparison;
import org.hl7.fhir.r5.comparison.StructureDefinitionComparer.ProfileComparison;
import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
@ -28,7 +27,6 @@ import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.ExpressionNode.CollectionStatus;
import org.hl7.fhir.r5.model.StringType;
import org.hl7.fhir.r5.model.Tuple;
import org.hl7.fhir.r5.model.TypeDetails;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext;

View File

@ -8,14 +8,17 @@ import java.util.UUID;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.r5.comparison.CanonicalResourceComparer.CanonicalResourceComparison;
import org.hl7.fhir.r5.comparison.CapabilityStatementComparer.CapabilityStatementComparison;
import org.hl7.fhir.r5.comparison.CodeSystemComparer.CodeSystemComparison;
import org.hl7.fhir.r5.comparison.StructureDefinitionComparer.ProfileComparison;
import org.hl7.fhir.r5.comparison.ResourceComparer.ResourceComparison;
import org.hl7.fhir.r5.comparison.StructureDefinitionComparer.ProfileComparison;
import org.hl7.fhir.r5.comparison.ValueSetComparer.ValueSetComparison;
import org.hl7.fhir.r5.comparison.VersionComparisonAnnotation.AnotationType;
import org.hl7.fhir.r5.conformance.profile.ProfileKnowledgeProvider;
import org.hl7.fhir.r5.conformance.profile.ProfileUtilities;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.CapabilityStatement;
import org.hl7.fhir.r5.model.CodeSystem;
@ -32,7 +35,6 @@ public class ComparisonSession {
private String sessiondId;
private int count;
private boolean debug;
private String forVersion;
private boolean annotate;
private String title;
private ProfileKnowledgeProvider pkpLeft;
@ -115,7 +117,7 @@ public class ComparisonSession {
return csc;
}
} else if (left != null) {
VersionComparisonAnnotation.markDeleted(null, forVersion, left.fhirType(), left); // todo: waht?
markDeleted(null, left.fhirType(), left); // todo: waht?
String key = key(left.getUrl(), left.getVersion(), left.getUrl(), left.getVersion());
if (compares.containsKey(key)) {
return compares.get(key);
@ -124,7 +126,7 @@ public class ComparisonSession {
compares.put(key, csc);
return csc;
} else {
VersionComparisonAnnotation.markAdded(right, forVersion);
markAdded(right);
String key = key(right.getUrl(), right.getVersion(), right.getUrl(), right.getVersion());
if (compares.containsKey(key)) {
return compares.get(key);
@ -169,14 +171,6 @@ public class ComparisonSession {
return pkpRight;
}
public String getForVersion() {
return forVersion;
}
public void setForVersion(String forVersion) {
this.forVersion = forVersion;
}
public boolean isAnnotate() {
return annotate;
}
@ -184,6 +178,39 @@ public class ComparisonSession {
public void setAnnotate(boolean annotate) {
this.annotate = annotate;
}
private VersionComparisonAnnotation getAnnotation(Base b) {
if (b.hasUserData(VersionComparisonAnnotation.USER_DATA_NAME)) {
return (VersionComparisonAnnotation) b.getUserData(VersionComparisonAnnotation.USER_DATA_NAME);
} else {
VersionComparisonAnnotation vca = new VersionComparisonAnnotation(AnotationType.NoChange);
b.setUserData(VersionComparisonAnnotation.USER_DATA_NAME, vca);
return vca;
}
}
public void markAdded(Base focus) {
if (isAnnotate()) {
getAnnotation(focus).added();
}
}
public void markChanged(Base focus, Base original) {
if (isAnnotate()) {
getAnnotation(focus).changed(original);
}
}
public void markDeleted(Base parent, String name, Base other) {
if (isAnnotate() && other != null) {
getAnnotation(parent).deleted(name, other);
getAnnotation(other).deleted();
}
}
public void annotate(Base base, CanonicalResourceComparison<? extends CanonicalResource> comp) {
if (isAnnotate()) {
getAnnotation(base).comp(comp);
}
}
}

View File

@ -3,8 +3,6 @@ package org.hl7.fhir.r5.comparison;
import java.util.ArrayList;
import java.util.List;
import org.hl7.fhir.r5.comparison.ResourceComparer.MessageCounts;
import org.hl7.fhir.r5.comparison.ResourceComparer.ResourceComparison;
import org.hl7.fhir.r5.model.CanonicalResource;
import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.StructureDefinition;
@ -326,5 +324,7 @@ public class ResourceComparer {
}
return cell;
}
}

View File

@ -4,7 +4,6 @@ import java.util.ArrayList;
import java.util.List;
import org.hl7.fhir.r5.comparison.ResourceComparer.MessageCounts;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;

View File

@ -5,12 +5,10 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
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.conformance.profile.BindingResolution;
import org.hl7.fhir.r5.conformance.profile.ProfileKnowledgeProvider;
@ -19,7 +17,6 @@ import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.formats.IParser;
import org.hl7.fhir.r5.formats.JsonParser;
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.DataType;
import org.hl7.fhir.r5.model.ElementDefinition;
@ -43,10 +40,8 @@ import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules;
import org.hl7.fhir.r5.renderers.utils.RenderingContext.ResourceRendererMode;
import org.hl7.fhir.r5.utils.DefinitionNavigator;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.MarkDownProcessor;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.validation.ValidationOptions;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator;
import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Cell;
@ -147,7 +142,7 @@ public class StructureDefinitionComparer extends CanonicalResourceComparer imple
sd1.setDate(new Date());
List<String> chMetadata = new ArrayList<>();
boolean ch = compareMetadata(left, right, res.getMetadata(), res, chMetadata, right, session.getForVersion());
boolean ch = compareMetadata(left, right, res.getMetadata(), res, chMetadata, right);
if (comparePrimitives("fhirVersion", left.getFhirVersionElement(), right.getFhirVersionElement(), res.getMetadata(), IssueSeverity.WARNING, res)) {
ch = true;
chMetadata.add("fhirVersion");
@ -178,7 +173,7 @@ public class StructureDefinitionComparer extends CanonicalResourceComparer imple
}
res.updateDefinitionsState(ch);
VersionComparisonAnnotation.annotate(right, session.getForVersion(), res);
session.annotate(right, res);
return res;
}
@ -228,19 +223,19 @@ public class StructureDefinitionComparer extends CanonicalResourceComparer imple
// descriptive properties from ElementDefinition - merge them:
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());
comparePrimitivesWithTracking("label", left.current().getLabelElement(), right.current().getLabelElement(), null, IssueSeverity.INFORMATION, comp, right.current());
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;
def = comparePrimitivesWithTracking("short", left.current().getShortElement(), right.current().getShortElement(), null, IssueSeverity.INFORMATION, comp, right.current()) || def;
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;
def = comparePrimitivesWithTracking("definition", left.current().getDefinitionElement(), right.current().getDefinitionElement(), null, IssueSeverity.INFORMATION, comp, right.current()) || def;
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;
def = comparePrimitivesWithTracking("comment", left.current().getCommentElement(), right.current().getCommentElement(), null, IssueSeverity.INFORMATION, comp, right.current()) || def;
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;
def = comparePrimitivesWithTracking("requirements", left.current().getRequirementsElement(), right.current().getRequirementsElement(), null, IssueSeverity.INFORMATION, comp, right.current()) || def;
subset.getCode().addAll(mergeCodings(left.current().getCode(), right.current().getCode()));
subset.getAlias().addAll(mergeStrings(left.current().getAlias(), right.current().getAlias()));
@ -253,12 +248,12 @@ public class StructureDefinitionComparer extends CanonicalResourceComparer imple
}
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;
def = comparePrimitivesWithTracking("mustSupport", left.current().getMustSupportElement(), right.current().getMustSupportElement(), null, IssueSeverity.INFORMATION, null, right.current()) || def;
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;
def = comparePrimitivesWithTracking("min", left.current().getMinElement(), right.current().getMinElement(), null, IssueSeverity.INFORMATION, null, right.current()) || def;
def = comparePrimitivesWithTracking("max", left.current().getMaxElement(), right.current().getMaxElement(), null, IssueSeverity.INFORMATION, null, right.current()) || def;
// compare and intersect
int leftMin = left.current().getMin();
@ -396,6 +391,8 @@ public class StructureDefinitionComparer extends CanonicalResourceComparer imple
assert(left.path().equals(right.path()));
boolean def = false;
boolean ch = false;
System.out.println(left.getId());
// not allowed to be different:
// ruleEqual(comp, res, left.current().getDefaultValue(), right.current().getDefaultValue(), "defaultValue", path);
@ -403,25 +400,71 @@ public class StructureDefinitionComparer extends CanonicalResourceComparer imple
// 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
if (left.current() == null && right.current() == null) {
ElementDefinition edl = left.current();
ElementDefinition edr = right.current();
if (edl == null && edr == null) {
// both are sparse at this point, do nothing
} else if (left.current() == null) {
VersionComparisonAnnotation.markAdded(right.current(), session.getForVersion());
} else if (right.current() == null) {
VersionComparisonAnnotation.markDeleted(right.parent(), session.getForVersion(), "element", left.current());
} else if (edl == null) {
session.markAdded(edr);
} else if (edr == null) {
session.markDeleted(right.parent(), "element", edl);
} else {
// 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;
// descriptive properties from ElementDefinition
comparePrimitivesWithTracking("label", edl.getLabelElement(), edr.getLabelElement(), null, IssueSeverity.INFORMATION, null, edr);
comparePrimitivesWithTracking("sliceName", edl.getSliceNameElement(), edr.getSliceNameElement(), null, IssueSeverity.INFORMATION, null, edr);
comparePrimitivesWithTracking("sliceIsConstraining", edl.getSliceIsConstrainingElement(), edr.getSliceIsConstrainingElement(), null, IssueSeverity.INFORMATION, null, edr);
comparePrimitivesWithTracking("alias", edl.getAlias(), edr.getAlias(), null, IssueSeverity.INFORMATION, null, edr);
compareDataTypesWithTracking("code", edl.getCode(), edr.getCode(), null, IssueSeverity.INFORMATION, null, edr);
def = comparePrimitivesWithTracking("short", edl.getShortElement(), edr.getShortElement(), null, IssueSeverity.INFORMATION, null, edr) || def;
def = comparePrimitivesWithTracking("definition", edl.getDefinitionElement(), edr.getDefinitionElement(), null, IssueSeverity.INFORMATION, null, edr) || def;
def = comparePrimitivesWithTracking("comment", edl.getCommentElement(), edr.getCommentElement(), null, IssueSeverity.INFORMATION, null, edr) || def;
def = comparePrimitivesWithTracking("requirements", edl.getRequirementsElement(), edr.getRequirementsElement(), null, IssueSeverity.INFORMATION, null, edr) || def;
def = comparePrimitivesWithTracking("mustSupport", edl.getMustSupportElement(), edr.getMustSupportElement(), null, IssueSeverity.INFORMATION, null, edr) || def;
def = comparePrimitivesWithTracking("meaningWhenMissing", edl.getMeaningWhenMissingElement(), edr.getMeaningWhenMissingElement(), null, IssueSeverity.INFORMATION, null, edr) || def;
def = comparePrimitivesWithTracking("isModifierReason", edl.getIsModifierReasonElement(), edr.getIsModifierReasonElement(), null, IssueSeverity.INFORMATION, null, edr) || def;
ch = comparePrimitivesWithTracking("min", edl.getMinElement(), edr.getMinElement(), null, IssueSeverity.ERROR, null, edr) || ch;
ch = comparePrimitivesWithTracking("max", edl.getMaxElement(), edr.getMaxElement(), null, IssueSeverity.ERROR, null, edr) || ch;
ch = compareDataTypesWithTracking("defaultValue", edl.getDefaultValue(), edr.getDefaultValue(), null, IssueSeverity.ERROR, null, edr) || ch;
ch = compareDataTypesWithTracking("fixed", edl.getFixed(), edr.getFixed(), null, IssueSeverity.ERROR, null, edr) || ch;
ch = compareDataTypesWithTracking("pattern", edl.getPattern(), edr.getPattern(), null, IssueSeverity.ERROR, null, edr) || ch;
ch = compareDataTypesWithTracking("minValue", edl.getMinValue(), edr.getMinValue(), null, IssueSeverity.ERROR, null, edr) || ch;
ch = compareDataTypesWithTracking("maxValue", edl.getMaxValue(), edr.getMaxValue(), null, IssueSeverity.ERROR, null, edr) || ch;
ch = comparePrimitivesWithTracking("maxLength", edl.getMaxLengthElement(), edr.getMaxLengthElement(), null, IssueSeverity.INFORMATION, null, edr) || def;
ch = comparePrimitivesWithTracking("mustHaveValue", edl.getMustHaveValueElement(), edr.getMustHaveValueElement(), null, IssueSeverity.INFORMATION, null, edr) || def;
ch = comparePrimitivesWithTracking("valueAlternatives", edl.getValueAlternatives(), edr.getValueAlternatives(), null, IssueSeverity.INFORMATION, null, edr) || ch;
ch = comparePrimitivesWithTracking("isModifier", edl.getIsModifierElement(), edr.getIsModifierElement(), null, IssueSeverity.INFORMATION, null, edr) || def;
def = compareTypes(path, sliceName, edl, edr, res) || def;
ElementDefinitionBindingComponent bl = edl.getBinding();
ElementDefinitionBindingComponent br = edr.getBinding();
if (bl == null && br == null) {
// both are sparse at this point, do nothing
} else if (bl == null) {
session.markAdded(edr);
} else if (br == null) {
session.markDeleted(right.parent(), "element", edl);
} else {
ch = comparePrimitivesWithTracking("strength", bl.getStrengthElement(), br.getStrengthElement(), null, IssueSeverity.ERROR, null, edr) || ch;
def = comparePrimitivesWithTracking("description", bl.getDescriptionElement(), br.getDescriptionElement(), null, IssueSeverity.ERROR, null, edr) || def;
ch = comparePrimitivesWithTracking("valueSet", bl.getValueSetElement(), br.getValueSetElement(), null, IssueSeverity.ERROR, null, edr) || ch;
// todo: additional
}
def = compareInvariants(path, sliceName, edl, edr, res) || def;
// main todos:
// invariants, slicing
// mappings
}
// add the children
def = compareDiffChildren(path, left, right, right.current() == null ? parent : right.current(), res) || def;
if (ch) {
res.updateContentState(true);
}
def = compareDiffChildren(path, left, right, edr == null ? parent : edr, res) || def;
//
// // now process the slices
// if (left.current().hasSlicing() || right.current().hasSlicing()) {
@ -484,7 +527,6 @@ public class StructureDefinitionComparer extends CanonicalResourceComparer imple
return def;
}
private boolean compareDiffChildren(String path, DefinitionNavigator left, DefinitionNavigator right, Base parent, ProfileComparison res) throws DefinitionException, IOException, FHIRFormatError {
boolean def = false;
@ -495,7 +537,7 @@ public class StructureDefinitionComparer extends CanonicalResourceComparer imple
for (DefinitionNavigator l : lc) {
DefinitionNavigator r = findInList(rc, l);
if (r == null) {
VersionComparisonAnnotation.markDeleted(parent, session.getForVersion(), "element", l.current());
session.markDeleted(parent, "element", l.current());
res.updateContentState(true);
} else {
matchR.add(r);
@ -504,7 +546,7 @@ public class StructureDefinitionComparer extends CanonicalResourceComparer imple
}
for (DefinitionNavigator r : rc) {
if (!matchR.contains(r)) {
VersionComparisonAnnotation.markAdded(r.current(), session.getForVersion());
session.markAdded(r.current());
res.updateContentState(true);
}
}
@ -512,14 +554,112 @@ public class StructureDefinitionComparer extends CanonicalResourceComparer imple
}
private DefinitionNavigator findInList(List<DefinitionNavigator> rc, DefinitionNavigator l) {
String s = l.getId();
for (DefinitionNavigator t : rc) {
if (tail(t.current().getPath()).equals(tail(l.current().getPath()))) {
String ts = t.getId();
if (tail(ts).equals(tail(s))) {
return t;
}
}
return null;
}
private boolean compareTypes(String path, String sliceName, ElementDefinition left, ElementDefinition right, ProfileComparison res) {
boolean def = false;
List<TypeRefComponent> matchR = new ArrayList<>();
for (TypeRefComponent l : left.getType()) {
TypeRefComponent r = findInList(right.getType(), l);
if (r == null) {
session.markDeleted(right, "type", l);
res.updateContentState(true);
} else {
matchR.add(r);
def = compareType(path+".type", l, r, res) || def;
}
}
for (TypeRefComponent r : right.getType()) {
if (!matchR.contains(r)) {
session.markAdded(r);
res.updateContentState(true);
}
}
return def;
}
private TypeRefComponent findInList(List<TypeRefComponent> rc, TypeRefComponent l) {
for (TypeRefComponent t : rc) {
if (t.getCodeElement().equalsDeep(l.getCodeElement())) {
return t;
}
}
return null;
}
private boolean compareType(String string, TypeRefComponent l, TypeRefComponent r, ProfileComparison res) {
boolean def = false;
boolean ch = false;
// codes must match
ch = comparePrimitivesWithTracking("profile", l.getProfile(), r.getProfile(), null, IssueSeverity.ERROR, null, r) || ch;
ch = comparePrimitivesWithTracking("targetProfile", l.getTargetProfile(), r.getTargetProfile(), null, IssueSeverity.ERROR, null, r) || ch;
ch = comparePrimitivesWithTracking("aggregation", l.getAggregation(), r.getAggregation(), null, IssueSeverity.ERROR, null, r) || ch;
def = comparePrimitivesWithTracking("versioning", l.getVersioningElement(), r.getVersioningElement(), null, IssueSeverity.INFORMATION, null, r) || def;
if (ch) {
res.updateContentState(true);
}
return def;
}
private boolean compareInvariants(String path, String sliceName, ElementDefinition left, ElementDefinition right, ProfileComparison res) {
boolean def = false;
List<ElementDefinitionConstraintComponent> matchR = new ArrayList<>();
for (ElementDefinitionConstraintComponent l : left.getConstraint()) {
ElementDefinitionConstraintComponent r = findInList(right.getConstraint(), l);
if (r == null) {
session.markDeleted(right, "invariant", l);
res.updateContentState(true);
} else {
matchR.add(r);
def = compareInvariant(path+".type", l, r, res) || def;
}
}
for (ElementDefinitionConstraintComponent r : right.getConstraint()) {
if (!matchR.contains(r)) {
session.markAdded(r);
res.updateContentState(true);
}
}
return def;
}
private ElementDefinitionConstraintComponent findInList(List<ElementDefinitionConstraintComponent> rc, ElementDefinitionConstraintComponent l) {
for (ElementDefinitionConstraintComponent t : rc) {
if (t.getKeyElement().equalsDeep(l.getKeyElement())) {
return t;
}
}
return null;
}
private boolean compareInvariant(String string, ElementDefinitionConstraintComponent l, ElementDefinitionConstraintComponent r, ProfileComparison res) {
boolean def = false;
boolean ch = false;
// codes must match
def = comparePrimitivesWithTracking("requirements", l.getRequirementsElement(), r.getRequirementsElement(), null, IssueSeverity.INFORMATION, null, r) || def;
ch = comparePrimitivesWithTracking("severity", l.getSeverityElement(), r.getSeverityElement(), null, IssueSeverity.ERROR, null, r) || ch;
comparePrimitivesWithTracking("suppress", l.getSuppressElement(), r.getSuppressElement(), null, IssueSeverity.INFORMATION, null, r);
def = comparePrimitivesWithTracking("human", l.getHumanElement(), r.getHumanElement(), null, IssueSeverity.INFORMATION, null, r) || def;
ch = comparePrimitivesWithTracking("expression", l.getExpressionElement(), r.getExpressionElement(), null, IssueSeverity.ERROR, null, r) || ch;
if (ch) {
res.updateContentState(true);
}
return def;
}
// private void ruleEqual(ProfileComparison comp, StructuralMatch<ElementDefinitionNode> res, DataType vLeft, DataType vRight, String name, String path) throws IOException {
// if (vLeft == null && vRight == null) {
// // nothing

View File

@ -7,8 +7,6 @@ import java.util.List;
import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.comparison.ResourceComparer.MessageCounts;
import org.hl7.fhir.r5.comparison.VersionComparisonAnnotation.AnotationType;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.model.CanonicalType;
import org.hl7.fhir.r5.model.Element;
@ -125,7 +123,7 @@ public class ValueSetComparer extends CanonicalResourceComparer {
vs1.setDate(new Date());
List<String> chMetadata = new ArrayList<>();
var ch = compareMetadata(left, right, res.getMetadata(), res, chMetadata, right, session.getForVersion());
var ch = compareMetadata(left, right, res.getMetadata(), res, chMetadata, right);
var def = false;
if (comparePrimitives("immutable", left.getImmutableElement(), right.getImmutableElement(), res.getMetadata(), IssueSeverity.WARNING, res)) {
ch = true;
@ -143,7 +141,7 @@ public class ValueSetComparer extends CanonicalResourceComparer {
def = compareCompose(left.getCompose(), right.getCompose(), res, res.getUnion().getCompose(), res.getIntersection().getCompose()) || def;
res.updateDefinitionsState(def);
// compareExpansions(left, right, res);
VersionComparisonAnnotation.annotate(right, session.getForVersion(), res);
session.annotate(right, res);
return res;
}
@ -157,7 +155,7 @@ public class ValueSetComparer extends CanonicalResourceComparer {
union.getInclude().add(l);
res.updateContentState(true);
res.getIncludes().getChildren().add(new StructuralMatch<Element>(l, vmI(IssueSeverity.INFORMATION, "Removed Include", "ValueSet.compose.include")));
VersionComparisonAnnotation.markDeleted(right, session.getForVersion(), "include", l);
session.markDeleted(right, "include", l);
} else {
matchR.add(r);
ConceptSetComponent csM = new ConceptSetComponent();
@ -174,7 +172,7 @@ public class ValueSetComparer extends CanonicalResourceComparer {
union.getInclude().add(r);
res.updateContentState(true);
res.getIncludes().getChildren().add(new StructuralMatch<Element>(vmI(IssueSeverity.INFORMATION, "Added Include", "ValueSet.compose.include"), r));
VersionComparisonAnnotation.markAdded(r, session.getForVersion());
session.markAdded(r);
}
}
@ -252,7 +250,7 @@ public class ValueSetComparer extends CanonicalResourceComparer {
res.updateContentState(true);
combined.getChildren().add(new StructuralMatch<Element>(l, vmI(IssueSeverity.ERROR, "Removed ValueSet", "ValueSet.compose.include.valueSet")));
if (session.isAnnotate()) {
VersionComparisonAnnotation.markDeleted(right, session.getForVersion(), "valueset", l);
session.markDeleted(right, "valueset", l);
}
} else {
matchVSR.add(r);
@ -269,7 +267,7 @@ public class ValueSetComparer extends CanonicalResourceComparer {
StructuralMatch<Element> sm = new StructuralMatch<Element>(l, r, vmI(IssueSeverity.WARNING, "Values are different", "ValueSet.compose.include.valueSet"));
combined.getChildren().add(sm);
if (session.isAnnotate()) {
VersionComparisonAnnotation.markChanged(r, session.getForVersion());
session.markChanged(r, l);
}
}
@ -280,7 +278,7 @@ public class ValueSetComparer extends CanonicalResourceComparer {
union.getValueSet().add(r);
res.updateContentState(true);
combined.getChildren().add(new StructuralMatch<Element>(vmI(IssueSeverity.ERROR, "Add ValueSet", "ValueSet.compose.include.valueSet"), r));
VersionComparisonAnnotation.markAdded(r, session.getForVersion());
session.markAdded(r);
}
}
@ -292,7 +290,7 @@ public class ValueSetComparer extends CanonicalResourceComparer {
res.updateContentState(true);
combined.getChildren().add(new StructuralMatch<Element>(l, vmI(IssueSeverity.ERROR, "Removed this Concept", "ValueSet.compose.include.concept")));
res.getMessages().add(new ValidationMessage(Source.ProfileComparer, IssueType.INFORMATIONAL, path, "Code "+l.getCode()+" removed", IssueSeverity.ERROR));
VersionComparisonAnnotation.markDeleted(right, session.getForVersion(), "concept", l);
session.markDeleted(right,"concept", l);
} else {
matchCR.add(r);
if (l.getCode().equals(r.getCode())) {
@ -311,7 +309,7 @@ public class ValueSetComparer extends CanonicalResourceComparer {
combined.getChildren().add(sm);
res.updateContentState(true);
compareConcepts(path+".concept["+right.getConcept().indexOf(r)+"]", l, r, sm, null, null, res);
VersionComparisonAnnotation.markChanged(r, session.getForVersion());
session.markChanged(r, l);
}
}
}
@ -321,7 +319,7 @@ public class ValueSetComparer extends CanonicalResourceComparer {
res.updateContentState(true);
combined.getChildren().add(new StructuralMatch<Element>(vmI(IssueSeverity.ERROR, "Added this Concept", "ValueSet.compose.include.concept"), r));
res.getMessages().add(new ValidationMessage(Source.ProfileComparer, IssueType.INFORMATIONAL, path, "Code "+r.getCode()+" added", IssueSeverity.ERROR));
VersionComparisonAnnotation.markAdded(r, session.getForVersion());
session.markAdded(r);
}
}
@ -332,7 +330,7 @@ public class ValueSetComparer extends CanonicalResourceComparer {
union.getFilter().add(l);
res.updateContentState(true);
combined.getChildren().add(new StructuralMatch<Element>(l, vmI(IssueSeverity.ERROR, "Removed this item", "ValueSet.compose.include.filter")));
VersionComparisonAnnotation.markDeleted(right, session.getForVersion(), "filter", l);
session.markDeleted(right, "filter", l);
} else {
matchFR.add(r);
if (l.getProperty().equals(r.getProperty()) && l.getOp().equals(r.getOp())) {
@ -344,7 +342,7 @@ public class ValueSetComparer extends CanonicalResourceComparer {
combined.getChildren().add(sm);
if (!compareFilters(l, r, sm, cu, ci)) {
res.updateContentState(true);
VersionComparisonAnnotation.markChanged(r, session.getForVersion());
session.markChanged(r, l);
}
} else {
union.getFilter().add(l);
@ -361,7 +359,7 @@ public class ValueSetComparer extends CanonicalResourceComparer {
union.getFilter().add(r);
res.updateContentState(true);
combined.getChildren().add(new StructuralMatch<Element>(vmI(IssueSeverity.ERROR, "Added this item", "ValueSet.compose.include.filter"), r));
VersionComparisonAnnotation.markAdded(r, session.getForVersion());
session.markAdded(r);
}
}
return def;
@ -383,10 +381,10 @@ public class ValueSetComparer extends CanonicalResourceComparer {
def = !l.getDisplay().equals(r.getDisplay());
if (def) {
res.getMessages().add(new ValidationMessage(Source.ProfileComparer, IssueType.INFORMATIONAL, path, "Code "+l.getCode()+" display changed from '"+l.getDisplay()+"' to '"+r.getDisplay()+"'", IssueSeverity.WARNING));
VersionComparisonAnnotation.markChanged(r.getDisplayElement(), session.getForVersion());
session.markChanged(r.getDisplayElement(), l.getDisplayElement());
}
} else if (l.hasDisplay()) {
VersionComparisonAnnotation.markDeleted(r, session.getForVersion(), "display", l.getDisplayElement());
session.markDeleted(r, "display", l.getDisplayElement());
res.getMessages().add(new ValidationMessage(Source.ProfileComparer, IssueType.INFORMATIONAL, path, "Code "+l.getCode()+" display '"+l.getDisplay()+"' removed", IssueSeverity.WARNING));
sm.getChildren().add(new StructuralMatch<Element>(l.getDisplayElement(), null, vmI(IssueSeverity.INFORMATION, "Display Removed", "ValueSet.compose.include.concept")));
if (ci != null) {
@ -395,7 +393,7 @@ public class ValueSetComparer extends CanonicalResourceComparer {
}
def = true;
} else if (r.hasDisplay()) {
VersionComparisonAnnotation.markAdded(r.getDisplayElement(), session.getForVersion());
session.markAdded(r.getDisplayElement());
res.getMessages().add(new ValidationMessage(Source.ProfileComparer, IssueType.INFORMATIONAL, path, "Code "+l.getCode()+" display '"+r.getDisplay()+"' added", IssueSeverity.WARNING));
sm.getChildren().add(new StructuralMatch<Element>(null, r.getDisplayElement(), vmI(IssueSeverity.INFORMATION, "Display added", "ValueSet.compose.include.concept")));
if (ci != null) {

View File

@ -6,203 +6,87 @@ 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.CanonicalResource;
import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.StringType;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent;
import org.hl7.fhir.utilities.xhtml.NodeType;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
public class VersionComparisonAnnotation {
public enum AnotationType {
NoChange, Added, Changed, ChildrenDeleted, Deleted;
NoChange, Added, Changed, Deleted;
}
public static final String USER_DATA_NAME = "version-annotation";
private AnotationType type;
private String original;
private Map<String, List<Base>> deletedChildren;
private String version;
private CanonicalResourceComparison<? extends CanonicalResource> comp;
private VersionComparisonAnnotation(AnotationType type, String version) {
public VersionComparisonAnnotation(AnotationType type) {
super();
this.type = type;
this.version = version;
}
public static void annotate(Base base, String version, CanonicalResourceComparison<? extends CanonicalResource> comp) {
if (version != null) {
VersionComparisonAnnotation vca = (VersionComparisonAnnotation) base.getUserData(USER_DATA_NAME);
if (vca == null) {
vca = new VersionComparisonAnnotation(comp.noUpdates() ? AnotationType.NoChange : AnotationType.Changed, version);
base.setUserData(USER_DATA_NAME, vca);
}
vca.comp = comp;
}
public void added() {
assert type == AnotationType.NoChange;
type = AnotationType.Added;
}
public static void markAdded(Base focus, String version) {
if (version != null) {
focus.setUserData(USER_DATA_NAME, new VersionComparisonAnnotation(AnotationType.Added, version));
public void changed(Base orig) {
assert type == AnotationType.NoChange;
type = AnotationType.Changed;
if (original != null && orig.isPrimitive() && orig.primitiveValue().length() < 120) { // arbitrary, but we don't a whack of markdown
this.original = orig.primitiveValue();
}
}
public static void markChanged(Base focus, String version) {
if (version != null) {
focus.setUserData(USER_DATA_NAME, new VersionComparisonAnnotation(AnotationType.Changed, version));
}
public void deleted() {
assert type == AnotationType.NoChange;
type = AnotationType.Deleted;
}
public static void markDeleted(Base parent, String version, String name, Base other) {
if (version != null && other != null) {
VersionComparisonAnnotation vca = null;
if (parent.hasUserData(USER_DATA_NAME)) {
vca = (VersionComparisonAnnotation) parent.getUserData(USER_DATA_NAME);
assert vca.type != AnotationType.Added;
} else {
vca = new VersionComparisonAnnotation(AnotationType.ChildrenDeleted, 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);
public void deleted(String name, Base other) {
if (deletedChildren == null) {
deletedChildren = new HashMap<>();
}
if (!deletedChildren.containsKey(name)) {
deletedChildren.put(name, new ArrayList<>());
}
deletedChildren.get(name).add(other);
}
public void comp(CanonicalResourceComparison<? extends CanonicalResource> comp) {
assert this.comp == null;
// TODO Auto-generated method stub
if (!comp.noUpdates()) {
type = AnotationType.Changed;
}
this.comp = comp;
}
public static String getUserDataName() {
return USER_DATA_NAME;
}
public AnotationType getType() {
return type;
}
public void setType(AnotationType type) {
this.type = type;
}
public static XhtmlNode render(Base b, XhtmlNode x) {
if (b.hasUserData(USER_DATA_NAME)) {
VersionComparisonAnnotation self = (VersionComparisonAnnotation) b.getUserData(USER_DATA_NAME);
return self.render(x);
} else {
return x;
}
}
private XhtmlNode render(XhtmlNode x) {
switch (type) {
case Added:
XhtmlNode spanOuter = x.span("border: solid 1px #dddddd; margin: 2px; padding: 2px", null);
XhtmlNode spanInner = spanOuter.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 spanOuter;
case Changed:
spanOuter = x.span("border: solid 1px #dddddd; margin: 2px; padding: 2px", null);
spanInner = spanOuter.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This content has been changed since "+version);
spanInner.img("icon-change-edit.png", "icon");
spanInner.tx(" Changed:");
return spanOuter;
case Deleted:
spanOuter = x.span("border: solid 1px #dddddd; margin: 2px; padding: 2px", null);
spanInner = spanOuter.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This content has been removed since "+version);
spanInner.img("icon-change-remove.png", "icon");
spanInner.tx(" Removed:");
return spanOuter.strikethrough();
default:
return x;
}
public String getOriginal() {
return original;
}
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;
}
public Map<String, List<Base>> getDeletedChildren() {
return deletedChildren;
}
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 changed 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 removed since "+version);
spanInner.img("icon-change-remove.png", "icon");
spanInner.tx(" Removed:");
return divOuter.strikethrough();
default:
return x;
}
}
public static XhtmlNode renderRow(Base b, XhtmlNode tbl, XhtmlNode tr) {
if (b.hasUserData(USER_DATA_NAME)) {
VersionComparisonAnnotation self = (VersionComparisonAnnotation) b.getUserData(USER_DATA_NAME);
return self.renderRow(tbl, tr);
} else {
return tr.td();
}
}
private XhtmlNode renderRow(XhtmlNode tbl, XhtmlNode tr) {
switch (type) {
case Added:
if (tbl.isClass("grid")) {
tr.style("border: solid 1px #dddddd; margin: 2px; padding: 2px");
}
XhtmlNode td = tr.td();
XhtmlNode span = td.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This row of content has been added since "+version);
span.img("icon-change-add.png", "icon");
span.tx(" Added:");
XhtmlNode x = new XhtmlNode(NodeType.Element, "holder");
x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This row of content has been added since "+version).tx(" ");
tr.styleCells(x);
return td;
case Changed:
td = tr.td();
span = td.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This row of content has been changed since "+version);
span.img("icon-change-edit.png", "icon");
span.tx(" Changed:");
return td;
case Deleted:
tr.style("text-decoration: line-through");
td = tr.td();
span = td.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This content has been removed since "+version);
span.img("icon-change-remove.png", "icon");
span.tx(" Removed:");
x = new XhtmlNode(NodeType.Element, "holder");
x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px; text-decoration: none", "This row of content has been added since "+version).tx(" ");
tr.styleCells(x);
return td;
default:
return tr.td();
}
public CanonicalResourceComparison<? extends CanonicalResource> getComp() {
return comp;
}
public static boolean hasDeleted(Base base, String... names) {
boolean result = false;
if (base.hasUserData(USER_DATA_NAME)) {
@ -239,50 +123,5 @@ public class VersionComparisonAnnotation {
}
return result.isEmpty() ? null : result.get(0);
}
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;
}
}
public static void renderSummary(Base base, XhtmlNode x, String version, String... metadataFields) {
if (base.hasUserData(USER_DATA_NAME)) {
VersionComparisonAnnotation self = (VersionComparisonAnnotation) base.getUserData(USER_DATA_NAME);
switch (self.type) {
case Added:
XhtmlNode spanInner = x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This content has been added since "+version);
spanInner.img("icon-change-add.png", "icon");
spanInner.tx(" Added");
return;
case Changed:
if (self.comp.noChangeOtherThanMetadata(metadataFields)) {
x.span("color: #eeeeee").tx("n/c");
return;
} else {
spanInner = x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This content has been added since "+version);
spanInner.img("icon-change-edit.png", "icon");
spanInner.tx(" Changed");
}
return;
case Deleted:
spanInner = x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This content has been added since "+version);
spanInner.img("icon-change-remove.png", "icon");
spanInner.tx(" Removed");
return;
default:
x.span("color: #eeeeee").tx("n/c");
return;
}
} else {
x.span("color: #eeeeee").tx("--");
}
}
}

View File

@ -88,12 +88,12 @@ public class CodeSystemRenderer extends TerminologyRenderer {
tr.td().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Value", getContext().getLang()));
for (CodeSystemFilterComponent f : cs.getFilter()) {
tr = tbl.tr();
VersionComparisonAnnotation.render(f, tr.td()).tx(f.getCode());
VersionComparisonAnnotation.render(f.getDescriptionElement(), tr.td()).tx(f.getDescription());
renderStatus(f, tr.td()).tx(f.getCode());
renderStatus(f.getDescriptionElement(), tr.td()).tx(f.getDescription());
XhtmlNode td = tr.td();
for (Enumeration<org.hl7.fhir.r5.model.Enumerations.FilterOperator> t : f.getOperator())
VersionComparisonAnnotation.render(t, td).tx(t.asStringValue()+" ");
VersionComparisonAnnotation.render(f.getValueElement(), tr.td()).tx(f.getValue());
renderStatus(t, td).tx(t.asStringValue()+" ");
renderStatus(f.getValueElement(), tr.td()).tx(f.getValue());
}
}
}
@ -129,13 +129,13 @@ public class CodeSystemRenderer extends TerminologyRenderer {
if (hasRendered) {
tr.td().tx(ToolingExtensions.getPresentation(p, p.getCodeElement()));
}
VersionComparisonAnnotation.render(p, tr.td()).tx(p.getCode());
renderStatus(p, tr.td()).tx(p.getCode());
if (hasURI) {
VersionComparisonAnnotation.render(p.getUriElement(), tr.td()).tx(p.getUri());
renderStatus(p.getUriElement(), tr.td()).tx(p.getUri());
}
VersionComparisonAnnotation.render(p.getTypeElement(), tr.td()).tx(p.hasType() ? p.getType().toCode() : "");
renderStatus(p.getTypeElement(), tr.td()).tx(p.hasType() ? p.getType().toCode() : "");
if (hasDescription) {
VersionComparisonAnnotation.render(p.getDescriptionElement(), tr.td()).tx(p.getDescription());
renderStatus(p.getDescriptionElement(), tr.td()).tx(p.getDescription());
}
}
return true;
@ -174,7 +174,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
x.para().b().tx(getContext().getWorker().translator().translate("xhtml-gen-cs", "Concepts", getContext().getLang()));
}
XhtmlNode p = x.para();
VersionComparisonAnnotation.render(cs.getUrlElement(), p.param("cs")).code().tx(cs.getUrl());
renderStatus(cs.getUrlElement(), p.param("cs")).code().tx(cs.getUrl());
makeCasedParam(p.param("cased"), cs, cs.getCaseSensitiveElement());
makeHierarchyParam(p.param("h"), cs, cs.getHierarchyMeaningElement());
@ -247,7 +247,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
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");
renderStatus(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)) {
@ -260,7 +260,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
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);
renderStatus(caseSensitiveElement, x).tx(s);
} else if (VersionComparisonAnnotation.hasDeleted(cs, "caseSensitive")) {
makeCasedParam(x, null, (BooleanType) VersionComparisonAnnotation.getDeleted(cs, "caseSensitive").get(0));
} else {
@ -398,7 +398,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
tr.setAttribute("style", "background-color: #ffeeee");
}
XhtmlNode td = VersionComparisonAnnotation.renderRow(c, t, tr);
XhtmlNode td = renderStatusRow(c, t, tr);
if (hasHierarchy) {
td.addText(Integer.toString(level+1));
td = tr.td();
@ -425,9 +425,9 @@ public class CodeSystemRenderer extends TerminologyRenderer {
if (c != null &&c.hasDefinitionElement()) {
if (getContext().getLang() == null) {
if (hasMarkdownInDefinitions(cs)) {
addMarkdown(VersionComparisonAnnotation.renderDiv(c.getDefinitionElement(), td), c.getDefinition());
addMarkdown(renderStatusDiv(c.getDefinitionElement(), td), c.getDefinition());
} else {
VersionComparisonAnnotation.render(c.getDefinitionElement(), td).addText(c.getDefinition());
renderStatus(c.getDefinitionElement(), td).addText(c.getDefinition());
}
} else if (getContext().getLang().equals("*")) {
boolean sl = false;
@ -436,9 +436,9 @@ public class CodeSystemRenderer extends TerminologyRenderer {
sl = true;
td.addText((sl ? cs.getLanguage("en")+": " : ""));
if (hasMarkdownInDefinitions(cs))
addMarkdown(VersionComparisonAnnotation.renderDiv(c.getDefinitionElement(), td), c.getDefinition());
addMarkdown(renderStatusDiv(c.getDefinitionElement(), td), c.getDefinition());
else
VersionComparisonAnnotation.render(c.getDefinitionElement(), td).addText(c.getDefinition());
renderStatus(c.getDefinitionElement(), td).addText(c.getDefinition());
for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) {
if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && !c.getDefinition().equalsIgnoreCase(cd.getValue())) {
td.br();
@ -446,7 +446,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
}
}
} else if (getContext().getLang().equals(cs.getLanguage()) || (getContext().getLang().equals("en") && !cs.hasLanguage())) {
VersionComparisonAnnotation.render(c.getDefinitionElement(), td).addText(c.getDefinition());
renderStatus(c.getDefinitionElement(), td).addText(c.getDefinition());
} else {
for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) {
if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "definition") && cd.hasLanguage() && cd.getLanguage().equals(getContext().getLang())) {
@ -623,7 +623,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
public void renderDisplayName(ConceptDefinitionComponent c, CodeSystem cs, XhtmlNode td) {
if (c.hasDisplayElement()) {
if (getContext().getLang() == null) {
VersionComparisonAnnotation.render(c.getDisplayElement(), td).addText(c.getDisplay());
renderStatus(c.getDisplayElement(), td).addText(c.getDisplay());
} else if (getContext().getLang().equals("*")) {
boolean sl = false;
for (ConceptDefinitionDesignationComponent cd : c.getDesignation())
@ -637,7 +637,7 @@ public class CodeSystemRenderer extends TerminologyRenderer {
}
}
} else if (getContext().getLang().equals(cs.getLanguage()) || (getContext().getLang().equals("en") && !cs.hasLanguage())) {
VersionComparisonAnnotation.render(c.getDisplayElement(), td).addText(c.getDisplay());
renderStatus(c.getDisplayElement(), td).addText(c.getDisplay());
} else {
for (ConceptDefinitionDesignationComponent cd : c.getDesignation()) {
if (cd.getUse().is("http://terminology.hl7.org/CodeSystem/designation-usage", "display") && cd.hasLanguage() && cd.getLanguage().equals(getContext().getLang())) {

View File

@ -1,6 +1,8 @@
package org.hl7.fhir.r5.renderers;
import org.hl7.fhir.r5.comparison.VersionComparisonAnnotation;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.renderers.utils.RenderingContext;
import org.hl7.fhir.r5.renderers.utils.RenderingContext.GenerationRules;
import org.hl7.fhir.r5.renderers.utils.RenderingContext.KnownLinkType;
@ -11,6 +13,7 @@ import org.hl7.fhir.utilities.StandardsStatus;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.MarkDownProcessor.Dialect;
import org.hl7.fhir.utilities.validation.ValidationOptions;
import org.hl7.fhir.utilities.xhtml.NodeType;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
/**
@ -84,4 +87,155 @@ public class Renderer extends TranslatingUtilities {
}
}
protected XhtmlNode renderStatus(Base b, XhtmlNode x) {
if (b == null || context.getChangeVersion() == null) {
return x;
}
VersionComparisonAnnotation vca = (VersionComparisonAnnotation) b.getUserData(VersionComparisonAnnotation.USER_DATA_NAME);
if (vca == null) {
return x;
}
switch (vca.getType()) {
case Added:
XhtmlNode spanOuter = x.span("border: solid 1px #dddddd; margin: 2px; padding: 2px", null);
XhtmlNode spanInner = spanOuter.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This content has been added since "+context.getChangeVersion());
spanInner.img("icon-change-add.png", "icon");
spanInner.tx(" Added:");
return spanOuter;
case Changed:
spanOuter = x.span("border: solid 1px #dddddd; margin: 2px; padding: 2px", null);
spanInner = spanOuter.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This content has been changed since "+context.getChangeVersion()+(vca.getOriginal() != null ? " (was '"+vca.getOriginal()+"')" : ""));
spanInner.img("icon-change-edit.png", "icon");
spanInner.tx(" Changed:");
return spanOuter;
case Deleted:
spanOuter = x.span("border: solid 1px #dddddd; margin: 2px; padding: 2px", null);
spanInner = spanOuter.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This content has been removed since "+context.getChangeVersion());
spanInner.img("icon-change-remove.png", "icon");
spanInner.tx(" Removed:");
return spanOuter.strikethrough();
default:
return x;
}
}
protected XhtmlNode renderStatusDiv(Base b, XhtmlNode x) {
if (b == null || context.getChangeVersion() == null) {
return x;
}
VersionComparisonAnnotation vca = (VersionComparisonAnnotation) b.getUserData(VersionComparisonAnnotation.USER_DATA_NAME);
if (vca == null) {
return x;
}
switch (vca.getType()) {
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 "+context.getChangeVersion());
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 changed since "+context.getChangeVersion()+(vca.getOriginal() != null ? " (was '"+(vca.getOriginal())+"')" : ""));
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 removed since "+context.getChangeVersion());
spanInner.img("icon-change-remove.png", "icon");
spanInner.tx(" Removed:");
return divOuter.strikethrough();
default:
return x;
}
}
protected XhtmlNode renderStatusRow(Base b, XhtmlNode tbl, XhtmlNode tr) {
if (b == null || context.getChangeVersion() == null) {
return tr.td();
}
VersionComparisonAnnotation vca = (VersionComparisonAnnotation) b.getUserData(VersionComparisonAnnotation.USER_DATA_NAME);
if (vca == null) {
return tr.td();
}
switch (vca.getType()) {
case Added:
if (tbl.isClass("grid")) {
tr.style("border: solid 1px #dddddd; margin: 2px; padding: 2px");
}
XhtmlNode td = tr.td();
XhtmlNode span = td.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This row of content has been added since "+context.getChangeVersion());
span.img("icon-change-add.png", "icon");
span.tx(" Added:");
XhtmlNode x = new XhtmlNode(NodeType.Element, "holder");
x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This row of content has been added since "+context.getChangeVersion()).tx(" ");
tr.styleCells(x);
return td;
case Changed:
td = tr.td();
span = td.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This row of content has been changed since"+context.getChangeVersion()+(vca.getOriginal() != null ? " (was '"+vca.getOriginal()+"')" : ""));
span.img("icon-change-edit.png", "icon");
span.tx(" Changed:");
return td;
case Deleted:
tr.style("text-decoration: line-through");
td = tr.td();
span = td.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This content has been removed since "+context.getChangeVersion());
span.img("icon-change-remove.png", "icon");
span.tx(" Removed:");
x = new XhtmlNode(NodeType.Element, "holder");
x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px; text-decoration: none", "This row of content has been added since "+context.getChangeVersion()).tx(" ");
tr.styleCells(x);
return td;
default:
return tr.td();
}
}
//
//
//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;
// }
//}
//
//public static void renderSummary(Base base, XhtmlNode x, String version, String... metadataFields) {
// if (base.hasUserData(USER_DATA_NAME)) {
// VersionComparisonAnnotation self = (VersionComparisonAnnotation) base.getUserData(USER_DATA_NAME);
// switch (self.type) {
// case Added:
// XhtmlNode spanInner = x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This content has been added since "+version);
// spanInner.img("icon-change-add.png", "icon");
// spanInner.tx(" Added");
// return;
// case Changed:
// if (self.comp.noChangeOtherThanMetadata(metadataFields)) {
// x.span("color: #eeeeee").tx("n/c");
// return;
// } else {
// spanInner = x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This content has been changed since "+version+(self.original != null ? " (was '"+(self.original.primitiveValue())+"')" : ""));
// spanInner.img("icon-change-edit.png", "icon");
// spanInner.tx(" Changed");
// }
// return;
// case Deleted:
// spanInner = x.span("background-color: #fff2ff; border-left: solid 3px #ffa0ff; margin: 2px; padding: 2px", "This content has been added since "+version);
// spanInner.img("icon-change-remove.png", "icon");
// spanInner.tx(" Removed");
// return;
// default:
// x.span("color: #eeeeee").tx("n/c");
// return;
// }
// } else {
// x.span("color: #eeeeee").tx("--");
// }
//}
}

View File

@ -7,6 +7,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Stack;
import java.util.Map;
import java.util.Set;
@ -54,6 +55,7 @@ import org.hl7.fhir.r5.model.Enumerations.BindingStrength;
import org.hl7.fhir.r5.model.Extension;
import org.hl7.fhir.r5.model.IdType;
import org.hl7.fhir.r5.model.IntegerType;
import org.hl7.fhir.r5.model.MarkdownType;
import org.hl7.fhir.r5.model.PrimitiveType;
import org.hl7.fhir.r5.model.Quantity;
import org.hl7.fhir.r5.model.Resource;
@ -79,6 +81,7 @@ import org.hl7.fhir.utilities.StandardsStatus;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
import org.hl7.fhir.utilities.i18n.I18nConstants;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator;
import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Cell;
import org.hl7.fhir.utilities.xhtml.HierarchicalTableGenerator.Piece;
@ -172,10 +175,10 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
private abstract class ItemWithStatus {
ListItemStatus status = ListItemStatus.New; // new, unchanged, removed
protected abstract void renderDetails(XhtmlNode f);
protected abstract void renderDetails(XhtmlNode f) throws IOException;
protected abstract boolean matches(ItemWithStatus other);
public void render(XhtmlNode x) {
public void render(XhtmlNode x) throws IOException {
XhtmlNode f = x;
if (status == ListItemStatus.Unchanged) {
f = unchanged(f);
@ -247,14 +250,25 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
}
public void renderDetails(XhtmlNode f) {
f = renderStatus(value, f);
f.b().attribute("title", "Formal Invariant Identifier").tx(value.getKey());
f.tx(": ");
f.tx(value.getHuman());
if (value.hasHuman()) {
renderStatus(value.getHumanElement(), f).tx(value.getHuman());
} else if (VersionComparisonAnnotation.hasDeleted(value, "human")) {
Base b =VersionComparisonAnnotation.getDeletedItem(value, "human");
renderStatus(b, f).tx(b.primitiveValue());
}
f.tx(" (");
if (status == ListItemStatus.New) {
f.code().tx(value.getExpression());
if (value.hasExpression()) {
renderStatus(value.getExpressionElement(), f).code().tx(value.getExpression());
} else if (VersionComparisonAnnotation.hasDeleted(value, "expression")) {
Base b = VersionComparisonAnnotation.getDeletedItem(value, "expression");
renderStatus(b, f).code().tx(b.primitiveValue());
}
} else {
f.tx(value.getExpression());
renderStatus(value.getExpressionElement(), f).tx(value.getExpression());
}
f.tx(")");
}
@ -293,6 +307,27 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
}
f.tx(value.asStringValue());
}
}
private class DataValueWithStatus extends ItemWithStatus {
DataType value;
protected DataValueWithStatus(DataType value) {
this.value = value;
}
protected boolean matches(ItemWithStatus other) {
return ((ValueWithStatus) other).value.equalsDeep(value);
}
public void renderDetails(XhtmlNode f) throws IOException {
if (value.hasUserData("render.link")) {
f = f.ah(value.getUserString("render.link"));
}
f.tx(summarize(value));
}
}
@ -3060,8 +3095,6 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
return null;
}
private ElementDefinition getUrlFor(StructureDefinition ed, ElementDefinition c) {
int i = ed.getSnapshot().getElement().indexOf(c) + 1;
while (i < ed.getSnapshot().getElement().size() && ed.getSnapshot().getElement().get(i).getPath().startsWith(c.getPath()+".")) {
@ -3083,6 +3116,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
generateAnchors(stack, allAnchors);
checkInScope(stack, excluded);
}
Stack<ElementDefinition> dstack = new Stack<>();
for (ElementDefinition ec : elements) {
if ((incProfiledOut || !"0".equals(ec.getMax())) && !excluded.contains(ec)) {
ElementDefinition compareElement = null;
@ -3094,7 +3128,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
List<String> anchors = makeAnchors(ec, anchorPrefix);
String title = ec.getId();
XhtmlNode tr = t.tr();
XhtmlNode sp = VersionComparisonAnnotation.render(ec, tr.td("structure").colspan(2).spanClss("self-link-parent"));
XhtmlNode sp = renderStatus(ec, tr.td("structure").colspan(2).spanClss("self-link-parent"));
for (String s : anchors) {
sp.an(s).tx(" ");
}
@ -3116,6 +3150,10 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
// generateElementInner(b, extDefn, extDefn.getSnapshot().getElement().get(0), valueDefn == null ? 2 : 3, valueDefn);
}
} else {
while (!dstack.isEmpty() && !isParent(dstack.peek(), ec)) {
finish(t, sd, dstack.pop(), mode);
}
dstack.push(ec);
generateElementInner(t, sd, ec, mode, null, compareElement, null, false);
if (ec.hasSlicing()) {
generateSlicing(t, sd, ec, ec.getSlicing(), compareElement, mode, false);
@ -3125,20 +3163,26 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
t.tx("\r\n");
i++;
}
for (Base b : VersionComparisonAnnotation.getDeleted(sd, "element")) {
while (!dstack.isEmpty()) {
finish(t, sd, dstack.pop(), mode);
}
finish(t, sd, null, mode);
}
private void finish(XhtmlNode t, StructureDefinition sd, ElementDefinition ed, int mode) throws FHIRException, IOException {
for (Base b : VersionComparisonAnnotation.getDeleted(ed == null ? sd : ed, "element")) {
ElementDefinition ec = (ElementDefinition) b;
String title = ec.getId();
XhtmlNode tr = t.tr();
XhtmlNode sp = VersionComparisonAnnotation.render(ec, tr.td("structure").colspan(2).spanClss("self-link-parent"));
sp.span("color: grey", null).tx(Integer.toString(i++));
XhtmlNode sp = renderStatus(ec, tr.td("structure").colspan(2).spanClss("self-link-parent"));
sp.span("color: grey", null).tx("--");
sp.b().tx(". "+title);
generateElementInner(t, sd, ec, mode, null, null, null, true);
if (ec.hasSlicing()) {
generateSlicing(t, sd, ec, ec.getSlicing(), null, mode, true);
}
t.tx("\r\n");
}
}
}
@ -3310,7 +3354,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
if (md.hasValue()) {
String xhtml = hostMd.processMarkdown(location, md);
XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
VersionComparisonAnnotation.renderDiv(md, x).add(new XhtmlParser().parseFragment(xhtml));
renderStatusDiv(md, x).add(new XhtmlParser().parseFragment(xhtml));
return x;
} else {
return null;
@ -3369,10 +3413,10 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
if (mode != GEN_MODE_KEY) {
if (newStr != null) {
VersionComparisonAnnotation.render(source, x).ah(nLink).tx(newStr);
renderStatus(source, x).ah(nLink).tx(newStr);
} else if (VersionComparisonAnnotation.hasDeleted(parent, name)) {
PrimitiveType p = (PrimitiveType) VersionComparisonAnnotation.getDeletedItem(parent, name);
VersionComparisonAnnotation.render(p, x).tx(p.primitiveValue());
renderStatus(p, x).tx(p.primitiveValue());
} else {
return null;
}
@ -3380,7 +3424,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
if (newStr==null || newStr.isEmpty()) {
return null;
} else {
VersionComparisonAnnotation.render(source, x).ah(nLink).tx(newStr);
renderStatus(source, x).ah(nLink).tx(newStr);
}
} else if (oldStr!=null && !oldStr.isEmpty() && (newStr==null || newStr.isEmpty())) {
if (mode == GEN_MODE_DIFF) {
@ -3396,10 +3440,10 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
}
} else if (newStr.startsWith(oldStr)) {
unchanged(x).ah(oLink).tx(oldStr);
VersionComparisonAnnotation.render(source, x).ah(nLink).tx(newStr.substring(oldStr.length()));
renderStatus(source, x).ah(nLink).tx(newStr.substring(oldStr.length()));
} else {
// TODO: improve comparision in this fall-through case, by looking for matches in sub-paragraphs?
VersionComparisonAnnotation.render(source, x).ah(nLink).tx(newStr);
renderStatus(source, x).ah(nLink).tx(newStr);
removed(x).ah(oLink).tx(oldStr);
}
return x;
@ -3432,21 +3476,25 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
}
private void generateElementInner(XhtmlNode tbl, StructureDefinition sd, ElementDefinition d, int mode, ElementDefinition value, ElementDefinition compare, ElementDefinition compareValue, boolean strikethrough) throws FHIRException, IOException {
System.out.println(d.getPath());
boolean root = !d.getPath().contains(".");
boolean slicedExtension = d.hasSliceName() && (d.getPath().endsWith(".extension") || d.getPath().endsWith(".modifierExtension"));
// int slicedExtensionMode = (mode == GEN_MODE_KEY) && slicedExtension ? GEN_MODE_SNAP : mode; // see ProfileUtilities.checkExtensionDoco / Task 3970
if (d.hasSliceName()) {
tableRow(tbl, "SliceName", "profiling.html#slicing", strikethrough).tx(d.getSliceName());
tableRow(tbl, "Slice Name", "profiling.html#slicing", strikethrough, compareString(d.getSliceName(), d.getSliceNameElement(), null, (compare != null ? compare.getSliceName() : null), d, null, "sliceName", mode));
tableRow(tbl, "Slice Constraining", "profiling.html#slicing", strikethrough, compareString(encodeValue(d.getSliceIsConstrainingElement()), d.getSliceIsConstrainingElement(), null, (compare != null ? encodeValue(compare.getSliceIsConstrainingElement()) : null), d, null, "sliceName", mode));
}
tableRow(tbl, "Definition", null, strikethrough, compareMarkdown(sd.getName(), d.getDefinitionElement(), (compare==null) || slicedExtension ? null : compare.getDefinitionElement(), mode));
tableRow(tbl, "Short", null, strikethrough, compareString(d.hasShort() ? d.getShort() : null, d.getShortElement(), null, "short", d, compare!= null && compare.hasShortElement() ? compare.getShort() : null, null, mode));
tableRow(tbl, "Comments", null, strikethrough, compareMarkdown(sd.getName(), d.getCommentElement(), (compare==null) || slicedExtension ? null : compare.getCommentElement(), mode));
tableRow(tbl, "Note", null, strikethrough, businessIdWarning(sd.getName(), tail(d.getPath())));
tableRow(tbl, "Control", "conformance-rules.html#conformance", strikethrough, describeCardinality(d, compare, mode));
tableRow(tbl, "Binding", "terminologies.html", strikethrough, describeBinding(sd, d, d.getPath(), compare, mode));
if (d.hasContentReference()) {
tableRow(tbl, "Type", null, strikethrough, "See " + d.getContentReference().substring(1));
} else {
tableRow(tbl, "Type", "datatypes.html", strikethrough, describeTypes(d.getType(), false, compare, mode, value, compareValue, sd));
tableRow(tbl, "Type", "datatypes.html", strikethrough, describeTypes(d.getType(), false, d, compare, mode, value, compareValue, sd));
}
if (d.hasExtension(ToolingExtensions.EXT_DEF_TYPE)) {
tableRow(tbl, "Default Type", "datatypes.html", strikethrough, ToolingExtensions.readStringExtension(d, ToolingExtensions.EXT_DEF_TYPE));
@ -3457,7 +3505,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
if (d.getPath().endsWith("[x]") && !d.prohibited()) {
tableRow(tbl, "[x] Note", null, strikethrough).ahWithText("See ", spec("formats.html#choice"), null, "Choice of Data Types", " for further information about how to use [x]");
}
tableRow(tbl, "Is Modifier", "conformance-rules.html#ismodifier", strikethrough, displayBoolean(d.getIsModifier(), d.getIsModifierElement(), "isModifier", d, null, mode));
tableRow(tbl, "Is Modifier", "conformance-rules.html#ismodifier", strikethrough, presentModifier(d, mode, compare));
if (d.getMustHaveValue()) {
tableRow(tbl, "Primitive Value", "elementdefinition.html#primitives", strikethrough, "This primitive type must have a value (the value must be present, and cannot be replaced by an extension)");
} else if (d.hasValueAlternatives()) {
@ -3471,7 +3519,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
tableRow(tbl, "Must Support", "conformance-rules.html#mustSupport", strikethrough, displayBoolean(d.getMustSupport(), d.getMustSupportElement(), "mustSupport", d, compare==null ? null : compare.getMustSupportElement(), mode));
if (d.getMustSupport()) {
if (hasMustSupportTypes(d.getType())) {
tableRow(tbl, "Must Support Types", "datatypes.html", strikethrough, describeTypes(d.getType(), true, compare, mode, null, null, sd));
tableRow(tbl, "Must Support Types", "datatypes.html", strikethrough, describeTypes(d.getType(), true, d, compare, mode, null, null, sd));
} else if (hasChoices(d.getType())) {
tableRow(tbl, "Must Support Types", "datatypes.html", strikethrough, "No must-support rules about the choice of types/profiles");
}
@ -3552,19 +3600,37 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
tableRow(tbl, "Summary", "search.html#summary", strikethrough, Boolean.toString(d.getIsSummary()));
}
tableRow(tbl, "Requirements", null, strikethrough, compareMarkdown(sd.getName(), d.getRequirementsElement(), (compare==null) || slicedExtension ? null : compare.getRequirementsElement(), mode));
tableRow(tbl, "Label", null, strikethrough, compareString(d.getLabel(), d.getLabelElement(), null, "label", d, (compare != null ? compare.getLabel() : null), null, mode));
tableRow(tbl, "Alternate Names", null, strikethrough, compareSimpleTypeLists(d.getAlias(), ((compare==null) || slicedExtension ? null : compare.getAlias()), mode));
tableRow(tbl, "Comments", null, strikethrough, compareMarkdown(sd.getName(), d.getCommentElement(), (compare==null) || slicedExtension ? null : compare.getCommentElement(), mode));
tableRow(tbl, "Definitional Codes", null, strikethrough, compareDataTypeLists(d.getCode(), ((compare==null) || slicedExtension ? null : compare.getCode()), mode));
tableRow(tbl, "Min Value", null, strikethrough, compareString(d.hasMinValue() ? encodeValue(d.getMinValue()) : null, d.getMinValue(), null, "minValue", d, compare!= null && compare.hasMinValue() ? encodeValue(compare.getMinValue()) : null, null, mode));
tableRow(tbl, "Max Value", null, strikethrough, compareString(d.hasMaxValue() ? encodeValue(d.getMaxValue()) : null, d.getMaxValue(), null, "maxValue", d, compare!= null && compare.hasMaxValue() ? encodeValue(compare.getMaxValue()) : null, null, mode));
tableRow(tbl, "Max Length", null, strikethrough, compareString(d.hasMaxLength() ? toStr(d.getMaxLength()) : null, d.getMaxLengthElement(), null, "maxLength", d, compare!= null && compare.hasMaxLengthElement() ? toStr(compare.getMaxLength()) : null, null, mode));
tableRow(tbl, "Value Required", null, strikethrough, compareString(encodeValue(d.getMustHaveValueElement()), d.getMustHaveValueElement(), null, (compare != null ? encodeValue(compare.getMustHaveValueElement()) : null), d, null, "mustHaveValueElement", mode));
tableRow(tbl, "Value Alternatives", null, strikethrough, compareSimpleTypeLists(d.getValueAlternatives(), ((compare==null) || slicedExtension ? null : compare.getValueAlternatives()), mode));
tableRow(tbl, "Default Value", null, strikethrough, encodeValue(d.getDefaultValue(), "defaultValue", d, compare==null ? null : compare.getDefaultValue(), mode));
tableRow(tbl, "Meaning if Missing", null, strikethrough, d.getMeaningWhenMissing());
tableRow(tbl, "Fixed Value", null, strikethrough, encodeValue(d.getFixed(), "fixed", d, compare==null ? null : compare.getFixed(), mode));
tableRow(tbl, "Pattern Value", null, strikethrough, encodeValue(d.getPattern(), "pattern", d, compare==null ? null : compare.getPattern(), mode));
tableRow(tbl, "Example", null, strikethrough, encodeValues(d.getExample()));
tableRow(tbl, "Invariants", null, strikethrough, invariants(d.getConstraint(), compare==null ? null : compare.getConstraint(), mode));
tableRow(tbl, "Invariants", null, strikethrough, invariants(d.getConstraint(), compare==null ? null : compare.getConstraint(), d, mode));
tableRow(tbl, "LOINC Code", null, strikethrough, getMapping(sd, d, LOINC_MAPPING, compare, mode));
tableRow(tbl, "SNOMED-CT Code", null, strikethrough, getMapping(sd, d, SNOMED_MAPPING, compare, mode));
tbl.tx("\r\n");
}
private XhtmlNode presentModifier(ElementDefinition d, int mode, ElementDefinition compare) throws FHIRException, IOException {
XhtmlNode x1 = compareString(encodeValue(d.getIsModifierElement()), d.getIsModifierElement(), null, "isModifier", d, compare == null ? null : encodeValue(compare.getIsModifierElement()), null, mode);
if (x1 != null) {
XhtmlNode x2 = compareString(encodeValue(d.getIsModifierReasonElement()), d.getIsModifierReasonElement(), null, "isModifierReason", d, compare == null ? null : encodeValue(compare.getIsModifierReasonElement()), null, mode);
if (x2 != null) {
x1.tx(" because ");
x1.copyAllContent(x2);
}
}
return x1;
}
private String spec(String name) {
return Utilities.pathURL(VersionUtilities.getSpecUrl(context.getWorker().getVersion()) , name);
}
@ -3817,6 +3883,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
x.tx(", and defines no discriminators to differentiate the slices");
}
tableRow(tbl, "Slicing", "profiling.html#slicing", strikethrough, x);
tbl.tx("\r\n");
}
private XhtmlNode tableRow(XhtmlNode x, String name, String defRef, boolean strikethrough) throws IOException {
@ -3896,18 +3963,18 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
return null;
}
private XhtmlNode describeCardinality(ElementDefinition d, ElementDefinition compare, int mode) {
private XhtmlNode describeCardinality(ElementDefinition d, ElementDefinition compare, int mode) throws IOException {
XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
if (compare==null || mode==GEN_MODE_DIFF) {
if (!d.hasMax() && !d.hasMin())
return null;
else if (d.getMax() == null) {
VersionComparisonAnnotation.render(d.getMinElement(), x).tx(toStr(d.getMin()));
renderStatus(d.getMinElement(), x).tx(toStr(d.getMin()));
x.tx("..?");
} else {
VersionComparisonAnnotation.render(d.getMinElement(), x).tx(toStr(d.getMin()));
renderStatus(d.getMinElement(), x).tx(toStr(d.getMin()));
x.tx( "..");
VersionComparisonAnnotation.render(d.getMaxElement(), x).tx( d.getMax());
renderStatus(d.getMaxElement(), x).tx( d.getMax());
}
} else {
if (!(mode==GEN_MODE_DIFF && (d.getMin()==compare.getMin() || d.getMin()==0))) {
@ -3936,19 +4003,21 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
return false;
}
private XhtmlNode describeTypes(List<TypeRefComponent> types, boolean mustSupportOnly, ElementDefinition compare, int mode, ElementDefinition value, ElementDefinition compareValue, StructureDefinition sd) throws FHIRException {
private XhtmlNode describeTypes(List<TypeRefComponent> types, boolean mustSupportOnly, ElementDefinition ed, ElementDefinition compare, int mode, ElementDefinition value, ElementDefinition compareValue, StructureDefinition sd) throws FHIRException, IOException {
if (types.isEmpty())
return null;
List<TypeRefComponent> compareTypes = compare==null ? new ArrayList<>() : compare.getType();
XhtmlNode ret = new XhtmlNode(NodeType.Element, "div");
if ((!mustSupportOnly && types.size() == 1 && compareTypes.size() <=1) || (mustSupportOnly && mustSupportCount(types) == 1)) {
if ((!mustSupportOnly && types.size() == 1 && compareTypes.size() <=1 && (mode != GEN_MODE_DIFF || !VersionComparisonAnnotation.hasDeleted(ed, "type"))) || (mustSupportOnly && mustSupportCount(types) == 1)) {
if (!mustSupportOnly || isMustSupport(types.get(0))) {
describeType(ret, types.get(0), mustSupportOnly, compareTypes.size()==0 ? null : compareTypes.get(0), mode, sd);
}
} else {
boolean first = true;
ret.tx("Choice of: ");
if (types.size() > 1) {
ret.tx("Choice of: ");
}
Map<String,TypeRefComponent> map = new HashMap<String, TypeRefComponent>();
for (TypeRefComponent t : compareTypes) {
map.put(t.getCode(), t);
@ -3970,6 +4039,13 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
ret.tx(", ");
describeType(removed(ret), t, mustSupportOnly, null, mode, sd);
}
if (mode == GEN_MODE_DIFF) {
for (Base b : VersionComparisonAnnotation.getDeleted(ed, "type")) {
TypeRefComponent t = (TypeRefComponent) b;
ret.tx(", ");
describeType(ret, t, false, null, mode, sd);
}
}
}
if (value != null) {
XhtmlNode xt = processSecondary(mode, value, compareValue, mode, sd);
@ -3980,7 +4056,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
return ret;
}
private XhtmlNode processSecondary(int mode, ElementDefinition value, ElementDefinition compareValue, int compMode, StructureDefinition sd) throws FHIRException {
private XhtmlNode processSecondary(int mode, ElementDefinition value, ElementDefinition compareValue, int compMode, StructureDefinition sd) throws FHIRException, IOException {
switch (mode) {
case 1:
return null;
@ -3991,7 +4067,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
case 3:
x = new XhtmlNode(NodeType.Element, "div");
x.tx(" (Extension Type: ");
x.copyAllContent(describeTypes(value.getType(), false, compareValue, compMode, null, null, sd));
x.copyAllContent(describeTypes(value.getType(), false, value, compareValue, compMode, null, null, sd));
x.tx(")");
return x;
default:
@ -4011,7 +4087,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
}
private void describeType(XhtmlNode x, TypeRefComponent t, boolean mustSupportOnly, TypeRefComponent compare, int mode, StructureDefinition sd) throws FHIRException {
private void describeType(XhtmlNode x, TypeRefComponent t, boolean mustSupportOnly, TypeRefComponent compare, int mode, StructureDefinition sd) throws FHIRException, IOException {
if (t.getWorkingCode() == null) {
return;
}
@ -4021,9 +4097,9 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
boolean ts = false;
if (t.getWorkingCode().startsWith("xs:")) {
ts = compareString(x, t.getWorkingCode(), t.getCodeElement(), null, "code", t, compare==null ? null : compare.getWorkingCode(), null, mode);
ts = compareString(x, t.getWorkingCode(), t, null, "code", t, compare==null ? null : compare.getWorkingCode(), null, mode);
} else {
ts = compareString(x, t.getWorkingCode(), t.getCodeElement(), getTypeLink(t, sd), "code", t, compare==null ? null : compare.getWorkingCode(), compare==null ? null : getTypeLink(compare, sd), mode);
ts = compareString(x, t.getWorkingCode(), t, getTypeLink(t, sd), "code", t, compare==null ? null : compare.getWorkingCode(), compare==null ? null : getTypeLink(compare, sd), mode);
}
if ((!mustSupportOnly && (t.hasProfile() || (compare!=null && compare.hasProfile()))) || isMustSupport(t.getProfile())) {
@ -4140,7 +4216,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
}
private XhtmlNode invariants(List<ElementDefinitionConstraintComponent> originalList, List<ElementDefinitionConstraintComponent> compareList, int mode) {
private XhtmlNode invariants(List<ElementDefinitionConstraintComponent> originalList, List<ElementDefinitionConstraintComponent> compareList, ElementDefinition parent, int mode) throws IOException {
StatusList<InvariantWithStatus> list = new StatusList<>();
for (ElementDefinitionConstraintComponent v : originalList) {
if (!v.isEmpty()) {
@ -4161,6 +4237,11 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
if (first) first = false; else x.br();
t.render(x);
}
for (Base b : VersionComparisonAnnotation.getDeleted(parent, "invariant")) {
if (first) first = false; else x.br();
InvariantWithStatus ts = new InvariantWithStatus((ElementDefinitionConstraintComponent) b);
ts.render(x);
}
return x;
}
@ -4172,7 +4253,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
ElementDefinitionBindingComponent compBinding = compare == null ? null : compare.getBinding();
XhtmlNode bindingDesc = null;
if (binding.hasDescription()) {
StringType newBinding = PublicationHacker.fixBindingDescriptions(context.getContext(), binding.getDescriptionElement());
MarkdownType newBinding = PublicationHacker.fixBindingDescriptions(context.getContext(), binding.getDescriptionElement());
if (mode == GEN_MODE_SNAP || mode == GEN_MODE_MS) {
bindingDesc = new XhtmlNode(NodeType.Element, "div");
bindingDesc.add(new XhtmlParser().parseFragment(hostMd.processMarkdown("Binding.description", newBinding)));
@ -4181,22 +4262,13 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
bindingDesc = compareMarkdown("Binding.description", newBinding, oldBinding, mode);
}
}
if (!binding.hasValueSet())
if (!binding.hasValueSet()) {
return bindingDesc;
}
XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
var nsp = x.span();
renderBinding(nsp, binding, path, sd);
if (compBinding!=null ) {
var osp = x.span();
renderBinding(osp, compBinding, path, sd);
if (osp.allText().equals(nsp.allText())) {
nsp.style(unchangedStyle());
x.remove(osp);
} else {
osp.style(removedStyle());
}
}
renderBinding(nsp, binding, compBinding, path, sd, mode);
if (bindingDesc != null) {
if (isSimpleContent(bindingDesc)) {
x.tx(": ");
@ -4232,16 +4304,11 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
return bindingDesc.getChildNodes().size() == 1 && bindingDesc.getChildNodes().get(0).isPara();
}
private void renderBinding(XhtmlNode span, ElementDefinitionBindingComponent binding, String path, StructureDefinition sd) {
private void renderBinding(XhtmlNode span, ElementDefinitionBindingComponent binding, ElementDefinitionBindingComponent compare, String path, StructureDefinition sd, int mode) {
compareString(span, conf(binding), binding.getStrengthElement(), null, "strength", binding, compare == null ? null : conf(compare), null, mode);
span.tx(" ");
BindingResolution br = context.getPkp().resolveBinding(sd, binding, path);
span.tx(conf(binding));
if (br.url == null) {
span.code().tx(br.display);
} else {
span.ah(br.url).tx(br.display);
}
span.tx(confTail(binding));
compareString(span, br.display, binding.getValueSetElement(), br.url, "valueSet", binding, compare == null ? null : compare.getValueSet(), null, mode);
}
private String stripPara(String s) {
@ -4254,13 +4321,6 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
return s;
}
private String confTail(ElementDefinitionBindingComponent def) {
if (def.getStrength() == BindingStrength.EXTENSIBLE)
return "; other codes may be used where these codes are not suitable";
else
return "";
}
private String conf(ElementDefinitionBindingComponent def) {
if (def.getStrength() == null) {
return "For codes, see ";
@ -4271,7 +4331,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
case PREFERRED:
return "The codes SHOULD be taken from ";
case EXTENSIBLE:
return "The codes SHALL be taken from ";
return "Unless not suitable, these codes SHALL be taken from ";
case REQUIRED:
return "The codes SHALL be taken from ";
default:
@ -4348,12 +4408,12 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
return compareString(Utilities.escapeXml(newMap), null, null, "mapping", d, Utilities.escapeXml(oldMap), null, mode);
}
private XhtmlNode compareSimpleTypeLists(List<? extends PrimitiveType> original, List<? extends PrimitiveType> compare, int mode) {
private XhtmlNode compareSimpleTypeLists(List<? extends PrimitiveType> original, List<? extends PrimitiveType> compare, int mode) throws IOException {
return compareSimpleTypeLists(original, compare, mode, ", ");
}
private XhtmlNode compareSimpleTypeLists(List<? extends PrimitiveType> originalList, List<? extends PrimitiveType> compareList, int mode, String separator) {
private XhtmlNode compareSimpleTypeLists(List<? extends PrimitiveType> originalList, List<? extends PrimitiveType> compareList, int mode, String separator) throws IOException {
StatusList<ValueWithStatus> list = new StatusList<>();
for (PrimitiveType v : originalList) {
if (!v.isEmpty()) {
@ -4378,6 +4438,37 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
}
private XhtmlNode compareDataTypeLists(List<? extends DataType> original, List<? extends DataType> compare, int mode) throws IOException {
return compareDataTypeLists(original, compare, mode, ", ");
}
private XhtmlNode compareDataTypeLists(List<? extends DataType> originalList, List<? extends DataType> compareList, int mode, String separator) throws IOException {
StatusList<DataValueWithStatus> list = new StatusList<>();
for (DataType v : originalList) {
if (!v.isEmpty()) {
list.add(new DataValueWithStatus(v));
}
}
if (compareList != null && mode != GEN_MODE_DIFF) {
for (DataType v : compareList) {
list.merge(new DataValueWithStatus(v));
}
}
if (list.size() == 0) {
return null;
}
XhtmlNode x = new XhtmlNode(NodeType.Element, "div");
boolean first = true;
for (DataValueWithStatus t : list) {
if (first) first = false; else x.tx(separator);
t.render(x);
}
return x;
}
private String summarise(CodeableConcept cc) throws FHIRException {
if (cc.getCoding().size() == 1 && cc.getText() == null) {
return summarise(cc.getCoding().get(0));

View File

@ -1146,7 +1146,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
boolean hasExtensions = false;
XhtmlNode li;
li = ul.li();
li = VersionComparisonAnnotation.render(inc, li);
li = renderStatus(inc, li);
Map<String, ConceptDefinitionComponent> definitions = new HashMap<>();
@ -1199,7 +1199,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
li.tx(", ");
}
}
XhtmlNode wli = VersionComparisonAnnotation.render(f, li);
XhtmlNode wli = renderStatus(f, li);
if (f.getOp() == FilterOperator.EXISTS) {
if (f.getValue().equals("true")) {
wli.tx(f.getProperty()+" exists");
@ -1239,7 +1239,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
first = false;
else
li.tx(", ");
XhtmlNode wli = VersionComparisonAnnotation.render(vs, li);
XhtmlNode wli = renderStatus(vs, li);
AddVsRef(vs.asStringValue(), wli, vsRes);
}
}
@ -1256,13 +1256,13 @@ public class ValueSetRenderer extends TerminologyRenderer {
first = false;
else
li.tx(", ");
XhtmlNode wli = VersionComparisonAnnotation.render(vs, li);
XhtmlNode wli = renderStatus(vs, li);
AddVsRef(vs.asStringValue(), wli, vsRes);
}
} else {
XhtmlNode xul = li.ul();
for (UriType vs : inc.getValueSet()) {
XhtmlNode wli = VersionComparisonAnnotation.render(vs, xul.li());
XhtmlNode wli = renderStatus(vs, xul.li());
AddVsRef(vs.asStringValue(), wli, vsRes);
}
@ -1275,16 +1275,16 @@ public class ValueSetRenderer extends TerminologyRenderer {
List<UsedConceptMap> maps, Map<String, String> designations, Map<String, ConceptDefinitionComponent> definitions,
XhtmlNode t, boolean hasComments, boolean hasDefinition, ConceptReferenceComponent c) {
XhtmlNode tr = t.tr();
XhtmlNode td = VersionComparisonAnnotation.renderRow(c, t, tr);
XhtmlNode td = renderStatusRow(c, t, tr);
ConceptDefinitionComponent cc = definitions == null ? null : definitions.get(c.getCode());
addCodeToTable(false, inc.getSystem(), c.getCode(), c.hasDisplay()? c.getDisplay() : cc != null ? cc.getDisplay() : "", td);
td = tr.td();
if (!Utilities.noString(c.getDisplay()))
VersionComparisonAnnotation.render(c.getDisplayElement(), td).addText(c.getDisplay());
renderStatus(c.getDisplayElement(), td).addText(c.getDisplay());
else if (VersionComparisonAnnotation.hasDeleted(c, "display")) {
StringType d = (StringType) VersionComparisonAnnotation.getDeletedItem(c, "display");
VersionComparisonAnnotation.render(d, td).addText(d.primitiveValue());
renderStatus(d, td).addText(d.primitiveValue());
} else if (cc != null && !Utilities.noString(cc.getDisplay()))
td.style("color: #cccccc").addText(cc.getDisplay());

View File

@ -187,6 +187,7 @@ public class RenderingContext {
private DateTimeFormatter dateYearMonthFormat;
private boolean copyButton;
private ProfileKnowledgeProvider pkp;
private String changeVersion;
private Map<KnownLinkType, String> links = new HashMap<>();
/**
@ -709,4 +710,14 @@ public class RenderingContext {
return this;
}
public String getChangeVersion() {
return changeVersion;
}
public RenderingContext setChangeVersion(String changeVersion) {
this.changeVersion = changeVersion;
return this;
}
}

View File

@ -315,9 +315,12 @@ public class CompareUtilities extends BaseTestingUtilities {
}
private String compareNodes(String path, JsonElement expectedJsonElement, JsonElement actualJsonElement) {
if (actualJsonElement.getClass() != expectedJsonElement.getClass())
return createNotEqualMessage("properties differ at " + path, expectedJsonElement.getClass().getName(), actualJsonElement.getClass().getName());
else if (actualJsonElement instanceof JsonPrimitive) {
if (!(expectedJsonElement instanceof JsonPrimitive && actualJsonElement instanceof JsonPrimitive)) {
if (actualJsonElement.getClass() != expectedJsonElement.getClass()) {
return createNotEqualMessage("properties differ at " + path, expectedJsonElement.getClass().getName(), actualJsonElement.getClass().getName());
}
}
if (actualJsonElement instanceof JsonPrimitive) {
JsonPrimitive actualJsonPrimitive = (JsonPrimitive) actualJsonElement;
JsonPrimitive expectedJsonPrimitive = (JsonPrimitive) expectedJsonElement;
if (actualJsonPrimitive.isJsonBoolean() && expectedJsonPrimitive.isJsonBoolean()) {
@ -333,8 +336,11 @@ public class CompareUtilities extends BaseTestingUtilities {
} else if (actualJsonPrimitive.isJsonNumber() && expectedJsonPrimitive.isJsonNumber()) {
if (!actualJsonPrimitive.asString().equals(expectedJsonPrimitive.asString()))
return createNotEqualMessage("number property values differ at " + path, expectedJsonPrimitive.asString(), actualJsonPrimitive.asString());
} else
} else if (expectedJsonElement instanceof JsonNull) {
return actualJsonPrimitive instanceof JsonNull ? null : createNotEqualMessage("null Properties differ at " + path, "null", actualJsonPrimitive.asString());
} else {
return createNotEqualMessage("property types differ at " + path, expectedJsonPrimitive.asString(), actualJsonPrimitive.asString());
}
} else if (actualJsonElement instanceof JsonObject) {
String s = compareObjects(path, (JsonObject) expectedJsonElement, (JsonObject) actualJsonElement);
if (!Utilities.noString(s))
@ -363,8 +369,7 @@ public class CompareUtilities extends BaseTestingUtilities {
c++;
}
}
} else if (actualJsonElement instanceof JsonNull) {
} else
return "unhandled property " + actualJsonElement.getClass().getName();
return null;

View File

@ -151,11 +151,18 @@ public class DefinitionNavigator {
if (nameMap.containsKey(path)) {
DefinitionNavigator master = nameMap.get(path);
ElementDefinition cm = master.current();
// if (!cm.hasSlicing())
// throw new DefinitionException("Found slices with no slicing details at "+dn.current().getPath());
if (master.slices == null)
master.slices = new ArrayList<DefinitionNavigator>();
master.slices.add(dn);
if (diff && cm.hasSliceName()) {
// slice name - jumped straight into slicing
children.add(dn);
} else {
if (!cm.hasSlicing()) {
throw new DefinitionException("Found slices with no slicing details at "+dn.current().getPath());
}
if (master.slices == null) {
master.slices = new ArrayList<DefinitionNavigator>();
}
master.slices.add(dn);
}
} else {
nameMap.put(path, dn);
children.add(dn);
@ -238,7 +245,11 @@ public class DefinitionNavigator {
@Override
public String toString() {
return current().getId();
return getId();
}
public String getId() {
return current() == null ? path : current().hasSliceName() ? current().getPath()+":"+current().getSliceName() : current().getPath();
}
public Base parent() {

View File

@ -1,6 +1,7 @@
package org.hl7.fhir.r5.utils;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.model.MarkdownType;
import org.hl7.fhir.r5.model.StringType;
import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.VersionUtilities;
@ -11,17 +12,21 @@ public class PublicationHacker {
// this routine fixes up broken binding descriptions from past FHIR publications. All of them will be or are fixed in a later version,
// but fixing old versions is procedurally very difficult. Hence, these work around fixes here
public static StringType fixBindingDescriptions(IWorkerContext context, StringType s) {
StringType res = s.copy();
// ServiceRequest.code
if (res.getValue().contains("LOINC is (preferred)[http://build.fhir.org/terminologies.html#preferred]")) {
res.setValue(res.getValue().replace("LOINC is (preferred)[http://build.fhir.org/terminologies.html#preferred]", "LOINC is [preferred]("+Utilities.pathURL(VersionUtilities.getSpecUrl(context.getVersion()), "terminologies.html#preferred)")));
public static MarkdownType fixBindingDescriptions(IWorkerContext context, MarkdownType md) {
MarkdownType ret = null;
// ServiceRequest.code
if (md.getValue().contains("LOINC is (preferred)[http://build.fhir.org/terminologies.html#preferred]")) {
ret = md.copy();
ret.setValue(md.getValue().replace("LOINC is (preferred)[http://build.fhir.org/terminologies.html#preferred]", "LOINC is [preferred]("+Utilities.pathURL(VersionUtilities.getSpecUrl(context.getVersion()), "terminologies.html#preferred)")));
}
if (md.getValue().contains("[here](valueset-diagnostic-requests.html)")) {
if (ret == null) {
ret = md.copy();
}
if (res.getValue().contains("[here](valueset-diagnostic-requests.html)")) {
res.setValue(res.getValue().replace("[here](valueset-diagnostic-requests.html)", "here"));
}
return res;
ret.setValue(md.getValue().replace("[here](valueset-diagnostic-requests.html)", "here"));
}
return ret == null ? md : ret;
}
}

View File

@ -1,3 +1,3 @@
string property values differ at .expectedArray[0]
Expected :expectedValue 1
Actual :unexpectedValue 1
Expected :"expectedValue 1"
Actual :"unexpectedValue 1"

View File

@ -1,3 +1,3 @@
array item count differs at .expectedArray
Expected :2
Actual :1
Expected :"2"
Actual :"1"

View File

@ -1,3 +1,3 @@
boolean property values differ at .expectedBoolean
Expected :true
Actual :false
Expected :"true"
Actual :"false"

View File

@ -1,3 +1,3 @@
number property values differ at .expectedNumber
Expected :123
Actual :789
Expected :"123"
Actual :"789"

View File

@ -1,3 +1,3 @@
property types differ at .expectedString
Expected :expected value
Actual :1
Expected :"expected value"
Actual :"1"

View File

@ -1,3 +1,3 @@
string property values differ at .expectedString
Expected :expected value
Actual :unexpected value
Expected :"expected value"
Actual :"unexpected value"

View File

@ -1,3 +1,3 @@
Attributes differ at /root/blah
Expected :dummyAtt
Actual :wrongwrongwrong
Expected :"dummyAtt"
Actual :"wrongwrongwrong"

View File

@ -1,3 +1,3 @@
Names differ at /root
Expected :nameSpacedNode
Actual :wrongNameSpacedNode
Expected :"nameSpacedNode"
Actual :"wrongNameSpacedNode"

View File

@ -1,3 +1,3 @@
Namespaces differ at /root
Expected :http://www.example.com/FOO
Actual :http://www.example.com/BAR
Expected :"http://www.example.com/FOO"
Actual :"http://www.example.com/BAR"

View File

@ -1,3 +1,3 @@
node type mismatch in children of /root/blah
Expected :1
Actual :1
Expected :"1"
Actual :"1"

View File

@ -1,3 +1,3 @@
Text differs at /root/blah
Expected :expected
Actual :different
Expected :"expected"
Actual :"different"

View File

@ -154,12 +154,14 @@ public class ComparisonTests {
ComparisonSession session = new ComparisonSession(context, context, "Comparison Tests", null, null);
if (content.has("version")) {
session.setForVersion(content.getJsonObject("version").asString("stated"));
session.setAnnotate(true);
}
RenderingContext lrc = new RenderingContext(context, new MarkDownProcessor(Dialect.COMMON_MARK), null, "http://hl7.org/fhir", "", "en", ResourceRendererMode.TECHNICAL, GenerationRules.IG_PUBLISHER);
lrc.setDestDir(Utilities.path("[tmp]", "comparison"));
lrc.setPkp(new TestProfileKnowledgeProvider(context));
if (content.has("version")) {
lrc.setChangeVersion(content.getJsonObject("version").asString("stated"));
}
if (left instanceof CodeSystem && right instanceof CodeSystem) {
CodeSystemComparer cs = new CodeSystemComparer(session);
@ -205,14 +207,14 @@ public class ComparisonTests {
TextFile.stringToFile(HEADER + hd("Messages") + xmle + BREAK + hd("Metadata") + xml1 + BREAK + hd("Structure") + xml2 + FOOTER, Utilities.path("[tmp]", "comparison", name + ".html"));
checkOutcomes(csc.getMessages(), content);
lrc.setStructureMode(StructureDefinitionRendererMode.SUMMARY);
new StructureDefinitionRenderer(lrc).render(right);
checkOutput(content.getJsonObject("version").asString("filename-tree"), right);
lrc.setStructureMode(StructureDefinitionRendererMode.DATA_DICT);
new StructureDefinitionRenderer(lrc).render(right);
checkOutput(content.getJsonObject("version").asString("filename-dd"), right);
lrc.setStructureMode(StructureDefinitionRendererMode.SUMMARY);
new StructureDefinitionRenderer(lrc).render(right);
checkOutput(content.getJsonObject("version").asString("filename-tree"), right);
} else if (left instanceof CapabilityStatement && right instanceof CapabilityStatement) {
CapabilityStatementComparer pc = new CapabilityStatementComparer(session);
CapabilityStatementComparison csc = pc.compare((CapabilityStatement) left, (CapabilityStatement) right);