use of org.hl7.fhir.r4b.utils.DefinitionNavigator in project org.hl7.fhir.core by hapifhir.
the class ProfileComparer method compareElements.
/**
* left and right refer to the same element. Are they compatible?
* @param outcome
* @param outcome
* @param path
* @param left
* @param right
* @- if there's a problem that needs fixing in this code
* @throws DefinitionException
* @throws IOException
*/
private boolean compareElements(ProfileComparison outcome, String path, DefinitionNavigator left, DefinitionNavigator right) throws DefinitionException, IOException {
// preconditions:
assert (path != null);
assert (left != null);
assert (right != null);
assert (left.path().equals(right.path()));
// we ignore slicing right now - we're going to clone the root one anyway, and then think about clones
// simple stuff
ElementDefinition subset = new ElementDefinition();
subset.setPath(left.path());
// not allowed to be different:
// can't be bothered even testing this one
subset.getRepresentation().addAll(left.current().getRepresentation());
if (!outcome.ruleCompares(subset, left.current().getDefaultValue(), right.current().getDefaultValue(), path + ".defaultValue[x]", BOTH_NULL))
return false;
subset.setDefaultValue(left.current().getDefaultValue());
if (!outcome.ruleEqual(path, subset, left.current().getMeaningWhenMissing(), right.current().getMeaningWhenMissing(), "meaningWhenMissing Must be the same", true))
return false;
subset.setMeaningWhenMissing(left.current().getMeaningWhenMissing());
if (!outcome.ruleEqual(subset, left.current().getIsModifier(), right.current().getIsModifier(), path, "isModifier"))
return false;
subset.setIsModifier(left.current().getIsModifier());
if (!outcome.ruleEqual(subset, left.current().getIsSummary(), right.current().getIsSummary(), path, "isSummary"))
return false;
subset.setIsSummary(left.current().getIsSummary());
// descriptive properties from ElementDefinition - merge them:
subset.setLabel(mergeText(subset, outcome, path, "label", left.current().getLabel(), right.current().getLabel()));
subset.setShort(mergeText(subset, outcome, path, "short", left.current().getShort(), right.current().getShort()));
subset.setDefinition(mergeText(subset, outcome, path, "definition", left.current().getDefinition(), right.current().getDefinition()));
subset.setComments(mergeText(subset, outcome, path, "comments", left.current().getComments(), right.current().getComments()));
subset.setRequirements(mergeText(subset, outcome, path, "requirements", left.current().getRequirements(), right.current().getRequirements()));
subset.getCode().addAll(mergeCodings(left.current().getCode(), right.current().getCode()));
subset.getAlias().addAll(mergeStrings(left.current().getAlias(), right.current().getAlias()));
subset.getMapping().addAll(mergeMappings(left.current().getMapping(), right.current().getMapping()));
// left will win for example
subset.setExample(left.current().hasExample() ? left.current().getExample() : right.current().getExample());
subset.setMustSupport(left.current().getMustSupport() || right.current().getMustSupport());
ElementDefinition superset = subset.copy();
// compare and intersect
superset.setMin(unionMin(left.current().getMin(), right.current().getMin()));
superset.setMax(unionMax(left.current().getMax(), right.current().getMax()));
subset.setMin(intersectMin(left.current().getMin(), right.current().getMin()));
subset.setMax(intersectMax(left.current().getMax(), right.current().getMax()));
outcome.rule(subset, subset.getMax().equals("*") || Integer.parseInt(subset.getMax()) >= subset.getMin(), path, "Cardinality Mismatch: " + card(left) + "/" + card(right));
superset.getType().addAll(unionTypes(path, left.current().getType(), right.current().getType()));
subset.getType().addAll(intersectTypes(subset, outcome, path, left.current().getType(), right.current().getType()));
outcome.rule(subset, !subset.getType().isEmpty() || (!left.current().hasType() && !right.current().hasType()), path, "Type Mismatch:\r\n " + typeCode(left) + "\r\n " + typeCode(right));
// <fixed[x]><!-- ?? 0..1 * Value must be exactly this --></fixed[x]>
// <pattern[x]><!-- ?? 0..1 * Value must have at least these property values --></pattern[x]>
superset.setMaxLengthElement(unionMaxLength(left.current().getMaxLength(), right.current().getMaxLength()));
subset.setMaxLengthElement(intersectMaxLength(left.current().getMaxLength(), right.current().getMaxLength()));
if (left.current().hasBinding() || right.current().hasBinding()) {
compareBindings(outcome, subset, superset, path, left.current(), right.current());
}
// note these are backwards
superset.getConstraint().addAll(intersectConstraints(path, left.current().getConstraint(), right.current().getConstraint()));
subset.getConstraint().addAll(unionConstraints(subset, outcome, path, left.current().getConstraint(), right.current().getConstraint()));
// now process the slices
if (left.current().hasSlicing() || right.current().hasSlicing()) {
if (isExtension(left.path()))
return compareExtensions(outcome, path, superset, subset, left, right);
else
throw new DefinitionException("Slicing is not handled yet");
// todo: name
}
// add the children
outcome.subset.getSnapshot().getElement().add(subset);
outcome.superset.getSnapshot().getElement().add(superset);
return compareChildren(subset, outcome, path, left, right);
}
use of org.hl7.fhir.r4b.utils.DefinitionNavigator in project org.hl7.fhir.core by hapifhir.
the class ProfileComparer method compare.
public ProfileComparison compare(StructureDefinition left, StructureDefinition right) throws DefinitionException, FHIRFormatError, IOException {
check(left, "left");
check(right, "right");
ProfileComparison res = new ProfileComparison(left, right);
session.identify(res);
StructureDefinition sd = new StructureDefinition();
res.setUnion(sd);
session.identify(sd);
sd.setName("Union" + left.getName() + "And" + right.getName());
sd.setTitle("Union of " + left.getTitle() + " And " + right.getTitle());
sd.setStatus(left.getStatus());
sd.setDate(new Date());
StructureDefinition sd1 = new StructureDefinition();
res.setIntersection(sd1);
session.identify(sd1);
sd1.setName("Intersection" + left.getName() + "And" + right.getName());
sd1.setTitle("Intersection of " + left.getTitle() + " And " + right.getTitle());
sd1.setStatus(left.getStatus());
sd1.setDate(new Date());
compareMetadata(left, right, res.getMetadata(), res);
comparePrimitives("fhirVersion", left.getFhirVersionElement(), right.getFhirVersionElement(), res.getMetadata(), IssueSeverity.WARNING, res);
comparePrimitives("kind", left.getKindElement(), right.getKindElement(), res.getMetadata(), IssueSeverity.WARNING, res);
comparePrimitives("abstract", left.getAbstractElement(), right.getAbstractElement(), res.getMetadata(), IssueSeverity.WARNING, res);
comparePrimitives("type", left.getTypeElement(), right.getTypeElement(), res.getMetadata(), IssueSeverity.ERROR, res);
comparePrimitives("baseDefinition", left.getBaseDefinitionElement(), right.getBaseDefinitionElement(), res.getMetadata(), IssueSeverity.ERROR, res);
if (left.getType().equals(right.getType())) {
DefinitionNavigator ln = new DefinitionNavigator(session.getContextLeft(), left);
DefinitionNavigator rn = new DefinitionNavigator(session.getContextRight(), right);
StructuralMatch<ElementDefinitionNode> sm = new StructuralMatch<ElementDefinitionNode>(new ElementDefinitionNode(left, ln.current()), new ElementDefinitionNode(right, rn.current()));
compareElements(res, sm, ln.path(), null, ln, rn);
res.combined = sm;
}
return res;
}
use of org.hl7.fhir.r4b.utils.DefinitionNavigator in project org.hl7.fhir.core by hapifhir.
the class ProfileComparer method compareElements.
private void compareElements(ProfileComparison comp, StructuralMatch<ElementDefinitionNode> res, String path, String sliceName, DefinitionNavigator left, DefinitionNavigator right) throws DefinitionException, FHIRFormatError, IOException {
assert (path != null);
assert (left != null);
assert (right != null);
assert (left.path().equals(right.path()));
if (session.isDebug()) {
System.out.println("Compare elements at " + path);
}
// not allowed to be different:
// ruleEqual(comp, res, left.current().getDefaultValue(), right.current().getDefaultValue(), "defaultValue", path);
// ruleEqual(comp, res, left.current().getMeaningWhenMissingElement(), right.current().getMeaningWhenMissingElement(), "meaningWhenMissing", path);
// ruleEqual(comp, res, left.current().getIsModifierElement(), right.current().getIsModifierElement(), "isModifier", path); - this check belongs in the core
// ruleEqual(comp, res, left.current().getIsSummaryElement(), right.current().getIsSummaryElement(), "isSummary", path); - so does this
// we ignore slicing right now - we're going to clone the root one anyway, and then think about clones
// simple stuff
ElementDefinition subset = new ElementDefinition();
subset.setPath(left.path());
if (sliceName != null)
subset.setSliceName(sliceName);
// can't be bothered even testing this one
subset.getRepresentation().addAll(left.current().getRepresentation());
subset.setDefaultValue(left.current().getDefaultValue());
subset.setMeaningWhenMissing(left.current().getMeaningWhenMissing());
subset.setIsModifier(left.current().getIsModifier());
subset.setIsSummary(left.current().getIsSummary());
// descriptive properties from ElementDefinition - merge them:
subset.setLabel(mergeText(comp, res, path, "label", left.current().getLabel(), right.current().getLabel(), false));
subset.setShort(mergeText(comp, res, path, "short", left.current().getShort(), right.current().getShort(), false));
subset.setDefinition(mergeText(comp, res, path, "definition", left.current().getDefinition(), right.current().getDefinition(), false));
subset.setComment(mergeText(comp, res, path, "comments", left.current().getComment(), right.current().getComment(), false));
subset.setRequirements(mergeText(comp, res, path, "requirements", left.current().getRequirements(), right.current().getRequirements(), false));
subset.getCode().addAll(mergeCodings(left.current().getCode(), right.current().getCode()));
subset.getAlias().addAll(mergeStrings(left.current().getAlias(), right.current().getAlias()));
subset.getMapping().addAll(mergeMappings(left.current().getMapping(), right.current().getMapping()));
// left will win for example
subset.setExample(left.current().hasExample() ? left.current().getExample() : right.current().getExample());
if (left.current().getMustSupport() != right.current().getMustSupport()) {
vm(IssueSeverity.WARNING, "Elements differ in definition for mustSupport: '" + left.current().getMustSupport() + "' vs '" + right.current().getMustSupport() + "'", path, comp.getMessages(), res.getMessages());
}
subset.setMustSupport(left.current().getMustSupport() || right.current().getMustSupport());
ElementDefinition superset = subset.copy();
// compare and intersect
int leftMin = left.current().getMin();
int rightMin = right.current().getMin();
int leftMax = "*".equals(left.current().getMax()) ? Integer.MAX_VALUE : Integer.parseInt(left.current().getMax());
int rightMax = "*".equals(right.current().getMax()) ? Integer.MAX_VALUE : Integer.parseInt(right.current().getMax());
checkMinMax(comp, res, path, leftMin, rightMin, leftMax, rightMax);
superset.setMin(unionMin(leftMin, rightMin));
superset.setMax(unionMax(leftMax, rightMax, left.current().getMax(), right.current().getMax()));
subset.setMin(intersectMin(leftMin, rightMin));
subset.setMax(intersectMax(leftMax, rightMax, left.current().getMax(), right.current().getMax()));
superset.getType().addAll(unionTypes(comp, res, path, left.current().getType(), right.current().getType()));
subset.getType().addAll(intersectTypes(comp, res, subset, path, left.current().getType(), right.current().getType()));
rule(comp, res, !subset.getType().isEmpty() || (!left.current().hasType() && !right.current().hasType()), path, "Type Mismatch: " + typeCode(left) + " vs " + typeCode(right));
// <fixed[x]><!-- ?? 0..1 * Value must be exactly this --></fixed[x]>
// <pattern[x]><!-- ?? 0..1 * Value must have at least these property values --></pattern[x]>
superset.setMaxLengthElement(unionMaxLength(left.current().getMaxLength(), right.current().getMaxLength()));
subset.setMaxLengthElement(intersectMaxLength(left.current().getMaxLength(), right.current().getMaxLength()));
if (left.current().hasBinding() || right.current().hasBinding()) {
compareBindings(comp, res, subset, superset, path, left.current(), right.current());
}
// note these are backwards
superset.getConstraint().addAll(intersectConstraints(path, left.current().getConstraint(), right.current().getConstraint()));
subset.getConstraint().addAll(unionConstraints(comp, res, path, left.current().getConstraint(), right.current().getConstraint()));
comp.getIntersection().getSnapshot().getElement().add(subset);
comp.getUnion().getSnapshot().getElement().add(superset);
// add the children
compareChildren(comp, res, path, left, right);
//
// // now process the slices
// if (left.current().hasSlicing() || right.current().hasSlicing()) {
// assert sliceName == null;
// if (isExtension(left.path()))
// return compareExtensions(outcome, path, superset, subset, left, right);
// // return true;
// else {
// ElementDefinitionSlicingComponent slicingL = left.current().getSlicing();
// ElementDefinitionSlicingComponent slicingR = right.current().getSlicing();
// // well, this is tricky. If one is sliced, and the other is not, then in general, the union just ignores the slices, and the intersection is the slices.
// if (left.current().hasSlicing() && !right.current().hasSlicing()) {
// // the super set is done. Any restrictions in the slices are irrelevant to what the super set says, except that we're going sum up the value sets if we can (for documentation purposes) (todo)
// // the minimum set is the slicing specified in the slicer
// subset.setSlicing(slicingL);
// // stick everything from the right to do with the slices to the subset
// copySlices(outcome.subset.getSnapshot().getElement(), left.getStructure().getSnapshot().getElement(), left.slices());
// } else if (!left.current().hasSlicing() && right.current().hasSlicing()) {
// // the super set is done. Any restrictions in the slices are irrelevant to what the super set says, except that we're going sum up the value sets if we can (for documentation purposes) (todo)
// // the minimum set is the slicing specified in the slicer
// subset.setSlicing(slicingR);
// // stick everything from the right to do with the slices to the subset
// copySlices(outcome.subset.getSnapshot().getElement(), right.getStructure().getSnapshot().getElement(), right.slices());
// } else if (isTypeSlicing(slicingL) || isTypeSlicing(slicingR)) {
// superset.getSlicing().setRules(SlicingRules.OPEN).setOrdered(false).addDiscriminator().setType(DiscriminatorType.TYPE).setPath("$this");
// subset.getSlicing().setRules(slicingL.getRules() == SlicingRules.CLOSED || slicingR.getRules() == SlicingRules.CLOSED ? SlicingRules.OPEN : SlicingRules.CLOSED).setOrdered(false).addDiscriminator().setType(DiscriminatorType.TYPE).setPath("$this");
//
// // the superset is the union of the types
// // the subset is the intersection of them
// List<DefinitionNavigator> handled = new ArrayList<>();
// for (DefinitionNavigator t : left.slices()) {
// DefinitionNavigator r = findMatchingSlice(right.slices(), t);
// if (r == null) {
// copySlice(outcome.superset.getSnapshot().getElement(), left.getStructure().getSnapshot().getElement(), t);
// } else {
// handled.add(r);
// ret = compareElements(outcome, path+":"+t.current().getSliceName(), t, r, t.current().getSliceName()) && ret;
// }
// }
// for (DefinitionNavigator t : right.slices()) {
// if (!handled.contains(t)) {
// copySlice(outcome.superset.getSnapshot().getElement(), right.getStructure().getSnapshot().getElement(), t);
// }
// }
// } else if (slicingMatches(slicingL, slicingR)) {
// // if it's the same, we can try matching the slices - though we might have to give up without getting matches correct
// // there amy be implied consistency we can't reason about
// throw new DefinitionException("Slicing matches but is not handled yet at "+left.current().getId()+": ("+ProfileUtilities.summarizeSlicing(slicingL)+")");
// } else {
// // if the slicing is different, we can't compare them - or can we?
// throw new DefinitionException("Slicing doesn't match at "+left.current().getId()+": ("+ProfileUtilities.summarizeSlicing(slicingL)+" / "+ProfileUtilities.summarizeSlicing(slicingR)+")");
// }
// }
// // todo: name
// }
// return ret;
//
// // TODO Auto-generated method stub
// return null;
}
use of org.hl7.fhir.r4b.utils.DefinitionNavigator in project org.hl7.fhir.core by hapifhir.
the class DefinitionNavigator method loadChildren.
private void loadChildren() throws DefinitionException {
children = new ArrayList<DefinitionNavigator>();
String prefix = current().getPath() + ".";
Map<String, DefinitionNavigator> nameMap = new HashMap<String, DefinitionNavigator>();
for (int i = index + 1; i < structure.getSnapshot().getElement().size(); i++) {
String path = structure.getSnapshot().getElement().get(i).getPath();
if (path.startsWith(prefix) && !path.substring(prefix.length()).contains(".")) {
DefinitionNavigator dn = new DefinitionNavigator(context, structure, i, this.path + "." + tail(path), names, null);
if (nameMap.containsKey(path)) {
DefinitionNavigator master = nameMap.get(path);
if (!master.current().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);
}
} else if (path.length() < prefix.length())
break;
}
}
use of org.hl7.fhir.r4b.utils.DefinitionNavigator in project org.hl7.fhir.core by hapifhir.
the class DefinitionNavigator method loadTypedChildren.
private void loadTypedChildren(TypeRefComponent type) throws DefinitionException {
typeOfChildren = null;
StructureDefinition sd = context.fetchResource(StructureDefinition.class, type.hasProfile() ? type.getProfile() : type.getCode());
if (sd != null) {
DefinitionNavigator dn = new DefinitionNavigator(context, sd, 0, path, names, sd.getType());
typeChildren = dn.children();
} else
throw new DefinitionException("Unable to find definition for " + type.getCode() + (type.hasProfile() ? "(" + type.getProfile() + ")" : ""));
typeOfChildren = type;
}
Aggregations