diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java index 25fc8b5b8..6c581a5dd 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/ProfileUtilities.java @@ -429,7 +429,7 @@ public class ProfileUtilities extends TranslatingUtilities { throw new DefinitionException("Base profile "+base.getUrl()+" has no type"); if (!derived.hasType()) throw new DefinitionException("Derived profile "+derived.getUrl()+" has no type"); - if (!base.getType().equals(derived.getType())) + if (!base.getType().equals(derived.getType()) && derived.getDerivation().equals(TypeDerivationRule.CONSTRAINT)) throw new DefinitionException("Base & Derived profiles have different types ("+base.getUrl()+" = "+base.getType()+" vs "+derived.getUrl()+" = "+derived.getType()+")"); if (snapshotStack.contains(derived.getUrl())) @@ -461,9 +461,22 @@ public class ProfileUtilities extends TranslatingUtilities { // we actually delegate the work to a subroutine so we can re-enter it with a different cursors StructureDefinitionDifferentialComponent diff = cloneDiff(derived.getDifferential()); // we make a copy here because we're sometimes going to hack the differential while processing it. Have to migrate user data back afterwards - - processPaths("", derived.getSnapshot(), base.getSnapshot(), diff, baseCursor, diffCursor, base.getSnapshot().getElement().size()-1, + StructureDefinitionSnapshotComponent baseSnapshot = base.getSnapshot(); + if (derived.getDerivation().equals(TypeDerivationRule.SPECIALIZATION)) { + baseSnapshot = cloneSnapshot(baseSnapshot, base.getType(), derived.getType()); + } + processPaths("", derived.getSnapshot(), baseSnapshot, diff, baseCursor, diffCursor, baseSnapshot.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(), base); + if (derived.getDerivation().equals(TypeDerivationRule.SPECIALIZATION)) { + for (ElementDefinition e : diff.getElement()) { + if (!e.hasUserData(GENERATED_IN_SNAPSHOT)) { + ElementDefinition outcome = updateURLs(url, webUrl, e.copy()); + e.setUserData(GENERATED_IN_SNAPSHOT, outcome); + derived.getSnapshot().addElement(outcome); + } + } + } + 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); @@ -519,6 +532,16 @@ public class ProfileUtilities extends TranslatingUtilities { return diff; } + private StructureDefinitionSnapshotComponent cloneSnapshot(StructureDefinitionSnapshotComponent source, String baseType, String derivedType) { + StructureDefinitionSnapshotComponent diff = new StructureDefinitionSnapshotComponent(); + for (ElementDefinition sed : source.getElement()) { + ElementDefinition ted = sed.copy(); + ted.setId(ted.getId().replaceFirst(baseType,derivedType)); + ted.setPath(ted.getPath().replaceFirst(baseType,derivedType)); + diff.getElement().add(ted); + } + return diff; + } private String constraintSummary(ElementDefinition ed) { CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(); diff --git a/org.hl7.fhir.r5/src/test/resources/snapshot-generation/logical1-expected.xml b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/logical1-expected.xml new file mode 100644 index 000000000..ce5e02cd6 --- /dev/null +++ b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/logical1-expected.xml @@ -0,0 +1,234 @@ + + + + + + +
+ +

Defines the basic properties of every data value. This is an abstract type, meaning that no value can be just a data value without belonging to any concrete type. Every concrete type is a specialization of this general abstract DataValue type.

+ +
+ + + + + + + + + + + + + + + + + + + + + + + +
+ Name + + Flags + + Card. + + Type + + Description & Constraints + + + doco + + +
+ . + . + ANY + + + 1..* + +
+ . + . + . + nullFlavor + + + 0..1 + code + + Binding: + something ( + required) +
+
+ + doco Documentation for this format + +
+
+
+ + + + + + + <status value="active"/> + <experimental value="false"/> + <publisher value="HL7"/> + <description value="Defines the basic properties of every data value. This is an abstract type, meaning that no value can be just a data value without belonging to any concrete type. Every concrete type is a specialization of this general abstract DataValue type."/> + <mapping> + <identity value="rim"/> + <uri value="http://hl7.org/v3"/> + <name value="RIM Mapping"/> + </mapping> + <kind value="logical"/> + <abstract value="true"/> + <type value="ANY"/> + <baseDefinition value="http://hl7.org/fhir/StructureDefinition/Element"/> + <derivation value="specialization"/> + <snapshot> + <element id="ANY"> + <path value="ANY"/> + <short value="Base for all elements"/> + <definition value="Defines the basic properties of every data value. This is an abstract type, meaning that no value can be just a data value without belonging to any concrete type. Every concrete type is a specialization of this general abstract DataValue type."/> + <min value="1"/> + <max value="*"/> + <base> + <path value="Element"/> + <min value="0"/> + <max value="*"/> + </base> + <condition value="ele-1"/> + <constraint> + <key value="ele-1"/> + <severity value="error"/> + <human value="All FHIR elements must have a @value or children"/> + <expression value="hasValue() or (children().count() > id.count())"/> + <xpath value="@value|f:*|h:div"/> + <source value="ANY"/> + </constraint> + <isModifier value="false"/> + <mapping> + <identity value="rim"/> + <map value="n/a"/> + </mapping> + </element> + <element id="ANY.id"> + <path value="ANY.id"/> + <representation value="xmlAttr"/> + <short value="Unique id for inter-element referencing"/> + <definition value="Unique id for the element within a resource (for internal references). This may be any string value that does not contain spaces."/> + <min value="0"/> + <max value="1"/> + <base> + <path value="Element.id"/> + <min value="0"/> + <max value="1"/> + </base> + <type> + <code> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-json-type"> + <valueString value="string"/> + </extension> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-xml-type"> + <valueString value="xsd:string"/> + </extension> + <extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-rdf-type"> + <valueString value="xsd:string"/> + </extension> + </code> + </type> + <isModifier value="false"/> + <isSummary value="false"/> + <mapping> + <identity value="rim"/> + <map value="n/a"/> + </mapping> + </element> + <element id="ANY.extension"> + <path value="ANY.extension"/> + <slicing> + <discriminator> + <type value="value"/> + <path value="url"/> + </discriminator> + <description value="Extensions are always sliced by (at least) url"/> + <rules value="open"/> + </slicing> + <short value="Additional content defined by implementations"/> + <definition value="May be used to represent additional information that is not part of the basic definition of the element. To make the use of extensions safe and manageable, there is a strict set of governance applied to the definition and use of extensions. Though any implementer can define an extension, there is a set of requirements that SHALL be met as part of the definition of the extension."/> + <comment value="There can be no stigma associated with the use of extensions by any application, project, or standard - regardless of the institution or jurisdiction that uses or defines the extensions. The use of extensions is what allows the FHIR specification to retain a core level of simplicity for everyone."/> + <alias value="extensions"/> + <alias value="user content"/> + <min value="0"/> + <max value="*"/> + <base> + <path value="Element.extension"/> + <min value="0"/> + <max value="*"/> + </base> + <type> + <code value="Extension"/> + </type> + <isModifier value="false"/> + <isSummary value="false"/> + <mapping> + <identity value="rim"/> + <map value="n/a"/> + </mapping> + </element> + <element id="ANY.nullFlavor"> + <path value="ANY.nullFlavor"/> + <representation value="xmlAttr"/> + <label value="Exceptional Value Detail"/> + <definition value="If a value is an exceptional value (NULL-value), this specifies in what way and why proper information is missing."/> + <min value="0"/> + <max value="1"/> + <base> + <path value="ANY.nullFlavor"/> + <min value="0"/> + <max value="1"/> + </base> + <type> + <code value="code"/> + </type> + <binding> + <strength value="required"/> + <valueSet value="http://terminology.hl7.org/ValueSet/v3-NullFlavor"/> + </binding> + </element> + </snapshot> + <differential> + <element id="ANY"> + <path value="ANY"/> + <definition value="Defines the basic properties of every data value. This is an abstract type, meaning that no value can be just a data value without belonging to any concrete type. Every concrete type is a specialization of this general abstract DataValue type."/> + <min value="1"/> + <max value="*"/> + </element> + <element id="ANY.nullFlavor"> + <path value="ANY.nullFlavor"/> + <representation value="xmlAttr"/> + <label value="Exceptional Value Detail"/> + <definition value="If a value is an exceptional value (NULL-value), this specifies in what way and why proper information is missing."/> + <min value="0"/> + <max value="1"/> + <type> + <code value="code"/> + </type> + <binding> + <strength value="required"/> + <valueSet value="http://terminology.hl7.org/ValueSet/v3-NullFlavor"/> + </binding> + </element> + </differential> +</StructureDefinition> \ No newline at end of file diff --git a/org.hl7.fhir.r5/src/test/resources/snapshot-generation/logical1-input.xml b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/logical1-input.xml new file mode 100644 index 000000000..7dc148e44 --- /dev/null +++ b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/logical1-input.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8"?> +<StructureDefinition xmlns="http://hl7.org/fhir"> + <id value="ANY"/> + <text> + <status value="generated"/> + <div xmlns="http://www.w3.org/1999/xhtml"> + <p>Defines the basic properties of every data value. This is an abstract type, meaning that no value can be just a data value without belonging to any concrete type. Every concrete type is a specialization of this general abstract DataValue type.</p> + </div> + </text> + <extension url="http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace"> + <valueUri value="urn:hl7-org:v3"/> + </extension> + <url value="http://hl7.org/fhir/cda/StructureDefinition/ANY"/> + <name value="ANY"/> + <title value="ANY: DataValue (V3 Data Type)"/> + <status value="active"/> + <experimental value="false"/> + <publisher value="HL7"/> + <description value="Defines the basic properties of every data value. This is an abstract type, meaning that no value can be just a data value without belonging to any concrete type. Every concrete type is a specialization of this general abstract DataValue type."/> + <kind value="logical"/> + <abstract value="true"/> + <type value="ANY"/> + <baseDefinition value="http://hl7.org/fhir/StructureDefinition/Element"/> + <derivation value="specialization"/> + <differential> + <element id="ANY"> + <path value="ANY"/> + <definition value="Defines the basic properties of every data value. This is an abstract type, meaning that no value can be just a data value without belonging to any concrete type. Every concrete type is a specialization of this general abstract DataValue type."/> + <min value="1"/> + <max value="*"/> + </element> + <element id="ANY.nullFlavor"> + <path value="ANY.nullFlavor"/> + <representation value="xmlAttr"/> + <label value="Exceptional Value Detail"/> + <definition value="If a value is an exceptional value (NULL-value), this specifies in what way and why proper information is missing."/> + <min value="0"/> + <max value="1"/> + <type> + <code value="code"/> + </type> + <binding> + <strength value="required"/> + <valueSet value="http://terminology.hl7.org/ValueSet/v3-NullFlavor"/> + </binding> + </element> + </differential> +</StructureDefinition> \ No newline at end of file diff --git a/org.hl7.fhir.r5/src/test/resources/snapshot-generation/manifest.xml b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/manifest.xml index cd59f7162..1e9afdb9b 100644 --- a/org.hl7.fhir.r5/src/test/resources/snapshot-generation/manifest.xml +++ b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/manifest.xml @@ -230,4 +230,5 @@ <test gen="true" id="au2"/> <test gen="true" id="au3"/> <test gen="true" id="dv1"/> + <test gen="true" id="logical1"/> </snapshot-generation-tests>