From bc776064f56ad934cb4b803b65aee688dd4afaf0 Mon Sep 17 00:00:00 2001 From: Grahame Grieve Date: Mon, 29 Jul 2019 14:10:38 +1000 Subject: [PATCH] Fix for sparse differentials --- .../fhir/r5/conformance/ProfileUtilities.java | 114 +- .../fhir/r5/test/SnapShotGenerationTests.java | 28 +- .../resources/snapshot-generation/clean.bat | 2 + .../snapshot-generation/manifest.xml | 5 +- .../snapshot-generation/samply1-expected.xml | 4428 +++++++++++++++++ .../snapshot-generation/samply1-input.json | 277 ++ .../snapshot-generation/t12-expected.xml | 4 +- .../snapshot-generation/t12a-expected.xml | 4 +- .../snapshot-generation/t16-expected.xml | 10 +- .../snapshot-generation/t18-expected.xml | 4 +- .../snapshot-generation/t19-expected.xml | 4 +- .../snapshot-generation/t23-expected.xml | 37 +- .../snapshot-generation/t28-expected.xml | 4 +- .../snapshot-generation/t29-expected.xml | 8 +- .../snapshot-generation/t31-expected.xml | 18 +- .../snapshot-generation/t4a-output.xml | 1503 ------ .../org/hl7/fhir/utilities/Utilities.java | 3 + 17 files changed, 4862 insertions(+), 1591 deletions(-) create mode 100644 org.hl7.fhir.r5/src/test/resources/snapshot-generation/clean.bat create mode 100644 org.hl7.fhir.r5/src/test/resources/snapshot-generation/samply1-expected.xml create mode 100644 org.hl7.fhir.r5/src/test/resources/snapshot-generation/samply1-input.json delete mode 100644 org.hl7.fhir.r5/src/test/resources/snapshot-generation/t4a-output.xml 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 666e79aa9..701407b3b 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 @@ -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(), base); + 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.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 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 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 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 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; + } + + } diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/SnapShotGenerationTests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/SnapShotGenerationTests.java index 09a309135..f7ea04b4e 100644 --- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/SnapShotGenerationTests.java +++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/test/SnapShotGenerationTests.java @@ -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 errors = new ArrayList(); @@ -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(); diff --git a/org.hl7.fhir.r5/src/test/resources/snapshot-generation/clean.bat b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/clean.bat new file mode 100644 index 000000000..33832c26d --- /dev/null +++ b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/clean.bat @@ -0,0 +1,2 @@ +del *.bak +del *-actual.* \ 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 c77a868cd..69c33ee40 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 @@ -142,9 +142,10 @@ - + + @@ -219,4 +220,6 @@ + + diff --git a/org.hl7.fhir.r5/src/test/resources/snapshot-generation/samply1-expected.xml b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/samply1-expected.xml new file mode 100644 index 000000000..738f084d7 --- /dev/null +++ b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/samply1-expected.xml @@ -0,0 +1,4428 @@ + + + + + +
+ + + + + + + + + + + + + + + + +
+ Name + + Flags + + Card. + + Type + + Description & Constraints + + + doco + + +
+ . + . + extension + + + + + + Slice: Unordered, Open by value:url +
+
+ + doco Documentation for this format + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/org.hl7.fhir.r5/src/test/resources/snapshot-generation/samply1-input.json b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/samply1-input.json new file mode 100644 index 000000000..150244902 --- /dev/null +++ b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/samply1-input.json @@ -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": "_: 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 + } + ] + } +} diff --git a/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t12-expected.xml b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t12-expected.xml index f6bb3d5c2..bd5f1acde 100644 --- a/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t12-expected.xml +++ b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t12-expected.xml @@ -44,7 +44,7 @@
URL: http://hl7.org/fhir/StructureDefinition/patient-birthTime - + @@ -304,7 +304,7 @@ - + diff --git a/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t12a-expected.xml b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t12a-expected.xml index ddccba664..e69909dea 100644 --- a/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t12a-expected.xml +++ b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t12a-expected.xml @@ -44,7 +44,7 @@
URL: http://hl7.org/fhir/StructureDefinition/patient-birthTime - + @@ -304,7 +304,7 @@
- + diff --git a/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t16-expected.xml b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t16-expected.xml index 549fe3e6e..62abb2c7d 100644 --- a/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t16-expected.xml +++ b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t16-expected.xml @@ -39,7 +39,7 @@ - + @@ -53,7 +53,7 @@ - + @@ -67,7 +67,7 @@ - + @@ -909,7 +909,7 @@ - + @@ -1229,7 +1229,7 @@ - + diff --git a/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t18-expected.xml b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t18-expected.xml index dfb9d3e08..a7abe9b1a 100644 --- a/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t18-expected.xml +++ b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t18-expected.xml @@ -41,7 +41,7 @@ Birth Time - + @@ -325,7 +325,7 @@ - + diff --git a/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t19-expected.xml b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t19-expected.xml index dae653767..8ad49ed08 100644 --- a/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t19-expected.xml +++ b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t19-expected.xml @@ -41,7 +41,7 @@ Birth Time - + @@ -325,7 +325,7 @@ - + diff --git a/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t23-expected.xml b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t23-expected.xml index 7c2e1eb0d..a53bee47c 100644 --- a/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t23-expected.xml +++ b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t23-expected.xml @@ -39,7 +39,7 @@ - + @@ -56,7 +56,7 @@ Slice: Unordered, Open by value:gender - + @@ -70,7 +70,7 @@ - + @@ -78,17 +78,14 @@ . . . - gender - + telecom + + 1.. - - Fixed Value: - male - - + @@ -96,14 +93,17 @@ . . . - telecom - + gender + - 1.. - + + Fixed Value: + male + + @@ -1406,6 +1406,7 @@ + @@ -1931,13 +1932,13 @@ - - - - + + + + \ No newline at end of file diff --git a/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t28-expected.xml b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t28-expected.xml index f9cef84f2..0ef6bdbb9 100644 --- a/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t28-expected.xml +++ b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t28-expected.xml @@ -802,7 +802,7 @@ - + @@ -1005,7 +1005,7 @@ - + diff --git a/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t29-expected.xml b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t29-expected.xml index 684ea55a8..02c3b9292 100644 --- a/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t29-expected.xml +++ b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t29-expected.xml @@ -1077,16 +1077,16 @@ - - + + - - + + diff --git a/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t31-expected.xml b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t31-expected.xml index 62b72b39c..20ad53d3a 100644 --- a/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t31-expected.xml +++ b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t31-expected.xml @@ -39,7 +39,7 @@ - + @@ -56,7 +56,7 @@ Slice: Unordered, Open by value:name - + @@ -70,7 +70,7 @@ - + @@ -88,7 +88,7 @@ Fixed Value: string - + @@ -108,7 +108,7 @@ Max Length: 2 - + @@ -127,7 +127,7 @@
URL: http://hl7.org/fhir/StructureDefinition/translation - + @@ -144,7 +144,7 @@ - + @@ -165,7 +165,7 @@ Max Length: 2 - + @@ -805,7 +805,7 @@
- + diff --git a/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t4a-output.xml b/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t4a-output.xml deleted file mode 100644 index d75bea83e..000000000 --- a/org.hl7.fhir.r5/src/test/resources/snapshot-generation/t4a-output.xml +++ /dev/null @@ -1,1503 +0,0 @@ - - - - - - -
- - - - - - - - - - - - - - - -
- Name - - Flags - - Card. - - Type - - Description & Constraints - - - doco - - -
- . - . - telecom - - - - - -
-
- - doco Documentation for this format - -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
\ No newline at end of file diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/Utilities.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/Utilities.java index 12e29582a..19d4eb678 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/Utilities.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/Utilities.java @@ -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 == '.') {