use of org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionDifferentialComponent in project org.hl7.fhir.core by hapifhir.
the class ProfileUtilities method cloneDiff.
private StructureDefinitionDifferentialComponent cloneDiff(StructureDefinitionDifferentialComponent source) {
StructureDefinitionDifferentialComponent diff = new StructureDefinitionDifferentialComponent();
for (ElementDefinition sed : source.getElement()) {
ElementDefinition ted = sed.copy();
diff.getElement().add(ted);
ted.setUserData("diff-source", sed);
}
return diff;
}
use of org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionDifferentialComponent in project kindling by HL7.
the class ProfileGenerator method generate.
public StructureDefinition generate(Profile pack, ConstraintStructure profile, ResourceDefn resource, String id, String html, ImplementationGuideDefn usage, List<ValidationMessage> issues, ResourceDefn baseResource) throws Exception {
if (profile.getResource() != null)
return profile.getResource();
StructureDefinition p = new StructureDefinition();
p.setId(FormatUtilities.makeId(id));
p.setUrl("http://hl7.org/fhir/StructureDefinition/" + id);
if (usage != null && !usage.isCore()) {
if (!id.startsWith(usage.getCode() + "-"))
throw new Exception("Error: " + id + " must start with " + usage.getCode() + "-");
}
if (!resource.getRoot().getTypes().isEmpty() && (resource.getRoot().getTypes().get(0).getProfile() != null))
p.setBaseDefinition(resource.getRoot().getTypes().get(0).getProfile());
else
p.setBaseDefinition("http://hl7.org/fhir/StructureDefinition/" + resource.getName());
if (definitions.hasType(resource.getName()))
p.setKind(StructureDefinitionKind.COMPLEXTYPE);
else
p.setKind(StructureDefinitionKind.RESOURCE);
p.setType(resource.getName());
p.setDerivation(TypeDerivationRule.CONSTRAINT);
p.setAbstract(false);
p.setUserData("filename", id);
p.setUserData("path", ((usage == null || usage.isCore()) ? "" : usage.getCode() + File.separator) + id + ".html");
p.setTitle(pack.metadata("display"));
p.setFhirVersion(version);
p.setVersion(version.toCode());
if (pack.hasMetadata("summary-" + profile.getTitle()))
ToolingExtensions.addMarkdownExtension(p, "http://hl7.org/fhir/StructureDefinition/structuredefinition-summary", pack.metadata("summary-" + profile.getTitle()));
ToolResourceUtilities.updateUsage(p, usage.getCode());
p.setName(pack.metadata("name"));
p.setPublisher(pack.metadata("author.name"));
if (pack.hasMetadata("author.reference"))
p.addContact().getTelecom().add(Factory.newContactPoint(ContactPointSystem.URL, pack.metadata("author.reference")));
// <code> opt Zero+ Coding assist with indexing and finding</code>
p.setDescription(resource.getRoot().getShortDefn());
if (!p.hasDescriptionElement() && pack.hasMetadata("description"))
p.setDescription(preProcessMarkdown(pack.metadata("description"), "pack.description"));
p.setPurpose(resource.getRoot().getRequirements());
if (!p.hasPurpose() && pack.hasMetadata("requirements"))
p.setPurpose(pack.metadata("requirements"));
p.setExperimental(Utilities.existsInList(pack.metadata("Experimental"), "y", "Y", "true", "TRUE", "1"));
if (pack.hasMetadata("date"))
p.setDateElement(Factory.newDateTime(pack.metadata("date").substring(0, 10)));
else
p.setDate(genDate.getTime());
if (pack.hasMetadata("fmm-level"))
ToolingExtensions.addIntegerExtension(p, ToolingExtensions.EXT_FMM_LEVEL, Integer.parseInt(pack.getFmmLevel()));
else if (pack.hasMetadata("fmm"))
ToolingExtensions.addIntegerExtension(p, ToolingExtensions.EXT_FMM_LEVEL, Integer.parseInt(pack.metadata("fmm")));
else if (!Utilities.noString(resource.getFmmLevel()))
ToolingExtensions.addIntegerExtension(p, ToolingExtensions.EXT_FMM_LEVEL, Integer.parseInt(resource.getFmmLevel()));
else if (baseResource != null && !Utilities.noString(baseResource.getFmmLevel()))
ToolingExtensions.addIntegerExtension(p, ToolingExtensions.EXT_FMM_LEVEL, Integer.parseInt(baseResource.getFmmLevel()));
if (pack.hasMetadata("workgroup"))
ToolingExtensions.setCodeExtension(p, ToolingExtensions.EXT_WORKGROUP, pack.getWg());
else if (resource.getWg() != null)
ToolingExtensions.setCodeExtension(p, ToolingExtensions.EXT_WORKGROUP, resource.getWg().getCode());
else if (baseResource != null && baseResource.getWg() != null)
ToolingExtensions.setCodeExtension(p, ToolingExtensions.EXT_WORKGROUP, baseResource.getWg().getCode());
if (pack.hasMetadata("Standards-Status"))
ToolingExtensions.setStandardsStatus(p, StandardsStatus.fromCode(pack.metadata("Standards-Status")), null);
else
ToolingExtensions.setStandardsStatus(p, resource.getStatus(), null);
if (pack.hasMetadata("status"))
p.setStatus(PublicationStatus.fromCode(pack.metadata("status")));
if (pack.getMetadata().containsKey("code"))
for (String s : pack.getMetadata().get("code")) if (!Utilities.noString(s))
p.getKeyword().add(Factory.makeCoding(s));
if (pack.hasMetadata("datadictionary"))
ToolingExtensions.setStringExtension(p, "http://hl7.org/fhir/StructureDefinition/datadictionary", pack.metadata("datadictionary"));
Set<String> containedSlices = new HashSet<String>();
p.setDifferential(new StructureDefinitionDifferentialComponent());
defineElement(pack, p, p.getDifferential().getElement(), resource.getRoot(), resource.getName(), containedSlices, new ArrayList<ProfileGenerator.SliceHandle>(), SnapShotMode.None, true, null, null, false);
List<String> names = new ArrayList<String>();
names.addAll(resource.getSearchParams().keySet());
Collections.sort(names);
for (String pn : names) {
pack.getSearchParameters().add(makeSearchParam(p, pack.getId() + "-" + resource.getName() + "-" + pn, resource.getName(), resource.getSearchParams().get(pn), resource));
}
StructureDefinition base = definitions.getSnapShotForBase(p.getBaseDefinition());
List<String> errors = new ArrayList<String>();
new ProfileUtilities(context, null, pkp).sortDifferential(base, p, p.getName(), errors, false);
for (String s : errors) issues.add(new ValidationMessage(Source.ProfileValidator, IssueType.STRUCTURE, -1, -1, p.getUrl(), s, IssueSeverity.WARNING));
reset();
// ok, c is the differential. now we make the snapshot
new ProfileUtilities(context, issues, pkp).generateSnapshot(base, p, "http://hl7.org/fhir/StructureDefinition/" + p.getType(), "http://hl7.org/fhir", p.getName());
reset();
p.getDifferential().getElement().get(0).getType().clear();
p.getSnapshot().getElement().get(0).getType().clear();
addElementConstraintToSnapshot(p);
XhtmlNode div = new XhtmlNode(NodeType.Element, "div");
div.addText("to do");
p.setText(new Narrative());
p.getText().setStatus(NarrativeStatus.GENERATED);
p.getText().setDiv(div);
new ProfileUtilities(context, issues, pkp).setIds(p, false);
checkHasTypes(p);
return p;
}
use of org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionDifferentialComponent in project kindling by HL7.
the class ProfileGenerator method generate.
public StructureDefinition generate(PrimitiveType type) throws Exception {
genUml(type);
StructureDefinition p = new StructureDefinition();
p.setId(type.getCode());
p.setUrl("http://hl7.org/fhir/StructureDefinition/" + type.getCode());
p.setKind(StructureDefinitionKind.PRIMITIVETYPE);
p.setAbstract(false);
p.setUserData("filename", type.getCode().toLowerCase());
p.setUserData("path", "datatypes.html#" + type.getCode());
p.setBaseDefinition("http://hl7.org/fhir/StructureDefinition/PrimitiveType");
p.setType(type.getCode());
p.setDerivation(TypeDerivationRule.SPECIALIZATION);
p.setFhirVersion(version);
p.setVersion(version.toCode());
ToolingExtensions.setStandardsStatus(p, StandardsStatus.NORMATIVE, "4.0.0");
ToolResourceUtilities.updateUsage(p, "core");
p.setName(type.getCode());
p.setPublisher("HL7 FHIR Standard");
p.addContact().getTelecom().add(Factory.newContactPoint(ContactPointSystem.URL, "http://hl7.org/fhir"));
p.setDescription("Base StructureDefinition for " + type.getCode() + " Type: " + type.getDefinition());
p.setDate(genDate.getTime());
// normative now
p.setStatus(PublicationStatus.fromCode("active"));
Set<String> containedSlices = new HashSet<String>();
// first, the differential
p.setDifferential(new StructureDefinitionDifferentialComponent());
ElementDefinition ec = new ElementDefinition();
p.getDifferential().getElement().add(ec);
ec.setId(type.getCode());
ec.setPath(type.getCode());
ec.setShort("Primitive Type " + type.getCode());
ec.setDefinition(type.getDefinition());
ec.setComment(type.getComment());
ec.setMin(0);
ec.setMax("*");
ec = new ElementDefinition();
p.getDifferential().getElement().add(ec);
ec.setId(type.getCode() + ".value");
ec.setPath(type.getCode() + ".value");
ec.addRepresentation(PropertyRepresentation.XMLATTR);
ec.setShort("Primitive value for " + type.getCode());
ec.setDefinition("Primitive value for " + type.getCode());
ec.setMin(0);
ec.setMax("1");
TypeRefComponent t = ec.addType();
t.getFormatCommentsPre().add("Note: special primitive values have a FHIRPath system type. e.g. this is compiler magic (a)");
t.setCode(Constants.NS_SYSTEM_TYPE + type.getFHIRPathType());
ToolingExtensions.addUriExtension(t, ToolingExtensions.EXT_FHIR_TYPE, type.getCode());
if (!Utilities.noString(type.getRegex())) {
ToolingExtensions.addStringExtension(t, ToolingExtensions.EXT_REGEX, type.getRegex());
}
addSpecificDetails(type, ec);
reset();
// now. the snapshot
p.setSnapshot(new StructureDefinitionSnapshotComponent());
ElementDefinition ec1 = new ElementDefinition(true, ElementDefinition.NOT_MODIFIER, ElementDefinition.NOT_IN_SUMMARY);
p.getSnapshot().getElement().add(ec1);
ec1.setId(type.getCode());
ec1.setPath(type.getCode());
ec1.setShort("Primitive Type " + type.getCode());
ec1.setDefinition(type.getDefinition());
ec1.setComment(type.getComment());
ec1.setMin(0);
ec1.setMax("*");
ec1.makeBase();
addElementConstraints("Element", ec1);
ElementDefinition ec2 = new ElementDefinition(true, ElementDefinition.NOT_MODIFIER, ElementDefinition.NOT_IN_SUMMARY);
p.getSnapshot().getElement().add(ec2);
ec2.setId(type.getCode() + ".id");
ec2.setPath(type.getCode() + ".id");
ec2.addRepresentation(PropertyRepresentation.XMLATTR);
ec2.setDefinition("unique id for the element within a resource (for internal references)");
ec2.setMin(0);
ec2.setMax("1");
ec2.setShort("xml:id (or equivalent in JSON)");
TypeRefComponent tr = ec2.addType();
t.getFormatCommentsPre().add("Note: special primitive values have a FHIRPath system type. e.g. this is compiler magic (b)");
tr.setCode(Constants.NS_SYSTEM_TYPE + "String");
ToolingExtensions.addUriExtension(tr, ToolingExtensions.EXT_FHIR_TYPE, "string");
generateElementDefinition(p, ec2, ec1);
ec2.makeBase("Element.id", 0, "1");
makeExtensionSlice("extension", p, p.getSnapshot(), null, type.getCode());
ElementDefinition ec3 = new ElementDefinition(true, ElementDefinition.NOT_MODIFIER, ElementDefinition.NOT_IN_SUMMARY);
p.getSnapshot().getElement().add(ec3);
ec3.setId(type.getCode() + ".value");
ec3.setPath(type.getCode() + ".value");
ec3.addRepresentation(PropertyRepresentation.XMLATTR);
ec3.setDefinition("The actual value");
ec3.setMin(0);
ec3.setMax("1");
ec3.setShort("Primitive value for " + type.getCode());
ec3.makeBase();
t = ec3.addType();
t.setCodeElement(new UriType());
t.getFormatCommentsPre().add("Note: special primitive values have a FHIRPath system type. e.g. this is compiler magic (c)");
t.setCode(Constants.NS_SYSTEM_TYPE + type.getFHIRPathType());
ToolingExtensions.addUriExtension(t, ToolingExtensions.EXT_FHIR_TYPE, type.getCode());
if (!Utilities.noString(type.getRegex()))
ToolingExtensions.addStringExtension(t, ToolingExtensions.EXT_REGEX, type.getRegex());
addSpecificDetails(type, ec3);
generateElementDefinition(p, ec3, ec);
containedSlices.clear();
addElementConstraintToSnapshot(p);
XhtmlNode div = new XhtmlNode(NodeType.Element, "div");
div.addText("to do");
p.setText(new Narrative());
p.getText().setStatus(NarrativeStatus.GENERATED);
p.getText().setDiv(div);
checkHasTypes(p);
return p;
}
use of org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionDifferentialComponent in project kindling by HL7.
the class ProfileGenerator method generate.
public StructureDefinition generate(Profile pack, ResourceDefn r, String usage, boolean logical) throws Exception {
StructureDefinition p = new StructureDefinition();
p.setId(r.getRoot().getName());
p.setUrl("http://hl7.org/fhir/StructureDefinition/" + r.getRoot().getName());
if (logical)
p.setKind(StructureDefinitionKind.LOGICAL);
else
p.setKind(StructureDefinitionKind.RESOURCE);
if (r.isInterface()) {
ToolingExtensions.addBooleanExtension(p, ToolingExtensions.EXT_RESOURCE_INTERFACE, true);
}
IniFile cini = new IniFile(Utilities.path(rootFolder, "temp", "categories.ini"));
String cat = cini.getStringProperty("category", r.getName());
if (!Utilities.noString(cat))
ToolingExtensions.setStringExtension(p, ToolingExtensions.EXT_RESOURCE_CATEGORY, cat);
p.setAbstract(r.isAbstract());
assert !Utilities.noString(r.getRoot().typeCode());
if (!Utilities.noString(r.getRoot().typeCode())) {
p.setBaseDefinition("http://hl7.org/fhir/StructureDefinition/" + r.getRoot().typeCode());
p.setDerivation(TypeDerivationRule.SPECIALIZATION);
// if (r.getTemplate() != null)
// ToolingExtensions.addStringExtension(p.getBaseDefinitionElement(), ToolingExtensions.EXT_CODE_GENERATION_PARENT, r.getTemplate().getName());
}
p.setType(r.getRoot().getName());
p.setUserData("filename", r.getName().toLowerCase());
p.setUserData("path", r.getName().toLowerCase() + ".html");
p.setTitle(pack.metadata("display"));
p.setFhirVersion(version);
p.setVersion(version.toCode());
ToolingExtensions.setStandardsStatus(p, r.getStatus(), r.getNormativeVersion());
if (r.getFmmLevel() != null)
ToolingExtensions.addIntegerExtension(p, ToolingExtensions.EXT_FMM_LEVEL, Integer.parseInt(r.getFmmLevel()));
if (r.getSecurityCategorization() != null)
ToolingExtensions.addCodeExtension(p, ToolingExtensions.EXT_SEC_CAT, r.getSecurityCategorization().toCode());
ToolResourceUtilities.updateUsage(p, usage);
p.setName(r.getRoot().getName());
p.setPublisher("Health Level Seven International" + (r.getWg() == null ? "" : " (" + r.getWg().getName() + ")"));
p.addContact().getTelecom().add(Factory.newContactPoint(ContactPointSystem.URL, "http://hl7.org/fhir"));
if (r.getWg() != null)
p.addContact().getTelecom().add(Factory.newContactPoint(ContactPointSystem.URL, r.getWg().getUrl()));
ToolingExtensions.setCodeExtension(p, ToolingExtensions.EXT_WORKGROUP, r.getWg().getCode());
p.setDescription(r.getDefinition());
p.setPurpose(r.getRoot().getRequirements());
if (!p.hasPurpose())
p.setPurpose(r.getRoot().getRequirements());
p.setDate(genDate.getTime());
// DSTU
p.setStatus(r.getStatus() == StandardsStatus.NORMATIVE ? PublicationStatus.fromCode("active") : PublicationStatus.fromCode("draft"));
Set<String> containedSlices = new HashSet<String>();
// first, the differential
p.setDifferential(new StructureDefinitionDifferentialComponent());
defineElement(null, p, p.getDifferential().getElement(), r.getRoot(), r.getRoot().getName(), containedSlices, new ArrayList<ProfileGenerator.SliceHandle>(), SnapShotMode.None, true, "BackboneElement", r.getRoot().typeCode(), false);
reset();
// now. the snapshot'
p.setSnapshot(new StructureDefinitionSnapshotComponent());
defineElement(null, p, p.getSnapshot().getElement(), r.getRoot(), r.getRoot().getName(), containedSlices, new ArrayList<ProfileGenerator.SliceHandle>(), SnapShotMode.Resource, true, "BackboneElement", r.getRoot().typeCode(), true);
for (ElementDefinition ed : p.getSnapshot().getElement()) if (!ed.hasBase() && !logical)
generateElementDefinition(p, ed, getParent(ed, p.getSnapshot().getElement()));
if (!logical && !r.isInterface()) {
List<String> names = new ArrayList<String>();
names.addAll(r.getSearchParams().keySet());
Collections.sort(names);
// 1st, non composites
for (String pn : names) {
SearchParameterDefn sp = r.getSearchParams().get(pn);
if (sp.getType() != SearchType.composite)
pack.getSearchParameters().add(makeSearchParam(p, r.getName() + "-" + pn.replace("_", ""), r.getName(), sp, r));
}
for (String pn : names) {
SearchParameterDefn sp = r.getSearchParams().get(pn);
if (sp.getType() == SearchType.composite)
pack.getSearchParameters().add(makeSearchParam(p, r.getName() + "-" + pn.replace("_", ""), r.getName(), sp, r));
}
}
containedSlices.clear();
addElementConstraintToSnapshot(p);
p.getDifferential().getElement().get(0).getType().clear();
p.getSnapshot().getElement().get(0).getType().clear();
XhtmlNode div = new XhtmlNode(NodeType.Element, "div");
div.addText("to do");
p.setText(new Narrative());
p.getText().setStatus(NarrativeStatus.GENERATED);
p.getText().setDiv(div);
checkHasTypes(p);
return p;
}
use of org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionDifferentialComponent in project org.hl7.fhir.core by hapifhir.
the class ProfileUtilities method generateSnapshot.
/**
* Given a base (snapshot) profile structure, and a differential profile, generate a new snapshot profile
*
* @param base - the base structure on which the differential will be applied
* @param differential - the differential to apply to the base
* @param url - where the base has relative urls for profile references, these need to be converted to absolutes by prepending this URL (e.g. the canonical URL)
* @param webUrl - where the base has relative urls in markdown, these need to be converted to absolutes by prepending this URL (this is not the same as the canonical URL)
* @param trimDifferential - if this is true, then the snap short generator will remove any material in the element definitions that is not different to the base
* @return
* @throws FHIRException
* @throws DefinitionException
* @throws Exception
*/
public void generateSnapshot(StructureDefinition base, StructureDefinition derived, String url, String webUrl, String profileName) throws DefinitionException, FHIRException {
if (base == null)
throw new DefinitionException("no base profile provided");
if (derived == null)
throw new DefinitionException("no derived structure provided");
if (snapshotStack.contains(derived.getUrl()))
throw new DefinitionException("Circular snapshot references detected; cannot generate snapshot (stack = " + snapshotStack.toString() + ")");
snapshotStack.add(derived.getUrl());
if (!Utilities.noString(webUrl) && !webUrl.endsWith("/"))
webUrl = webUrl + '/';
derived.setSnapshot(new StructureDefinitionSnapshotComponent());
try {
// so we have two lists - the base list, and the differential list
// the differential list is only allowed to include things that are in the base list, but
// is allowed to include them multiple times - thereby slicing them
// our approach is to walk through the base list, and see whether the differential
// says anything about them.
int baseCursor = 0;
// we need a diff cursor because we can only look ahead, in the bound scoped by longer paths
int diffCursor = 0;
if (derived.hasDifferential() && !derived.getDifferential().getElementFirstRep().getPath().contains(".") && !derived.getDifferential().getElementFirstRep().getType().isEmpty())
throw new Error("type on first differential element!");
for (ElementDefinition e : derived.getDifferential().getElement()) e.clearUserData(GENERATED_IN_SNAPSHOT);
// we actually delegate the work to a subroutine so we can re-enter it with a different cursors
// we make a copy here because we're sometimes going to hack the differential while processing it. Have to migrate user data back afterwards
StructureDefinitionDifferentialComponent diff = cloneDiff(derived.getDifferential());
processPaths("", derived.getSnapshot(), base.getSnapshot(), diff, baseCursor, diffCursor, base.getSnapshot().getElement().size() - 1, derived.getDifferential().hasElement() ? derived.getDifferential().getElement().size() - 1 : -1, url, webUrl, derived.present(), null, null, false, base.getUrl(), null, false, new ArrayList<ElementRedirection>(), base);
if (!derived.getSnapshot().getElementFirstRep().getType().isEmpty())
throw new Error("type on first snapshot element for " + derived.getSnapshot().getElementFirstRep().getPath() + " in " + derived.getUrl() + " from " + base.getUrl());
updateMaps(base, derived);
if (debug) {
System.out.println("Differential: ");
for (ElementDefinition ed : derived.getDifferential().getElement()) System.out.println(" " + ed.getPath() + " : " + typeSummaryWithProfile(ed) + "[" + ed.getMin() + ".." + ed.getMax() + "]" + sliceSummary(ed) + " id = " + ed.getId() + " " + constraintSummary(ed));
System.out.println("Snapshot: ");
for (ElementDefinition ed : derived.getSnapshot().getElement()) System.out.println(" " + ed.getPath() + " : " + typeSummaryWithProfile(ed) + "[" + ed.getMin() + ".." + ed.getMax() + "]" + sliceSummary(ed) + " id = " + ed.getId() + " " + constraintSummary(ed));
}
setIds(derived, false);
// Check that all differential elements have a corresponding snapshot element
for (ElementDefinition e : diff.getElement()) {
if (!e.hasUserData("diff-source"))
throw new Error("Unxpected internal condition - no source on diff element");
else {
if (e.hasUserData(DERIVATION_EQUALS))
((Base) e.getUserData("diff-source")).setUserData(DERIVATION_EQUALS, e.getUserData(DERIVATION_EQUALS));
if (e.hasUserData(DERIVATION_POINTER))
((Base) e.getUserData("diff-source")).setUserData(DERIVATION_POINTER, e.getUserData(DERIVATION_POINTER));
}
if (!e.hasUserData(GENERATED_IN_SNAPSHOT)) {
System.out.println("Error in snapshot generation: Differential for " + derived.getUrl() + " with " + (e.hasId() ? "id: " + e.getId() : "path: " + e.getPath()) + " has an element that is not marked with a snapshot match");
if (exception)
throw new DefinitionException("Snapshot for " + derived.getUrl() + " does not contain an element that matches an existing differential element that has " + (e.hasId() ? "id: " + e.getId() : "path: " + e.getPath()));
else
messages.add(new ValidationMessage(Source.ProfileValidator, ValidationMessage.IssueType.VALUE, url, "Snapshot for " + derived.getUrl() + " does not contain an element that matches an existing differential element that has id: " + e.getId(), ValidationMessage.IssueSeverity.ERROR));
}
}
if (derived.getDerivation() == TypeDerivationRule.SPECIALIZATION) {
for (ElementDefinition ed : derived.getSnapshot().getElement()) {
if (!ed.hasBase()) {
ed.getBase().setPath(ed.getPath()).setMin(ed.getMin()).setMax(ed.getMax());
}
}
}
} catch (Exception e) {
// if we had an exception generating the snapshot, make sure we don't leave any half generated snapshot behind
derived.setSnapshot(null);
throw e;
}
}
Aggregations