Fix for sparse differentials

This commit is contained in:
Grahame Grieve 2019-07-29 14:10:38 +10:00
parent 94feb31bef
commit bc776064f5
17 changed files with 4862 additions and 1591 deletions

View File

@ -166,7 +166,6 @@ public class ProfileUtilities extends TranslatingUtilities {
}
}
private static int nextSliceId = 0;
private static final int MAX_RECURSION_LIMIT = 10;
public class ExtensionContext {
@ -225,7 +224,8 @@ public class ProfileUtilities extends TranslatingUtilities {
public static final String IS_DERIVED = "derived.fact";
public static final String UD_ERROR_STATUS = "error-status";
private static final String GENERATED_IN_SNAPSHOT = "profileutilities.snapshot.processed";
private static final boolean DEBUG = false;
private boolean debug;
// note that ProfileUtilities are used re-entrantly internally, so nothing with process state can be here
private final IWorkerContext context;
@ -449,13 +449,12 @@ public class ProfileUtilities extends TranslatingUtilities {
StructureDefinitionDifferentialComponent diff = derived.getDifferential().copy(); // we make a copy here because we're sometimes going to hack the differential while processing it.
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.getId(), null, null, false, base.getUrl(), null, false, new ArrayList<ElementRedirection>(), base);
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);
setIds(derived, false);
if (DEBUG) {
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));
@ -463,12 +462,13 @@ public class ProfileUtilities extends TranslatingUtilities {
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(GENERATED_IN_SNAPSHOT)) {
System.out.println("Error in snapshot generation: Differential for "+derived.getUrl()+" with id: " + e.getId()+" has an element that is not marked with a snapshot match");
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 id: " + e.getId());
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));
}
@ -572,7 +572,7 @@ public class ProfileUtilities extends TranslatingUtilities {
*/
private ElementDefinition processPaths(String indent, StructureDefinitionSnapshotComponent result, StructureDefinitionSnapshotComponent base, StructureDefinitionDifferentialComponent differential, int baseCursor, int diffCursor, int baseLimit,
int diffLimit, String url, String webUrl, String profileName, String contextPathSrc, String contextPathDst, boolean trimDifferential, String contextName, String resultPathBase, boolean slicingDone, List<ElementRedirection> redirector, StructureDefinition srcSD) throws DefinitionException, FHIRException {
if (DEBUG)
if (debug)
System.out.println(indent+"PP @ "+resultPathBase+" / "+contextPathSrc+" : base = "+baseCursor+" to "+baseLimit+", diff = "+diffCursor+" to "+diffLimit+" (slicing = "+slicingDone+", redirector = "+(redirector == null ? "null" : redirector.toString())+")");
ElementDefinition res = null;
List<TypeSlice> typeList = new ArrayList<>();
@ -581,7 +581,7 @@ public class ProfileUtilities extends TranslatingUtilities {
// get the current focus of the base, and decide what to do
ElementDefinition currentBase = base.getElement().get(baseCursor);
String cpath = fixedPathSource(contextPathSrc, currentBase.getPath(), redirector);
if (DEBUG)
if (debug)
System.out.println(indent+" - "+cpath+": base = "+baseCursor+" to "+baseLimit+", diff = "+diffCursor+" to "+diffLimit+" (slicingDone = "+slicingDone+") (diffpath= "+(differential.getElement().size() > diffCursor ? differential.getElement().get(diffCursor).getPath() : "n/a")+")");
List<ElementDefinition> diffMatches = getDiffMatches(differential, cpath, diffCursor, diffLimit, profileName); // get a list of matching elements in scope
@ -600,21 +600,30 @@ public class ProfileUtilities extends TranslatingUtilities {
result.getElement().add(outcome);
if (hasInnerDiffMatches(differential, cpath, diffCursor, diffLimit, base.getElement())) {
// well, the profile walks into this, so we need to as well
if (outcome.getType().size() > 1) {
for (TypeRefComponent t : outcome.getType()) {
if (!t.getCode().equals("Reference"))
throw new DefinitionException(diffMatches.get(0).getPath()+" has children ("+differential.getElement().get(diffCursor).getPath()+") and multiple types ("+typeCode(outcome.getType())+") in profile "+profileName);
// did we implicitly step into a new type?
if (baseHasChildren(base, currentBase)) { // not a new type here
processPaths(indent+" ", result, base, differential, baseCursor+1, diffCursor, baseLimit, diffLimit, url, webUrl, profileName, contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, false, redirector, srcSD);
baseCursor = indexOfFirstNonChild(base, currentBase, baseCursor+1, baseLimit);
} else {
if (outcome.getType().size() == 0) {
throw new DefinitionException(diffMatches.get(0).getPath()+" has no children ("+differential.getElement().get(diffCursor).getPath()+") and no types in profile "+profileName);
}
if (outcome.getType().size() > 1) {
for (TypeRefComponent t : outcome.getType()) {
if (!t.getCode().equals("Reference"))
throw new DefinitionException(diffMatches.get(0).getPath()+" has children ("+differential.getElement().get(diffCursor).getPath()+") and multiple types ("+typeCode(outcome.getType())+") in profile "+profileName);
}
}
StructureDefinition dt = getProfileForDataType(outcome.getType().get(0));
if (dt == null)
throw new DefinitionException("Unknown type "+outcome.getType().get(0)+" at "+diffMatches.get(0).getPath());
contextName = dt.getUrl();
int start = diffCursor;
while (differential.getElement().size() > diffCursor && pathStartsWith(differential.getElement().get(diffCursor).getPath(), cpath+"."))
diffCursor++;
processPaths(indent+" ", result, dt.getSnapshot(), differential, 1 /* starting again on the data type, but skip the root */, start, dt.getSnapshot().getElement().size()-1,
diffCursor-1, url, webUrl, profileName, cpath, outcome.getPath(), trimDifferential, contextName, resultPathBase, false, redirector, srcSD);
}
StructureDefinition dt = outcome.getType().isEmpty() ? null : getProfileForDataType(outcome.getType().get(0));
if (dt == null)
throw new DefinitionException(cpath+" has children for type "+typeCode(outcome.getType())+" in profile "+profileName+", but can't find type");
contextName = dt.getUrl();
int start = diffCursor;
while (differential.getElement().size() > diffCursor && pathStartsWith(differential.getElement().get(diffCursor).getPath(), cpath+"."))
diffCursor++;
processPaths(indent+" ", result, dt.getSnapshot(), differential, 1 /* starting again on the data type, but skip the root */, start, dt.getSnapshot().getElement().size()-1,
diffCursor-1, url, webUrl, profileName, cpath, outcome.getPath(), trimDifferential, contextName, resultPathBase, false, redirector, srcSD);
}
baseCursor++;
} else if (diffMatches.size() == 1 && (slicingDone || (!isImplicitSlicing(diffMatches.get(0), cpath) && !(diffMatches.get(0).hasSlicing() || (isExtension(diffMatches.get(0)) && diffMatches.get(0).hasSliceName()))))) {// one matching element in the differential
@ -775,10 +784,15 @@ public class ProfileUtilities extends TranslatingUtilities {
if (diffMatches.get(0).getSlicing().getDiscriminatorFirstRep().getType() != DiscriminatorType.TYPE)
throw new FHIRException("Error at path "+contextPathSrc+": Type slicing with slicing.discriminator.type != 'type'");
}
// fix the slice names too while we're at it...
// check the slice names too while we're at it...
for (TypeSlice ts : typeList)
if (ts.type != null)
ts.defn.setSliceName(rootName(cpath)+Utilities.capitalize(ts.type));
if (ts.type != null) {
String tn = rootName(cpath)+Utilities.capitalize(ts.type);
if (!ts.defn.hasSliceName())
ts.defn.setSliceName(tn);
else if (!ts.defn.getSliceName().equals(tn))
throw new FHIRException("Error at path "+(!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath)+": Slice name must be '"+tn+"' but is '"+ts.defn.getSliceName()+"'");
}
// ok passed the checks.
// copy the root diff, and then process any children it has
@ -1072,6 +1086,29 @@ public class ProfileUtilities extends TranslatingUtilities {
}
private boolean baseHasChildren(StructureDefinitionSnapshotComponent base, ElementDefinition ed) {
int index = base.getElement().indexOf(ed);
if (index == -1 || index >= base.getElement().size()-1)
return false;
String p = base.getElement().get(index+1).getPath();
return isChildOf(p, ed.getPath());
}
private boolean isChildOf(String sub, String focus) {
if (focus.endsWith("[x]")) {
focus = focus.substring(0, focus.length()-3);
return sub.startsWith(focus);
} else
return sub.startsWith(focus+".");
}
private int indexOfFirstNonChild(StructureDefinitionSnapshotComponent base, ElementDefinition currentBase, int i, int baseLimit) {
return baseLimit+1;
}
private String rootName(String cpath) {
String t = tail(cpath);
return t.replace("[x]", "");
@ -1500,8 +1537,6 @@ public class ProfileUtilities extends TranslatingUtilities {
private ElementDefinitionSlicingComponent makeExtensionSlicing() {
ElementDefinitionSlicingComponent slice = new ElementDefinitionSlicingComponent();
nextSliceId++;
slice.setId(Integer.toString(nextSliceId));
slice.addDiscriminator().setPath("url").setType(DiscriminatorType.VALUE);
slice.setOrdered(false);
slice.setRules(SlicingRules.OPEN);
@ -1515,13 +1550,16 @@ public class ProfileUtilities extends TranslatingUtilities {
private boolean hasInnerDiffMatches(StructureDefinitionDifferentialComponent context, String path, int start, int end, List<ElementDefinition> base) throws DefinitionException {
for (int i = start; i <= end; i++) {
String statedPath = context.getElement().get(i).getPath();
if (statedPath.startsWith(path+".") && !statedPath.substring(path.length()+1).contains(".")) {
if (statedPath.startsWith(path+".")) {
boolean found = false;
for (ElementDefinition ed : base) {
String ep = ed.getPath();
if (ep.equals(statedPath) || (ep.endsWith("[x]") && statedPath.length() > ep.length() - 2 && statedPath.substring(0, ep.length()-3).equals(ep.substring(0, ep.length()-3)) && !statedPath.substring(ep.length()).contains(".")))
found = true;
}
// GG - I don't know what this code is doing....
// for (ElementDefinition ed : base) {
// String ep = ed.getPath();
// if (ep.equals(statedPath) || (ep.endsWith("[x]") && statedPath.length() > ep.length() - 2 && statedPath.substring(0, ep.length()-3).equals(ep.substring(0, ep.length()-3)) && !statedPath.substring(ep.length()).contains("."))) {
// found = true;
// break;
// }
// }
if (!found)
return true;
}
@ -4380,6 +4418,16 @@ public class ProfileUtilities extends TranslatingUtilities {
}
public boolean isDebug() {
return debug;
}
public void setDebug(boolean debug) {
this.debug = debug;
}
}

View File

@ -23,6 +23,7 @@ import org.hl7.fhir.r5.conformance.ProfileUtilities;
import org.hl7.fhir.r5.conformance.ProfileUtilities.ProfileKnowledgeProvider;
import org.hl7.fhir.r5.context.SimpleWorkerContext;
import org.hl7.fhir.r5.formats.IParser.OutputStyle;
import org.hl7.fhir.r5.formats.JsonParser;
import org.hl7.fhir.r5.formats.XmlParser;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.model.Coding;
@ -161,12 +162,16 @@ public class SnapShotGenerationTests {
this.output = output;
}
public void load() throws FHIRFormatError, FileNotFoundException, IOException {
source = (StructureDefinition) new XmlParser().parse(new FileInputStream(Utilities.path(TestingUtilities.resourceNameToFile("snapshot-generation", id+"-input.xml"))));
expected = (StructureDefinition) new XmlParser().parse(new FileInputStream(Utilities.path(TestingUtilities.resourceNameToFile("snapshot-generation", id+"-expected.xml"))));
if (new File(TestingUtilities.resourceNameToFile("snapshot-generation", id+"-input.json")).exists())
source = (StructureDefinition) new JsonParser().parse(new FileInputStream(TestingUtilities.resourceNameToFile("snapshot-generation", id+"-input.json")));
else
source = (StructureDefinition) new XmlParser().parse(new FileInputStream(TestingUtilities.resourceNameToFile("snapshot-generation", id+"-input.xml")));
if (!fail)
expected = (StructureDefinition) new XmlParser().parse(new FileInputStream(TestingUtilities.resourceNameToFile("snapshot-generation", id+"-expected.xml")));
if (!Utilities.noString(include))
included = (StructureDefinition) new XmlParser().parse(new FileInputStream(Utilities.path(TestingUtilities.resourceNameToFile("snapshot-generation", include+".xml"))));
included = (StructureDefinition) new XmlParser().parse(new FileInputStream(TestingUtilities.resourceNameToFile("snapshot-generation", include+".xml")));
if (!Utilities.noString(register)) {
included = (StructureDefinition) new XmlParser().parse(new FileInputStream(Utilities.path(TestingUtilities.resourceNameToFile("snapshot-generation", register+".xml"))));
included = (StructureDefinition) new XmlParser().parse(new FileInputStream(TestingUtilities.resourceNameToFile("snapshot-generation", register+".xml")));
}
}
}
@ -338,7 +343,7 @@ public class SnapShotGenerationTests {
if (url == null)
return null;
for (TestDetails t : tests) {
if (url.equals(t.expected.getUrl()))
if (t.expected != null && url.equals(t.expected.getUrl()))
return t.expected;
if (t.included != null && url.equals(t.included.getUrl()))
return t.expected;
@ -417,7 +422,7 @@ public class SnapShotGenerationTests {
pu.sortDifferential(base, test.getOutput(), test.getOutput().getUrl(), errors);
if (!errors.isEmpty())
throw new FHIRException(errors.get(0));
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(TestingUtilities.resourceNameToFile("snapshot-generation", test.getId()+"-output.xml")), test.getOutput());
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(TestingUtilities.resourceNameToFile("snapshot-generation", test.getId()+"-actual.xml")), test.getOutput());
Assert.assertTrue("Output does not match expected", test.expected.equalsDeep(test.output));
}
@ -435,6 +440,8 @@ public class SnapShotGenerationTests {
StructureDefinition output = test.getSource().copy();
ProfileUtilities pu = new ProfileUtilities(TestingUtilities.context(), messages , new TestPKP());
pu.setNewSlicingProcessing(true);
pu.setThrowException(true);
pu.setDebug(true);
pu.setIds(test.getSource(), false);
if (test.isSort()) {
List<String> errors = new ArrayList<String>();
@ -443,12 +450,17 @@ public class SnapShotGenerationTests {
if (errors.size() > 0)
throw new FHIRException("Sort failed: "+errors.toString());
}
pu.generateSnapshot(base, output, test.getSource().getUrl(), "http://test.org/profile", test.getSource().getName());
try {
pu.generateSnapshot(base, output, test.getSource().getUrl(), "http://test.org/profile", test.getSource().getName());
} catch (Throwable e) {
System.out.println("\r\nException: "+e.getMessage());
throw e;
}
if (output.getDifferential().hasElement())
new NarrativeGenerator("", "http://hl7.org/fhir", TestingUtilities.context()).setPkp(new TestPKP()).generate(output, null);
test.output = output;
TestingUtilities.context().cacheResource(output);
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(TestingUtilities.resourceNameToFile("snapshot-generation", test.getId()+"-output.xml")), output);
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(TestingUtilities.resourceNameToFile("snapshot-generation", test.getId()+"-actual.xml")), output);
StructureDefinition t1 = test.expected.copy();
t1.setText(null);
StructureDefinition t2 = test.output.copy();

View File

@ -0,0 +1,2 @@
del *.bak
del *-actual.*

View File

@ -142,9 +142,10 @@
<test gen="true" id="t22">
<rule text="element count increased by 76" fhirpath="fixture('t22-output').snapshot.element.count().trace('t22o') = fixture('patient').snapshot.element.count().trace('t22patient') + 76"/>
</test>
<test gen="true" id="t23">
<test gen="true" sort="true" id="t23">
<rule text="element count increased by ??" fhirpath="fixture('t23-output').snapshot.element.count().trace('t23o') = fixture('patient').snapshot.element.count().trace('t23patient') + 11"/>
</test>
<test gen="true" id="t23a" fail="true"/>
<test gen="true" id="t24b" register="t24a">
<rule text="Element count of profile a is increased by 22 from base Patient" fhirpath="fixture('t24b-output').snapshot.element.count().trace('t24ao') = fixture('patient').snapshot.element.count().trace('t24Patient') + 22"/>
<rule text="Element count of profile b is identical to profile a" fhirpath="fixture('t24b-output').snapshot.element.count().trace('t24bo') = fixture('t24b-include').snapshot.element.count().trace('t24ao')"/>
@ -219,4 +220,6 @@
<rule text="The element definition for value[x] quantity slice should have sliceName = 'Quantity'" fhirpath="fixture('t44-output').snapshot.element.where(id = 'Observation.value[x]:valueQuantity').check(exists(), 'no slice').sliceName = 'valueQuantity'"/>
<rule text="The element definition for value[x].value quantity slice should have sliceName = 'Quantity'" fhirpath="fixture('t44-output').snapshot.element.where(id = 'Observation.value[x]:valueQuantity.value').check(exists(), 'no slice').min = 1"/>
</test>
<test gen="true" id="samply1">
</test>
</snapshot-generation-tests>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,277 @@
{
"resourceType": "StructureDefinition",
"url": "https://fhir.bbmri.de/StructureDefinition/BbmriBiobank",
"name": "BbmriBiobank",
"status": "draft",
"fhirVersion": "4.0.0",
"kind": "resource",
"abstract": false,
"type": "Organization",
"baseDefinition": "http://hl7.org/fhir/StructureDefinition/Organization",
"derivation": "constraint",
"differential": {
"element": [
{
"id": "Organization.extension",
"path": "Organization.extension",
"slicing": {
"discriminator": [
{
"type": "value",
"path": "url"
}
],
"rules": "open"
}
},
{
"id": "Organization.extension:description",
"path": "Organization.extension",
"sliceName": "description",
"min": 1,
"max": "1",
"type": [
{
"code": "Extension",
"profile": [
"https://fhir.bbmri.de/StructureDefinition/BbmriOrganizationDescription"
]
}
]
},
{
"id": "Organization.extension:juridicalPerson",
"path": "Organization.extension",
"sliceName": "juridicalPerson",
"min": 1,
"max": "1",
"type": [
{
"code": "Extension",
"profile": [
"https://fhir.bbmri.de/StructureDefinition/BbmriJuridicalPerson"
]
}
]
},
{
"id": "Organization.extension:qualityStandard",
"path": "Organization.extension",
"sliceName": "qualityStandard",
"min": 0,
"max": "*",
"type": [
{
"code": "Extension",
"profile": [
"https://fhir.bbmri.de/StructureDefinition/BbmriQualityStandards"
]
}
]
},
{
"id": "Organization.identifier",
"path": "Organization.identifier",
"slicing": {
"discriminator": [
{
"type": "value",
"path": "system"
}
],
"rules": "open"
},
"min": 1
},
{
"id": "Organization.identifier:Bbmri-EricId",
"path": "Organization.identifier",
"sliceName": "Bbmri-EricId",
"min": 1,
"max": "1"
},
{
"id": "Organization.identifier:Bbmri-EricId.system",
"path": "Organization.identifier.system",
"fixedUri": "http://www.bbmri-eric.eu/"
},
{
"id": "Organization.identifier:Bbmri-EricId.value",
"path": "Organization.identifier.value",
"constraint": [
{
"key": "bbmri-id-1",
"requirements": "Make sure valid BBMRI IDs are provided",
"severity": "warning",
"human": "<CC>_<local id>: SHALL contain valid ISO-3166-1 alpha 2 country code followed by _ followed by biobank ID of national registry (if present).",
"expression": "matches('^([a-z]){2}_([a-zA-Z\\\\d])+$')"
}
]
},
{
"id": "Organization.name",
"path": "Organization.name",
"min": 1
},
{
"id": "Organization.alias",
"path": "Organization.alias",
"max": "1"
},
{
"id": "Organization.telecom",
"path": "Organization.telecom",
"slicing": {
"discriminator": [
{
"type": "value",
"path": "system"
}
],
"rules": "open"
}
},
{
"id": "Organization.telecom:url",
"path": "Organization.telecom",
"sliceName": "url"
},
{
"id": "Organization.telecom:url.system",
"path": "Organization.telecom.system",
"min": 1,
"fixedCode": "url"
},
{
"id": "Organization.telecom:url.value",
"path": "Organization.telecom.value",
"min": 1
},
{
"id": "Organization.address",
"path": "Organization.address",
"min": 1
},
{
"id": "Organization.address.country",
"path": "Organization.address.country",
"min": 1
},
{
"id": "Organization.contact",
"path": "Organization.contact",
"slicing": {
"discriminator": [
{
"type": "value",
"path": "purpose"
}
],
"rules": "open"
},
"min": 2
},
{
"id": "Organization.contact:head",
"path": "Organization.contact",
"sliceName": "head",
"min": 1,
"max": "1"
},
{
"id": "Organization.contact:head.purpose.coding.system",
"path": "Organization.contact.purpose.coding.system",
"fixedUri": "http://terminology.hl7.org/CodeSystem/contactentity-type"
},
{
"id": "Organization.contact:head.purpose.coding.code",
"path": "Organization.contact.purpose.coding.code",
"fixedCode": "ADMIN"
},
{
"id": "Organization.contact:head.name.family",
"path": "Organization.contact.name.family",
"min": 1
},
{
"id": "Organization.contact:head.name.given",
"path": "Organization.contact.name.given",
"min": 1,
"max": "1"
},
{
"id": "Organization.contact:contact",
"path": "Organization.contact",
"sliceName": "contact",
"min": 1,
"max": "1"
},
{
"id": "Organization.contact:contact.purpose.coding.system",
"path": "Organization.contact.purpose.coding.system",
"fixedUri": "https://fhir.bbmri.de/CodeSystem/BbmriContactTypes"
},
{
"id": "Organization.contact:contact.purpose.coding.code",
"path": "Organization.contact.purpose.coding.code",
"fixedCode": "RESEARCH"
},
{
"id": "Organization.contact:contact.telecom",
"path": "Organization.contact.telecom",
"slicing": {
"discriminator": [
{
"type": "value",
"path": "system"
}
],
"rules": "open"
},
"min": 1
},
{
"id": "Organization.contact:contact.telecom:phone",
"path": "Organization.contact.telecom",
"sliceName": "phone"
},
{
"id": "Organization.contact:contact.telecom:phone.system",
"path": "Organization.contact.telecom.system",
"fixedCode": "phone"
},
{
"id": "Organization.contact:contact.telecom:email",
"path": "Organization.contact.telecom",
"sliceName": "email",
"min": 1,
"max": "1"
},
{
"id": "Organization.contact:contact.telecom:email.system",
"path": "Organization.contact.telecom.system",
"fixedCode": "email"
},
{
"id": "Organization.contact:contact.telecom:email.value",
"path": "Organization.contact.telecom.value",
"min": 1
},
{
"id": "Organization.contact:contact.address",
"path": "Organization.contact.address",
"min": 1
},
{
"id": "Organization.contact:contact.address.line",
"path": "Organization.contact.address.line",
"max": "1"
},
{
"id": "Organization.contact:contact.address.country",
"path": "Organization.contact.address.country",
"min": 1
}
]
}
}

View File

@ -44,7 +44,7 @@
<br/>
<span style="font-weight:bold">URL: </span>http://hl7.org/fhir/StructureDefinition/patient-birthTime
</td>
</tr>
</tr>
<tr>
<td colspan="5" class="hierarchy">
@ -304,7 +304,7 @@
</element>
<element id="Patient.extension">
<path value="Patient.extension"/>
<slicing id="1">
<slicing>
<discriminator>
<type value="value"/>
<path value="url"/>

View File

@ -44,7 +44,7 @@
<br/>
<span style="font-weight:bold">URL: </span>http://hl7.org/fhir/StructureDefinition/patient-birthTime
</td>
</tr>
</tr>
<tr>
<td colspan="5" class="hierarchy">
@ -304,7 +304,7 @@
</element>
<element id="Patient.extension">
<path value="Patient.extension"/>
<slicing id="2">
<slicing>
<discriminator>
<type value="value"/>
<path value="url"/>

View File

@ -39,7 +39,7 @@
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
</tr>
</tr>
<tr style="border: 0px #F0F0F0 solid; padding:0px; vertical-align: top; background-color: #F7F7F7;">
<td style="vertical-align: top; text-align : left; background-color: #F7F7F7; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px; white-space: nowrap; background-image: url(tbl_bck54.png)" class="hierarchy">
@ -53,7 +53,7 @@
<td style="vertical-align: top; text-align : left; background-color: #F7F7F7; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
<td style="vertical-align: top; text-align : left; background-color: #F7F7F7; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
<td style="vertical-align: top; text-align : left; background-color: #F7F7F7; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
</tr>
</tr>
<tr style="border: 0px #F0F0F0 solid; padding:0px; vertical-align: top; background-color: white;">
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px; white-space: nowrap; background-image: url(tbl_bck44.png)" class="hierarchy">
@ -67,7 +67,7 @@
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
</tr>
</tr>
<tr>
<td colspan="5" class="hierarchy">
@ -909,7 +909,7 @@
</element>
<element id="Patient.address.extension:Geolocation.extension:latitude.valueDecimal.extension">
<path value="Patient.address.extension.extension.valueDecimal.extension"/>
<slicing id="3">
<slicing>
<discriminator>
<type value="value"/>
<path value="url"/>
@ -1229,7 +1229,7 @@
</element>
<element id="Patient.address.extension:Geolocation.extension:longitude.valueDecimal.extension">
<path value="Patient.address.extension.extension.valueDecimal.extension"/>
<slicing id="4">
<slicing>
<discriminator>
<type value="value"/>
<path value="url"/>

View File

@ -41,7 +41,7 @@
<a href="patient-birthTime.html" title="Extension">Birth Time</a>
</td>
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
</tr>
</tr>
<tr>
<td colspan="5" class="hierarchy">
@ -325,7 +325,7 @@
</element>
<element id="Patient.modifierExtension">
<path value="Patient.modifierExtension"/>
<slicing id="5">
<slicing>
<discriminator>
<type value="value"/>
<path value="url"/>

View File

@ -41,7 +41,7 @@
<a href="patient-birthTime.html" title="Extension">Birth Time</a>
</td>
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
</tr>
</tr>
<tr>
<td colspan="5" class="hierarchy">
@ -325,7 +325,7 @@
</element>
<element id="Patient.modifierExtension">
<path value="Patient.modifierExtension"/>
<slicing id="6">
<slicing>
<discriminator>
<type value="value"/>
<path value="url"/>

View File

@ -39,7 +39,7 @@
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
</tr>
</tr>
<tr style="border: 0px #F0F0F0 solid; padding:0px; vertical-align: top; background-color: #F7F7F7;">
<td style="vertical-align: top; text-align : left; background-color: #F7F7F7; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px; white-space: nowrap; background-image: url(tbl_bck12.png)" class="hierarchy">
@ -56,7 +56,7 @@
<span style="font-weight:bold; font-style: italic">Slice: </span>
<span style="font-style: italic">Unordered, Open by value:gender</span>
</td>
</tr>
</tr>
<tr style="border: 0px #F0F0F0 solid; padding:0px; vertical-align: top; background-color: white;">
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px; white-space: nowrap; background-image: url(tbl_bck05.png)" class="hierarchy">
@ -70,7 +70,7 @@
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
</tr>
</tr>
<tr style="border: 0px #F0F0F0 solid; padding:0px; vertical-align: top; background-color: #F7F7F7;">
<td style="vertical-align: top; text-align : left; background-color: #F7F7F7; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px; white-space: nowrap; background-image: url(tbl_bck050.png)" class="hierarchy">
@ -78,17 +78,14 @@
<img src="tbl_blank.png" alt="." style="background-color: inherit" class="hierarchy"/>
<img src="tbl_vjoin_slice.png" alt="." style="background-color: inherit" class="hierarchy"/>
<img src="icon_element.gif" alt="." style="background-color: #F7F7F7; background-color: inherit" title="Element" class="hierarchy"/>
<span title="null">gender</span>
<a name="Patient.contact.gender"> </a>
<span title="null">telecom</span>
<a name="Patient.contact.telecom"> </a>
</td>
<td style="vertical-align: top; text-align : left; background-color: #F7F7F7; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
<td style="vertical-align: top; text-align : left; background-color: #F7F7F7; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy">1..</td>
<td style="vertical-align: top; text-align : left; background-color: #F7F7F7; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
<td style="vertical-align: top; text-align : left; background-color: #F7F7F7; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
<td style="vertical-align: top; text-align : left; background-color: #F7F7F7; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy">
<span style="font-weight:bold">Fixed Value: </span>
<span style="color: darkgreen">male</span>
</td>
</tr>
</tr>
<tr style="border: 0px #F0F0F0 solid; padding:0px; vertical-align: top; background-color: white;">
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px; white-space: nowrap; background-image: url(tbl_bck040.png)" class="hierarchy">
@ -96,14 +93,17 @@
<img src="tbl_blank.png" alt="." style="background-color: inherit" class="hierarchy"/>
<img src="tbl_vjoin_end_slice.png" alt="." style="background-color: inherit" class="hierarchy"/>
<img src="icon_element.gif" alt="." style="background-color: white; background-color: inherit" title="Element" class="hierarchy"/>
<span title="null">telecom</span>
<a name="Patient.contact.telecom"> </a>
<span title="null">gender</span>
<a name="Patient.contact.gender"> </a>
</td>
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy">1..</td>
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
</tr>
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy">
<span style="font-weight:bold">Fixed Value: </span>
<span style="color: darkgreen">male</span>
</td>
</tr>
<tr>
<td colspan="5" class="hierarchy">
@ -1406,6 +1406,7 @@
<type>
<code value="code"/>
</type>
<fixedCode value="male"/>
<isModifier value="false"/>
<isSummary value="false"/>
<binding>
@ -1931,13 +1932,13 @@
<path value="Patient.contact"/>
<sliceName value="males"/>
</element>
<element id="Patient.contact:males.gender">
<path value="Patient.contact.gender"/>
<fixedCode value="male"/>
</element>
<element id="Patient.contact:males.telecom">
<path value="Patient.contact.telecom"/>
<min value="1"/>
</element>
<element id="Patient.contact:males.gender">
<path value="Patient.contact.gender"/>
<fixedCode value="male"/>
</element>
</differential>
</StructureDefinition>

View File

@ -802,7 +802,7 @@
</element>
<element id="OperationOutcome.issue.details.text.extension">
<path value="OperationOutcome.issue.details.text.extension"/>
<slicing id="7">
<slicing>
<discriminator>
<type value="value"/>
<path value="url"/>
@ -1005,7 +1005,7 @@
</element>
<element id="OperationOutcome.issue.details.text.extension:translation.value[x]:string.extension">
<path value="OperationOutcome.issue.details.text.extension.value[x].extension"/>
<slicing id="8">
<slicing>
<discriminator>
<type value="value"/>
<path value="url"/>

View File

@ -1077,16 +1077,16 @@
<code value="Coding"/>
</type>
</element>
<element id="Parameters.parameter.part:foo.value[x]:valueCoding">
<path value="Parameters.parameter.part.value[x]"/>
<element id="Parameters.parameter.part:foo.valueCoding:valueCoding">
<path value="Parameters.parameter.part.valueCoding"/>
<sliceName value="valueCoding"/>
<min value="1"/>
<type>
<code value="Coding"/>
</type>
</element>
<element id="Parameters.parameter.part:foo.value[x]:Coding.code">
<path value="Parameters.parameter.part.value[x].code"/>
<element id="Parameters.parameter.part:foo.valueCoding:valueCoding.code">
<path value="Parameters.parameter.part.valueCoding.code"/>
<min value="1"/>
</element>
</differential>

View File

@ -39,7 +39,7 @@
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
</tr>
</tr>
<tr style="border: 0px #F0F0F0 solid; padding:0px; vertical-align: top; background-color: #F7F7F7;">
<td style="vertical-align: top; text-align : left; background-color: #F7F7F7; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px; white-space: nowrap; background-image: url(tbl_bck12.png)" class="hierarchy">
@ -56,7 +56,7 @@
<span style="font-weight:bold; font-style: italic">Slice: </span>
<span style="font-style: italic">Unordered, Open by value:name</span>
</td>
</tr>
</tr>
<tr style="border: 0px #F0F0F0 solid; padding:0px; vertical-align: top; background-color: white;">
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px; white-space: nowrap; background-image: url(tbl_bck05.png)" class="hierarchy">
@ -70,7 +70,7 @@
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
</tr>
</tr>
<tr style="border: 0px #F0F0F0 solid; padding:0px; vertical-align: top; background-color: #F7F7F7;">
<td style="vertical-align: top; text-align : left; background-color: #F7F7F7; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px; white-space: nowrap; background-image: url(tbl_bck050.png)" class="hierarchy">
@ -88,7 +88,7 @@
<span style="font-weight:bold">Fixed Value: </span>
<span style="color: darkgreen">string</span>
</td>
</tr>
</tr>
<tr style="border: 0px #F0F0F0 solid; padding:0px; vertical-align: top; background-color: white;">
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px; white-space: nowrap; background-image: url(tbl_bck041.png)" class="hierarchy">
@ -108,7 +108,7 @@
<span style="font-weight:bold">Max Length: </span>
<span style="color: darkgreen">2</span>
</td>
</tr>
</tr>
<tr style="border: 0px #F0F0F0 solid; padding:0px; vertical-align: top; background-color: #F7F7F7;">
<td style="vertical-align: top; text-align : left; background-color: #F7F7F7; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px; white-space: nowrap; background-image: url(tbl_bck0405.png)" class="hierarchy">
@ -127,7 +127,7 @@
<br/>
<span style="font-weight:bold">URL: </span>http://hl7.org/fhir/StructureDefinition/translation
</td>
</tr>
</tr>
<tr style="border: 0px #F0F0F0 solid; padding:0px; vertical-align: top; background-color: white;">
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px; white-space: nowrap; background-image: url(tbl_bck04045.png)" class="hierarchy">
@ -144,7 +144,7 @@
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
<td style="vertical-align: top; text-align : left; background-color: white; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px" class="hierarchy"/>
</tr>
</tr>
<tr style="border: 0px #F0F0F0 solid; padding:0px; vertical-align: top; background-color: #F7F7F7;">
<td style="vertical-align: top; text-align : left; background-color: #F7F7F7; border: 0px #F0F0F0 solid; padding:0px 4px 0px 4px; white-space: nowrap; background-image: url(tbl_bck040444.png)" class="hierarchy">
@ -165,7 +165,7 @@
<span style="font-weight:bold">Max Length: </span>
<span style="color: darkgreen">2</span>
</td>
</tr>
</tr>
<tr>
<td colspan="5" class="hierarchy">
@ -805,7 +805,7 @@
</element>
<element id="Parameters.parameter:string.value[x].extension">
<path value="Parameters.parameter.value[x].extension"/>
<slicing id="9">
<slicing>
<discriminator>
<type value="value"/>
<path value="url"/>

View File

@ -144,6 +144,9 @@ public class Utilities {
if (isBlank(string)) {
return false;
}
if (string.startsWith("-"))
string = string.substring(1);
boolean havePeriod = false;
for (char next : string.toCharArray()) {
if (next == '.') {