diff --git a/org.hl7.fhir.convertors/pom.xml b/org.hl7.fhir.convertors/pom.xml index d1d3cd7f8..4a469f5ab 100644 --- a/org.hl7.fhir.convertors/pom.xml +++ b/org.hl7.fhir.convertors/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 5.1.21-SNAPSHOT + 5.1.23-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.dstu2/pom.xml b/org.hl7.fhir.dstu2/pom.xml index 50bf1db0d..2ce62e8d5 100644 --- a/org.hl7.fhir.dstu2/pom.xml +++ b/org.hl7.fhir.dstu2/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 5.1.21-SNAPSHOT + 5.1.23-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.dstu2016may/pom.xml b/org.hl7.fhir.dstu2016may/pom.xml index cb520f546..1add3f7e1 100644 --- a/org.hl7.fhir.dstu2016may/pom.xml +++ b/org.hl7.fhir.dstu2016may/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 5.1.21-SNAPSHOT + 5.1.23-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.dstu3/pom.xml b/org.hl7.fhir.dstu3/pom.xml index da94f2fe6..f94bb0853 100644 --- a/org.hl7.fhir.dstu3/pom.xml +++ b/org.hl7.fhir.dstu3/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 5.1.21-SNAPSHOT + 5.1.23-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.r4/pom.xml b/org.hl7.fhir.r4/pom.xml index dde7ecaa6..cfa48e768 100644 --- a/org.hl7.fhir.r4/pom.xml +++ b/org.hl7.fhir.r4/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 5.1.21-SNAPSHOT + 5.1.23-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.r5/pom.xml b/org.hl7.fhir.r5/pom.xml index 99fc53216..1453819d0 100644 --- a/org.hl7.fhir.r5/pom.xml +++ b/org.hl7.fhir.r5/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 5.1.21-SNAPSHOT + 5.1.23-SNAPSHOT ../pom.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 bc59a1e1f..f73020743 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 @@ -150,6 +150,26 @@ import org.hl7.fhir.utilities.xml.SchematronWriter.Section; */ public class ProfileUtilities extends TranslatingUtilities { + public class ElementDefinitionResolution { + + private StructureDefinition source; + private ElementDefinition element; + + public ElementDefinitionResolution(StructureDefinition source, ElementDefinition element) { + this.source = source; + this.element = element; + } + + public StructureDefinition getSource() { + return source; + } + + public ElementDefinition getElement() { + return element; + } + + } + public class ElementRedirection { private String path; @@ -590,7 +610,7 @@ public class ProfileUtilities extends TranslatingUtilities { baseSnapshot = cloneSnapshot(baseSnapshot, base.getType(), derivedType); } 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, null, new ArrayList(), base); + derived.getDifferential().hasElement() ? derived.getDifferential().getElement().size()-1 : -1, url, webUrl, derived.present(), null, null, false, base.getUrl(), null, false, null, null, new ArrayList(), base); checkGroupConstraints(derived); if (derived.getDerivation() == TypeDerivationRule.SPECIALIZATION) { for (ElementDefinition e : diff.getElement()) { @@ -968,7 +988,7 @@ public class ProfileUtilities extends TranslatingUtilities { * @throws Exception */ 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, String typeSlicingPath, List redirector, StructureDefinition srcSD) throws DefinitionException, FHIRException { + int diffLimit, String url, String webUrl, String profileName, String contextPathSrc, String contextPathDst, boolean trimDifferential, String contextName, String resultPathBase, boolean slicingDone, ElementDefinition slicer, String typeSlicingPath, List redirector, StructureDefinition srcSD) throws DefinitionException, FHIRException { 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())+")"); } @@ -1002,7 +1022,7 @@ public class ProfileUtilities extends TranslatingUtilities { // well, the profile walks into this, so we need to as well // 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, null, redirector, srcSD); + processPaths(indent+" ", result, base, differential, baseCursor+1, diffCursor, baseLimit, diffLimit, url, webUrl, profileName, contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD); baseCursor = indexOfFirstNonChild(base, currentBase, baseCursor+1, baseLimit); } else { if (outcome.getType().size() == 0) { @@ -1032,7 +1052,7 @@ public class ProfileUtilities extends TranslatingUtilities { 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, getWebUrl(dt, webUrl, indent), profileName, cpath, outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, redirector, srcSD); + diffCursor-1, url, getWebUrl(dt, webUrl, indent), profileName, cpath, outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD); } } baseCursor++; @@ -1103,8 +1123,14 @@ public class ProfileUtilities extends TranslatingUtilities { if (res == null) res = outcome; updateFromBase(outcome, currentBase); - if (diffMatches.get(0).hasSliceName()) + if (diffMatches.get(0).hasSliceName()) { outcome.setSliceName(diffMatches.get(0).getSliceName()); + if (!diffMatches.get(0).hasMin() && (diffMatches.size() > 1 || slicer == null || slicer.getSlicing().getRules() != SlicingRules.CLOSED) && !currentBase.hasSliceName()) { + if (!cpath.endsWith("xtension.value[x]")) { // hack work around for problems with snapshots in official releases + outcome.setMin(0); + } + } + } updateFromDefinition(outcome, diffMatches.get(0), profileName, trimDifferential, url, srcSD); removeStatusExtensions(outcome); // if (outcome.getPath().endsWith("[x]") && outcome.getType().size() == 1 && !outcome.getType().get(0).getCode().equals("*") && !diffMatches.get(0).hasSlicing()) // if the base profile allows multiple types, but the profile only allows one, rename it @@ -1148,22 +1174,31 @@ public class ProfileUtilities extends TranslatingUtilities { while (diffCursor <= diffLimit && differential.getElement().size() > diffCursor && pathStartsWith(differential.getElement().get(diffCursor).getPath(), diffMatches.get(0).getPath()+".")) diffCursor++; if (outcome.hasContentReference()) { - ElementDefinition tgt = getElementById(base.getElement(), outcome.getContentReference()); + ElementDefinitionResolution tgt = getElementById(srcSD, base.getElement(), outcome.getContentReference()); if (tgt == null) throw new DefinitionException(context.formatMessage(I18nConstants.UNABLE_TO_RESOLVE_REFERENCE_TO_, outcome.getContentReference())); - replaceFromContentReference(outcome, tgt); - int nbc = base.getElement().indexOf(tgt)+1; - int nbl = nbc; - while (nbl < base.getElement().size() && base.getElement().get(nbl).getPath().startsWith(tgt.getPath()+".")) - nbl++; - processPaths(indent+" ", result, base, differential, nbc, start - 1, nbl-1, diffCursor - 1, url, webUrl, profileName, tgt.getPath(), diffMatches.get(0).getPath(), trimDifferential, contextName, resultPathBase, false, null, redirectorStack(redirector, outcome, cpath), srcSD); + replaceFromContentReference(outcome, tgt.getElement()); + if (tgt.getSource() != srcSD) { + base = tgt.getSource().getSnapshot(); + int nbc = base.getElement().indexOf(tgt.getElement())+1; + int nbl = nbc; + while (nbl < base.getElement().size() && base.getElement().get(nbl).getPath().startsWith(tgt.getElement().getPath()+".")) + nbl++; + processPaths(indent+" ", result, base, differential, nbc, start - 1, nbl-1, diffCursor - 1, url, webUrl, profileName, tgt.getElement().getPath(), diffMatches.get(0).getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirectorStack(redirector, outcome, cpath), tgt.getSource()); + } else { + int nbc = base.getElement().indexOf(tgt.getElement())+1; + int nbl = nbc; + while (nbl < base.getElement().size() && base.getElement().get(nbl).getPath().startsWith(tgt.getElement().getPath()+".")) + nbl++; + processPaths(indent+" ", result, base, differential, nbc, start - 1, nbl-1, diffCursor - 1, url, webUrl, profileName, tgt.getElement().getPath(), diffMatches.get(0).getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirectorStack(redirector, outcome, cpath), srcSD); + } } else { StructureDefinition dt = outcome.getType().size() == 1 ? getProfileForDataType(outcome.getType().get(0)) : getProfileForDataType("Element"); if (dt == null) throw new DefinitionException(context.formatMessage(I18nConstants._HAS_CHILDREN__FOR_TYPE__IN_PROFILE__BUT_CANT_FIND_TYPE, diffMatches.get(0).getPath(), differential.getElement().get(diffCursor).getPath(), typeCode(outcome.getType()), profileName)); contextName = dt.getUrl(); 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, getWebUrl(dt, webUrl, indent), profileName+pathTail(diffMatches, 0), diffMatches.get(0).getPath(), outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, new ArrayList(), srcSD); + diffCursor - 1, url, getWebUrl(dt, webUrl, indent), profileName+pathTail(diffMatches, 0), diffMatches.get(0).getPath(), outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, null, new ArrayList(), srcSD); } } } @@ -1226,30 +1261,30 @@ public class ProfileUtilities extends TranslatingUtilities { } // check the slice names too while we're at it... for (TypeSlice ts : typeList) { - 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)) { - if (autoFixSliceNames) { + if (ts.type != null) { + String tn = rootName(cpath)+Utilities.capitalize(ts.type); + if (!ts.defn.hasSliceName()) { ts.defn.setSliceName(tn); - } else { - throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_NAME_MUST_BE__BUT_IS_, (!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath), tn, ts.defn.getSliceName())); + } else if (!ts.defn.getSliceName().equals(tn)) { + if (autoFixSliceNames) { + ts.defn.setSliceName(tn); + } else { + throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_NAME_MUST_BE__BUT_IS_, (!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath), tn, ts.defn.getSliceName())); + } + } if (!ts.defn.hasType()) { + ts.defn.addType().setCode(ts.type); + } else if (ts.defn.getType().size() > 1) { + throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_FOR_TYPE__HAS_MORE_THAN_ONE_TYPE_, (!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath), tn, ts.defn.typeSummary())); + } else if (!ts.defn.getType().get(0).getCode().equals(ts.type)) { + throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_FOR_TYPE__HAS_WRONG_TYPE_, (!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath), tn, ts.defn.typeSummary())); } - } if (!ts.defn.hasType()) { - ts.defn.addType().setCode(ts.type); - } else if (ts.defn.getType().size() > 1) { - throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_FOR_TYPE__HAS_MORE_THAN_ONE_TYPE_, (!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath), tn, ts.defn.typeSummary())); - } else if (!ts.defn.getType().get(0).getCode().equals(ts.type)) { - throw new FHIRException(context.formatMessage(I18nConstants.ERROR_AT_PATH__SLICE_FOR_TYPE__HAS_WRONG_TYPE_, (!Utilities.noString(contextPathSrc) ? contextPathSrc : cpath), tn, ts.defn.typeSummary())); } } - } // ok passed the checks. // copy the root diff, and then process any children it has ElementDefinition e = processPaths(indent+" ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName+pathTail(diffMatches, 0), contextPathSrc, contextPathDst, - trimDifferential, contextName, resultPathBase, true, null, redirector, srcSD); + trimDifferential, contextName, resultPathBase, true, null, null, redirector, srcSD); if (e==null) throw new FHIRException(context.formatMessage(I18nConstants.DID_NOT_FIND_TYPE_ROOT_, diffMatches.get(0).getPath())); // now set up slicing on the e (cause it was wiped by what we called. @@ -1257,6 +1292,7 @@ public class ProfileUtilities extends TranslatingUtilities { e.getSlicing().addDiscriminator().setType(DiscriminatorType.TYPE).setPath("$this"); e.getSlicing().setRules(SlicingRules.CLOSED); // type slicing is always closed; the differential might call it open, but that just means it's not constraining the slices it doesn't mention e.getSlicing().setOrdered(false); + start++; String fixedType = null; @@ -1274,7 +1310,7 @@ public class ProfileUtilities extends TranslatingUtilities { } ndc = differential.getElement().indexOf(diffMatches.get(i)); ndl = findEndOfElement(differential, ndc); - processPaths(indent+" ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName+pathTail(diffMatches, i), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, null, redirector, srcSD); + processPaths(indent+" ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName+pathTail(diffMatches, i), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, e, null, redirector, srcSD); } if (elementToRemove != null) { differential.getElement().remove(elementToRemove); @@ -1288,7 +1324,32 @@ public class ProfileUtilities extends TranslatingUtilities { } } } - + if (!"0".equals(e.getMax())) { + // check that there's a slice for each allowed types + Set allowedTypes = getListOfTypes(e); + for (TypeSlice t : typeList) { + if (t.type != null) { + allowedTypes.remove(t.type); + } else if (t.getDefn().hasSliceName() && t.getDefn().getType().size() == 1) { + allowedTypes.remove(t.getDefn().getType().get(0).getCode()); + } + } + if (!allowedTypes.isEmpty()) { + if (cpath.contains("xtension.value")) { + for (Iterator iter = e.getType().iterator(); iter.hasNext(); ) { + TypeRefComponent tr = iter.next(); + if (allowedTypes.contains(tr.getCode())) { + iter.remove(); + } + } +// System.out.println("!!: Extension Error at "+cpath+": Allowed Types not sliced = "+allowedTypes+". !Extension!!"); +// throw new Error("Extension Error at "+cpath+": Allowed Types not sliced = "+allowedTypes+". !Extension!!"); + + } else { + e.getSlicing().setRules(SlicingRules.OPEN); + } + } + } // ok, done with that - next in the base list baseCursor = nbl+1; diffCursor = ndl+1; @@ -1306,14 +1367,16 @@ public class ProfileUtilities extends TranslatingUtilities { int start = 0; int nbl = findEndOfElement(base, baseCursor); // if (diffMatches.size() > 1 && diffMatches.get(0).hasSlicing() && differential.getElement().indexOf(diffMatches.get(1)) > differential.getElement().indexOf(diffMatches.get(0))+1) { + ElementDefinition slicerElement; if (diffMatches.size() > 1 && diffMatches.get(0).hasSlicing() && (nbl > baseCursor || differential.getElement().indexOf(diffMatches.get(1)) > differential.getElement().indexOf(diffMatches.get(0))+1)) { // there's a default set before the slices int ndc = differential.getElement().indexOf(diffMatches.get(0)); int ndl = findEndOfElement(differential, ndc); ElementDefinition e = processPaths(indent+" ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName+pathTail(diffMatches, 0), contextPathSrc, contextPathDst, - trimDifferential, contextName, resultPathBase, true, null, redirector, srcSD); + trimDifferential, contextName, resultPathBase, true, null, null, redirector, srcSD); if (e==null) throw new FHIRException(context.formatMessage(I18nConstants.DID_NOT_FIND_SINGLE_SLICE_, diffMatches.get(0).getPath())); e.setSlicing(diffMatches.get(0).getSlicing()); + slicerElement = e; start++; } else { // we're just going to accept the differential slicing at face value @@ -1328,7 +1391,8 @@ public class ProfileUtilities extends TranslatingUtilities { if (!outcome.getPath().startsWith(resultPathBase)) throw new DefinitionException(context.formatMessage(I18nConstants.ADDING_WRONG_PATH)); result.getElement().add(outcome); - + slicerElement = outcome; + // differential - if the first one in the list has a name, we'll process it. Else we'll treat it as the base definition of the slice. if (!diffMatches.get(0).hasSliceName()) { updateFromDefinition(outcome, diffMatches.get(0), profileName, trimDifferential, url, srcSD); @@ -1348,7 +1412,7 @@ public class ProfileUtilities extends TranslatingUtilities { diffCursor++; 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, url, getWebUrl(dt, webUrl, indent), profileName, cpath, outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, redirector, srcSD); + diffCursor, url, getWebUrl(dt, webUrl, indent), profileName, cpath, outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD); } } start++; @@ -1370,7 +1434,7 @@ public class ProfileUtilities extends TranslatingUtilities { continue; }*/ // now we process the base scope repeatedly for each instance of the item in the differential list - processPaths(indent+" ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName+pathTail(diffMatches, i), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, null, redirector, srcSD); + processPaths(indent+" ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName+pathTail(diffMatches, i), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, slicerElement, null, redirector, srcSD); } // ok, done with that - next in the base list baseCursor = nbl+1; @@ -1403,7 +1467,7 @@ public class ProfileUtilities extends TranslatingUtilities { // the profile walks into this, so we need to as well // 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, null, redirector, srcSD); + processPaths(indent+" ", result, base, differential, baseCursor+1, diffCursor, baseLimit, diffLimit, url, webUrl, profileName, contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD); baseCursor = indexOfFirstNonChild(base, currentBase, baseCursor, baseLimit); } else { StructureDefinition dt = getTypeForElement(differential, diffCursor, profileName, diffMatches, outcome); @@ -1412,7 +1476,7 @@ public class ProfileUtilities extends TranslatingUtilities { 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, getWebUrl(dt, webUrl, indent), profileName, cpath, outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, redirector, srcSD); + diffCursor-1, url, getWebUrl(dt, webUrl, indent), profileName, cpath, outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD); } baseCursor++; } else { @@ -1505,7 +1569,7 @@ public class ProfileUtilities extends TranslatingUtilities { // ok passed the checks. // copy the root diff, and then process any children it has ElementDefinition e = processPaths(indent+" ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName+pathTail(diffMatches, 0), contextPathSrc, contextPathDst, - trimDifferential, contextName, resultPathBase, true, cpath, redirector, srcSD); + trimDifferential, contextName, resultPathBase, true, null, cpath, redirector, srcSD); if (e==null) throw new FHIRException(context.formatMessage(I18nConstants.DID_NOT_FIND_TYPE_ROOT_, diffMatches.get(0).getPath())); // now set up slicing on the e (cause it was wiped by what we called. @@ -1538,7 +1602,7 @@ public class ProfileUtilities extends TranslatingUtilities { sEnd = bs.end; bs.handled = true; } - processPaths(indent+" ", result, base, differential, sStart, ndc, sEnd, ndl, url, webUrl, profileName+pathTail(diffMatches, i), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, cpath, redirector, srcSD); + processPaths(indent+" ", result, base, differential, sStart, ndc, sEnd, ndl, url, webUrl, profileName+pathTail(diffMatches, i), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, e, cpath, redirector, srcSD); } if (elementToRemove != null) { differential.getElement().remove(elementToRemove); @@ -1557,7 +1621,7 @@ public class ProfileUtilities extends TranslatingUtilities { // ok we gimme up a fake differential that says nothing, and run that against the slice. StructureDefinitionDifferentialComponent fakeDiff = new StructureDefinitionDifferentialComponent(); fakeDiff.getElementFirstRep().setPath(bs.defn.getPath()); - processPaths(indent+" ", result, base, fakeDiff, bs.start, 0, bs.end, 0, url, webUrl, profileName+tail(bs.defn.getPath()), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, cpath, redirector, srcSD); + processPaths(indent+" ", result, base, fakeDiff, bs.start, 0, bs.end, 0, url, webUrl, profileName+tail(bs.defn.getPath()), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, e, cpath, redirector, srcSD); } } @@ -1614,10 +1678,10 @@ public class ProfileUtilities extends TranslatingUtilities { while (differential.getElement().size() > diffCursor && pathStartsWith(differential.getElement().get(diffCursor).getPath(), cpath+".")) diffCursor++; processPaths(indent+" ", result, dt.getSnapshot(), differential, 1, ndc, dt.getSnapshot().getElement().size()-1, ndl, - url, getWebUrl(dt, webUrl, indent), profileName, cpath, outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, redirector, srcSD); + url, getWebUrl(dt, webUrl, indent), profileName, cpath, outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD); } else { processPaths(indent+" ", result, base, differential, baseCursor+1, ndc, nbl, ndl, - url, webUrl, profileName+pathTail(diffMatches, 0), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, false, null, null, srcSD); + url, webUrl, profileName+pathTail(diffMatches, 0), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, false, null, null, null, srcSD); } // throw new Error("Not done yet"); // } else if (currentBase.getType().get(0).getCode().equals("BackboneElement") && diffMatches.size() > 0 && diffMatches.get(0).hasSliceName()) { @@ -1648,7 +1712,7 @@ public class ProfileUtilities extends TranslatingUtilities { int ndc = differential.getElement().indexOf(diffMatches.get(diffpos)); int ndl = findEndOfElement(differential, ndc); // now we process the base scope repeatedly for each instance of the item in the differential list - processPaths(indent+" ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName+pathTail(diffMatches, diffpos), contextPathSrc, contextPathDst, closed, contextName, resultPathBase, true, null, redirector, srcSD); + processPaths(indent+" ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName+pathTail(diffMatches, diffpos), contextPathSrc, contextPathDst, closed, contextName, resultPathBase, true, null, null, redirector, srcSD); // ok, done with that - now set the cursors for if this is the end baseCursor = nbl; diffCursor = ndl+1; @@ -1693,7 +1757,7 @@ public class ProfileUtilities extends TranslatingUtilities { outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); updateFromBase(outcome, currentBase); outcome.setSlicing(null); - outcome.setMin(0); // were in a slice, so it's only a mandatory if it's explicitly marked so + outcome.setMin(0); // we're in a slice, so it's only a mandatory if it's explicitly marked so if (!outcome.getPath().startsWith(resultPathBase)) throw new DefinitionException(context.formatMessage(I18nConstants.ADDING_WRONG_PATH)); result.getElement().add(outcome); @@ -1719,7 +1783,7 @@ public class ProfileUtilities extends TranslatingUtilities { while (differential.getElement().size() > diffCursor && pathStartsWith(differential.getElement().get(diffCursor).getPath(), diffMatches.get(0).getPath()+".")) diffCursor++; processPaths(indent+" ", result, base, differential, baseStart, start-1, baseMax-1, - diffCursor - 1, url, webUrl, profileName+pathTail(diffMatches, 0), base.getElement().get(0).getPath(), base.getElement().get(0).getPath(), trimDifferential, contextName, resultPathBase, false, null, redirector, srcSD); + diffCursor - 1, url, webUrl, profileName+pathTail(diffMatches, 0), base.getElement().get(0).getPath(), base.getElement().get(0).getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD); } else { StructureDefinition dt = getProfileForDataType(outcome.getType().get(0)); @@ -1733,7 +1797,7 @@ public class ProfileUtilities extends TranslatingUtilities { while (differential.getElement().size() > diffCursor && pathStartsWith(differential.getElement().get(diffCursor).getPath(), diffMatches.get(0).getPath()+".")) diffCursor++; processPaths(indent+" ", result, dt.getSnapshot(), differential, 1 /* starting again on the data type, but skip the root */, start-1, dt.getSnapshot().getElement().size()-1, - diffCursor - 1, url, getWebUrl(dt, webUrl, indent), profileName+pathTail(diffMatches, 0), diffMatches.get(0).getPath(), outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, redirector, srcSD); + diffCursor - 1, url, getWebUrl(dt, webUrl, indent), profileName+pathTail(diffMatches, 0), diffMatches.get(0).getPath(), outcome.getPath(), trimDifferential, contextName, resultPathBase, false, null, null, redirector, srcSD); } } } @@ -1756,6 +1820,14 @@ public class ProfileUtilities extends TranslatingUtilities { return res; } + private Set getListOfTypes(ElementDefinition e) { + Set result = new HashSet<>(); + for (TypeRefComponent t : e.getType()) { + result.add(t.getCode()); + } + return result; + } + public StructureDefinition getTypeForElement(StructureDefinitionDifferentialComponent differential, int diffCursor, String profileName, List diffMatches, ElementDefinition outcome) { if (outcome.getType().size() == 0) { @@ -1961,7 +2033,7 @@ public class ProfileUtilities extends TranslatingUtilities { private boolean diffsConstrainTypes(List diffMatches, String cPath, List typeList) { // if (diffMatches.size() < 2) -// return false; + // return false; String p = diffMatches.get(0).getPath(); if (!p.endsWith("[x]") && !cPath.endsWith("[x]")) return false; @@ -1978,11 +2050,17 @@ public class ProfileUtilities extends TranslatingUtilities { if (ed.hasSliceName() && ed.getType().size() == 1) { typeList.add(new TypeSlice(ed, ed.getTypeFirstRep().getWorkingCode())); } else if (ed.hasSliceName() && ed.getType().size() == 0) { - String tn = ed.getSliceName().substring(rn.length()); - if (isDataType(tn)) { - typeList.add(new TypeSlice(ed, tn)); - } else if (isPrimitive(Utilities.uncapitalize(tn))) { - typeList.add(new TypeSlice(ed, Utilities.uncapitalize(tn))); + if (isDataType(s)) { + typeList.add(new TypeSlice(ed, s)); + } else if (isPrimitive(Utilities.uncapitalize(s))) { + typeList.add(new TypeSlice(ed, Utilities.uncapitalize(s))); + } else { + String tn = ed.getSliceName().substring(n.length()); + if (isDataType(tn)) { + typeList.add(new TypeSlice(ed, tn)); + } else if (isPrimitive(Utilities.uncapitalize(tn))) { + typeList.add(new TypeSlice(ed, Utilities.uncapitalize(tn))); + } } } else if (!ed.hasSliceName() && !s.equals("[x]")) { if (isDataType(s)) @@ -1992,9 +2070,9 @@ public class ProfileUtilities extends TranslatingUtilities { else if (isPrimitive(Utilities.uncapitalize(s))) typeList.add(new TypeSlice(ed, Utilities.uncapitalize(s))); } else if (!ed.hasSliceName() && s.equals("[x]")) - typeList.add(new TypeSlice(ed, null)); - } - } + typeList.add(new TypeSlice(ed, null)); + } + } return true; } @@ -3143,7 +3221,7 @@ public class ProfileUtilities extends TranslatingUtilities { r1.getCells().add(gen.new Cell(null, defFile == null ? "" : defFile+"-definitions.html#extension."+ed.getName(), ((UriType) ued.getFixed()).getValue(), null, null)); r1.getCells().add(gen.new Cell()); r1.getCells().add(gen.new Cell(null, null, describeCardinality(c, null, new UnusedTracker()), null, null)); - genTypes(gen, r1, ved, defFile, ed, corePath, imagePath, false); + genTypes(gen, r1, ved, defFile, ed, corePath, imagePath, false, false); Cell cell = gen.new Cell(); cell.addMarkdown(c.getDefinition()); r1.getCells().add(cell); @@ -3156,7 +3234,7 @@ public class ProfileUtilities extends TranslatingUtilities { ved = ted; } - genTypes(gen, r, ved, defFile, ed, corePath, imagePath, false); + genTypes(gen, r, ved, defFile, ed, corePath, imagePath, false, false); r.setIcon("icon_"+m+"extension_simple.png", HierarchicalTableGenerator.TEXT_ICON_EXTENSION_SIMPLE); } @@ -3215,7 +3293,7 @@ public class ProfileUtilities extends TranslatingUtilities { private static final int AGG_GR = 2; private static final boolean TABLE_FORMAT_FOR_FIXED_VALUES = false; - private Cell genTypes(HierarchicalTableGenerator gen, Row r, ElementDefinition e, String profileBaseFileName, StructureDefinition profile, String corePath, String imagePath, boolean root) { + private Cell genTypes(HierarchicalTableGenerator gen, Row r, ElementDefinition e, String profileBaseFileName, StructureDefinition profile, String corePath, String imagePath, boolean root, boolean mustSupportMode) { Cell c = gen.new Cell(); r.getCells().add(c); if (e.hasContentReference()) { @@ -3266,88 +3344,94 @@ public class ProfileUtilities extends TranslatingUtilities { TypeRefComponent tl = null; for (TypeRefComponent t : types) { - if (first) { - first = false; - } else { - c.addPiece(checkForNoChange(tl, gen.new Piece(null,", ", null))); - } - tl = t; - if (t.hasTarget()) { - c.getPieces().add(gen.new Piece(corePath+"references.html", t.getWorkingCode(), null)); - if (isMustSupportDirect(t) && e.getMustSupport()) { - c.addPiece(gen.new Piece(null, " ", null)); - c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false); + if (!mustSupportMode || allTypesMustSupport(e) || isMustSupport(t)) { + if (first) { + first = false; + } else { + c.addPiece(checkForNoChange(tl, gen.new Piece(null,", ", null))); } - c.getPieces().add(gen.new Piece(null, "(", null)); - boolean tfirst = true; - for (CanonicalType u : t.getTargetProfile()) { - if (tfirst) - tfirst = false; - else - c.addPiece(gen.new Piece(null, " | ", null)); - genTargetLink(gen, profileBaseFileName, corePath, c, t, u.getValue()); - if (isMustSupport(u) && e.getMustSupport()) { + tl = t; + if (t.hasTarget()) { + c.getPieces().add(gen.new Piece(corePath+"references.html", t.getWorkingCode(), null)); + if (!mustSupportMode && isMustSupportDirect(t) && e.getMustSupport()) { c.addPiece(gen.new Piece(null, " ", null)); - c.addStyledText(translate("sd.table", "This target must be supported"), "S", "white", "red", null, false); + c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false); } - } - c.getPieces().add(gen.new Piece(null, ")", null)); - if (t.getAggregation().size() > 0) { - c.getPieces().add(gen.new Piece(corePath+"valueset-resource-aggregation-mode.html", " {", null)); - boolean firstA = true; - for (Enumeration a : t.getAggregation()) { - if (firstA = true) - firstA = false; - else - c.getPieces().add(gen.new Piece(corePath+"valueset-resource-aggregation-mode.html", ", ", null)); - c.getPieces().add(gen.new Piece(corePath+"valueset-resource-aggregation-mode.html", codeForAggregation(a.getValue()), hintForAggregation(a.getValue()))); - } - c.getPieces().add(gen.new Piece(corePath+"valueset-resource-aggregation-mode.html", "}", null)); - } - } else if (t.hasProfile() && (!t.getWorkingCode().equals("Extension") || isProfiledType(t.getProfile()))) { // a profiled type - String ref; - boolean pfirst = true; - for (CanonicalType p : t.getProfile()) { - if (pfirst) { - pfirst = false; - } else { - c.addPiece(checkForNoChange(tl, gen.new Piece(null,", ", null))); - } - - ref = pkp.getLinkForProfile(profile, p.getValue()); - if (ref != null) { - String[] parts = ref.split("\\|"); - if (parts[0].startsWith("http:") || parts[0].startsWith("https:")) { - // c.addPiece(checkForNoChange(t, gen.new Piece(parts[0], "<" + parts[1] + ">", t.getCode()))); Lloyd - c.addPiece(checkForNoChange(t, gen.new Piece(parts[0], parts[1], t.getWorkingCode()))); - } else { - // c.addPiece(checkForNoChange(t, gen.new Piece((t.getProfile().startsWith(corePath)? corePath: "")+parts[0], "<" + parts[1] + ">", t.getCode()))); - c.addPiece(checkForNoChange(t, gen.new Piece((p.getValue().startsWith(corePath+"StructureDefinition")? corePath: "")+parts[0], parts[1], t.getWorkingCode()))); + c.getPieces().add(gen.new Piece(null, "(", null)); + boolean tfirst = true; + for (CanonicalType u : t.getTargetProfile()) { + if (!mustSupportMode || allProfilesMustSupport(t.getTargetProfile()) || isMustSupport(u)) { + if (tfirst) + tfirst = false; + else + c.addPiece(gen.new Piece(null, " | ", null)); + genTargetLink(gen, profileBaseFileName, corePath, c, t, u.getValue()); + if (!mustSupportMode && isMustSupport(u) && e.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText(translate("sd.table", "This target must be supported"), "S", "white", "red", null, false); + } } - } else - c.addPiece(checkForNoChange(t, gen.new Piece((p.getValue().startsWith(corePath)? corePath: "")+ref, t.getWorkingCode(), null))); - if (isMustSupport(p) && e.getMustSupport()) { - c.addPiece(gen.new Piece(null, " ", null)); - c.addStyledText(translate("sd.table", "This profile must be supported"), "S", "white", "red", null, false); } - } - } else { - String tc = t.getWorkingCode(); - if (Utilities.isAbsoluteUrl(tc)) { - StructureDefinition sd = context.fetchTypeDefinition(tc); - if (sd == null) { + c.getPieces().add(gen.new Piece(null, ")", null)); + if (t.getAggregation().size() > 0) { + c.getPieces().add(gen.new Piece(corePath+"valueset-resource-aggregation-mode.html", " {", null)); + boolean firstA = true; + for (Enumeration a : t.getAggregation()) { + if (firstA = true) + firstA = false; + else + c.getPieces().add(gen.new Piece(corePath+"valueset-resource-aggregation-mode.html", ", ", null)); + c.getPieces().add(gen.new Piece(corePath+"valueset-resource-aggregation-mode.html", codeForAggregation(a.getValue()), hintForAggregation(a.getValue()))); + } + c.getPieces().add(gen.new Piece(corePath+"valueset-resource-aggregation-mode.html", "}", null)); + } + } else if (t.hasProfile() && (!t.getWorkingCode().equals("Extension") || isProfiledType(t.getProfile()))) { // a profiled type + String ref; + boolean pfirst = true; + for (CanonicalType p : t.getProfile()) { + if (!mustSupportMode || allProfilesMustSupport(t.getProfile()) || isMustSupport(p)) { + if (pfirst) { + pfirst = false; + } else { + c.addPiece(checkForNoChange(tl, gen.new Piece(null,", ", null))); + } + + ref = pkp.getLinkForProfile(profile, p.getValue()); + if (ref != null) { + String[] parts = ref.split("\\|"); + if (parts[0].startsWith("http:") || parts[0].startsWith("https:")) { + // c.addPiece(checkForNoChange(t, gen.new Piece(parts[0], "<" + parts[1] + ">", t.getCode()))); Lloyd + c.addPiece(checkForNoChange(t, gen.new Piece(parts[0], parts[1], t.getWorkingCode()))); + } else { + // c.addPiece(checkForNoChange(t, gen.new Piece((t.getProfile().startsWith(corePath)? corePath: "")+parts[0], "<" + parts[1] + ">", t.getCode()))); + c.addPiece(checkForNoChange(t, gen.new Piece((p.getValue().startsWith(corePath+"StructureDefinition")? corePath: "")+parts[0], parts[1], t.getWorkingCode()))); + } + } else + c.addPiece(checkForNoChange(t, gen.new Piece((p.getValue().startsWith(corePath)? corePath: "")+ref, t.getWorkingCode(), null))); + if (!mustSupportMode && isMustSupport(p) && e.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText(translate("sd.table", "This profile must be supported"), "S", "white", "red", null, false); + } + } + } + } else { + String tc = t.getWorkingCode(); + if (Utilities.isAbsoluteUrl(tc)) { + StructureDefinition sd = context.fetchTypeDefinition(tc); + if (sd == null) { + c.addPiece(checkForNoChange(t, gen.new Piece(pkp.getLinkFor(corePath, tc), tc, null))); + } else { + c.addPiece(checkForNoChange(t, gen.new Piece(pkp.getLinkFor(corePath, tc), sd.getType(), null))); + } + } else if (pkp != null && pkp.hasLinkFor(tc)) { c.addPiece(checkForNoChange(t, gen.new Piece(pkp.getLinkFor(corePath, tc), tc, null))); } else { - c.addPiece(checkForNoChange(t, gen.new Piece(pkp.getLinkFor(corePath, tc), sd.getType(), null))); + c.addPiece(checkForNoChange(t, gen.new Piece(null, tc, null))); + } + if (!mustSupportMode && isMustSupportDirect(t) && e.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false); } - } else if (pkp != null && pkp.hasLinkFor(tc)) { - c.addPiece(checkForNoChange(t, gen.new Piece(pkp.getLinkFor(corePath, tc), tc, null))); - } else { - c.addPiece(checkForNoChange(t, gen.new Piece(null, tc, null))); - } - if (isMustSupportDirect(t) && e.getMustSupport()) { - c.addPiece(gen.new Piece(null, " ", null)); - c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false); } } } @@ -3457,10 +3541,21 @@ public class ProfileUtilities extends TranslatingUtilities { // return null; } - private ElementDefinition getElementById(List elements, String contentReference) { + private ElementDefinitionResolution getElementById(StructureDefinition source, List elements, String contentReference) { + if (!contentReference.startsWith("#") && contentReference.contains("#")) { + String url = contentReference.substring(0, contentReference.indexOf("#")); + contentReference = contentReference.substring(contentReference.indexOf("#")); + if (!url.equals(source.getUrl())){ + source = context.fetchResource(StructureDefinition.class, url); + if (source == null) { + return null; + } + elements = source.getSnapshot().getElement(); + } + } for (ElementDefinition ed : elements) if (ed.hasId() && ("#"+ed.getId()).equals(contentReference)) - return ed; + return new ElementDefinitionResolution(source, ed); return null; } @@ -3549,6 +3644,25 @@ public class ProfileUtilities extends TranslatingUtilities { return piece; } + private String checkForNoChange(Element source) { + if (source.hasUserData(DERIVATION_EQUALS)) { + return "opacity: 0.5"; + } else { + return null; + } + } + + + private Piece applyAsUnchanged(Piece piece) { + piece.addStyle("opacity: 0.5"); + return piece; + } + + private String applyAsUnchanged() { + return "opacity: 0.5"; + } + + private Piece checkForNoChange(Element src1, Element src2, Piece piece) { if (src1.hasUserData(DERIVATION_EQUALS) && src2.hasUserData(DERIVATION_EQUALS)) { piece.addStyle("opacity: 0.5"); @@ -3824,7 +3938,7 @@ public class ProfileUtilities extends TranslatingUtilities { // genElement(defPath, gen, row.getSubRows(), child, all, profiles, showMissing, profileBaseFileName, true, false, corePath, imagePath, false, logicalModel, isConstraintMode, allInvariants); } if (typesRow != null) { - makeChoiceRows(typesRow.getSubRows(), element, gen, corePath, profileBaseFileName); + makeChoiceRows(typesRow.getSubRows(), element, gen, corePath, profileBaseFileName, mustSupport); } } return slicingRow; @@ -3909,7 +4023,7 @@ public class ProfileUtilities extends TranslatingUtilities { res.add(genCardinality(gen, element, row, hasDef, used, extDefn.getElement())); ElementDefinition valueDefn = extDefn.getExtensionValueDefinition(); if (valueDefn != null && !"0".equals(valueDefn.getMax())) - res.add(genTypes(gen, row, valueDefn, profileBaseFileName, profile, corePath, imagePath, root)); + res.add(genTypes(gen, row, valueDefn, profileBaseFileName, profile, corePath, imagePath, root, mustSupport)); else // if it's complex, we just call it nothing // genTypes(gen, row, extDefn.getSnapshot().getElement().get(0), profileBaseFileName, profile); res.add(addCell(row, gen.new Cell(null, null, "("+translate("sd.table", "Complex")+")", null, null))); @@ -3920,7 +4034,7 @@ public class ProfileUtilities extends TranslatingUtilities { if ("0".equals(element.getMax())) res.add(addCell(row, gen.new Cell())); else - res.add(genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root)); + res.add(genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root, mustSupport)); res.add(generateDescription(gen, row, element, (ElementDefinition) element.getUserData(DERIVATION_POINTER), used.used, null, null, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot, mustSupport)); } } else { @@ -3928,7 +4042,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (element.hasSlicing()) res.add(addCell(row, gen.new Cell(null, corePath+"profiling.html#slicing", "(Slice Definition)", null, null))); else if (hasDef && !"0".equals(element.getMax()) && typesRow == null) - res.add(genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root)); + res.add(genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root, mustSupport)); else res.add(addCell(row, gen.new Cell())); res.add(generateDescription(gen, row, element, (ElementDefinition) element.getUserData(DERIVATION_POINTER), used.used, null, null, profile, corePath, imagePath, root, logicalModel, allInvariants, snapshot, mustSupport)); @@ -3990,96 +4104,101 @@ public class ProfileUtilities extends TranslatingUtilities { return key.startsWith("ele-") || key.startsWith("res-") || key.startsWith("ext-") || key.startsWith("dom-") || key.startsWith("dr-"); } - private void makeChoiceRows(List subRows, ElementDefinition element, HierarchicalTableGenerator gen, String corePath, String profileBaseFileName) { + private void makeChoiceRows(List subRows, ElementDefinition element, HierarchicalTableGenerator gen, String corePath, String profileBaseFileName, boolean mustSupportMode) { // create a child for each choice for (TypeRefComponent tr : element.getType()) { - Row choicerow = gen.new Row(); - String t = tr.getWorkingCode(); - if (isReference(t)) { - choicerow.getCells().add(gen.new Cell(null, null, tail(element.getPath()).replace("[x]", Utilities.capitalize(t)), null, null)); - choicerow.getCells().add(gen.new Cell()); - choicerow.getCells().add(gen.new Cell(null, null, "", null, null)); - choicerow.setIcon("icon_reference.png", HierarchicalTableGenerator.TEXT_ICON_REFERENCE); - Cell c = gen.new Cell(); - choicerow.getCells().add(c); - if (ADD_REFERENCE_TO_TABLE) { - if (tr.getWorkingCode().equals("canonical")) - c.getPieces().add(gen.new Piece(corePath+"datatypes.html#canonical", "canonical", null)); - else - c.getPieces().add(gen.new Piece(corePath+"references.html#Reference", "Reference", null)); - if (isMustSupportDirect(tr) && element.getMustSupport()) { - c.addPiece(gen.new Piece(null, " ", null)); - c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false); - } - c.getPieces().add(gen.new Piece(null, "(", null)); - } - boolean first = true; - for (CanonicalType rt : tr.getTargetProfile()) { - if (!first) - c.getPieces().add(gen.new Piece(null, " | ", null)); - genTargetLink(gen, profileBaseFileName, corePath, c, tr, rt.getValue()); - if (isMustSupport(rt) && element.getMustSupport()) { - c.addPiece(gen.new Piece(null, " ", null)); - c.addStyledText(translate("sd.table", "This target must be supported"), "S", "white", "red", null, false); - } - first = false; - } - if (first) - c.getPieces().add(gen.new Piece(null, "Any", null)); - - if (ADD_REFERENCE_TO_TABLE) - c.getPieces().add(gen.new Piece(null, ")", null)); - - } else { - StructureDefinition sd = context.fetchTypeDefinition(t); - if (sd == null) { - System.out.println("Unable to find "+t); - sd = context.fetchTypeDefinition(t); - } else if (sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE) { - choicerow.getCells().add(gen.new Cell(null, null, tail(element.getPath()).replace("[x]", Utilities.capitalize(t)), sd.getDescription(), null)); + if (!mustSupportMode || allTypesMustSupport(element) || isMustSupport(tr)) { + Row choicerow = gen.new Row(); + String t = tr.getWorkingCode(); + if (isReference(t)) { + choicerow.getCells().add(gen.new Cell(null, null, tail(element.getPath()).replace("[x]", Utilities.capitalize(t)), null, null)); choicerow.getCells().add(gen.new Cell()); choicerow.getCells().add(gen.new Cell(null, null, "", null, null)); - choicerow.setIcon("icon_primitive.png", HierarchicalTableGenerator.TEXT_ICON_PRIMITIVE); - Cell c = gen.new Cell(null, corePath+"datatypes.html#"+t, sd.getType(), null, null); + choicerow.setIcon("icon_reference.png", HierarchicalTableGenerator.TEXT_ICON_REFERENCE); + Cell c = gen.new Cell(); choicerow.getCells().add(c); - if (isMustSupport(tr) && element.getMustSupport()) { - c.addPiece(gen.new Piece(null, " ", null)); - c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false); - } - } else { - choicerow.getCells().add(gen.new Cell(null, null, tail(element.getPath()).replace("[x]", Utilities.capitalize(t)), sd.getDescription(), null)); - choicerow.getCells().add(gen.new Cell()); - choicerow.getCells().add(gen.new Cell(null, null, "", null, null)); - choicerow.setIcon("icon_datatype.gif", HierarchicalTableGenerator.TEXT_ICON_DATATYPE); - Cell c = gen.new Cell(null, pkp.getLinkFor(corePath, t), sd.getType(), null, null); - choicerow.getCells().add(c); - if (isMustSupport(tr) && element.getMustSupport()) { - c.addPiece(gen.new Piece(null, " ", null)); - c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false); - } - } - if (tr.hasProfile()) { - Cell typeCell = choicerow.getCells().get(3); - typeCell.addPiece(gen.new Piece(null, "(", null)); - boolean first = true; - for (CanonicalType pt : tr.getProfile()) { - if (first) first = false; else typeCell.addPiece(gen.new Piece(null, " | ", null)); - StructureDefinition psd = context.fetchResource(StructureDefinition.class, pt.getValue()); - if (psd == null) - typeCell.addPiece(gen.new Piece(null, "?gen-e2?", null)); + if (ADD_REFERENCE_TO_TABLE) { + if (tr.getWorkingCode().equals("canonical")) + c.getPieces().add(gen.new Piece(corePath+"datatypes.html#canonical", "canonical", null)); else - typeCell.addPiece(gen.new Piece(psd.getUserString("path"), psd.getName(), psd.present())); - if (isMustSupport(pt) && element.getMustSupport()) { - typeCell.addPiece(gen.new Piece(null, " ", null)); - typeCell.addStyledText(translate("sd.table", "This profile must be supported"), "S", "white", "red", null, false); + c.getPieces().add(gen.new Piece(corePath+"references.html#Reference", "Reference", null)); + if (!mustSupportMode && isMustSupportDirect(tr) && element.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false); } - + c.getPieces().add(gen.new Piece(null, "(", null)); } - typeCell.addPiece(gen.new Piece(null, ")", null)); - } - } - choicerow.getCells().add(gen.new Cell()); - subRows.add(choicerow); + boolean first = true; + for (CanonicalType rt : tr.getTargetProfile()) { + if (!mustSupportMode || allProfilesMustSupport(tr.getTargetProfile()) || isMustSupport(rt)) { + if (!first) + c.getPieces().add(gen.new Piece(null, " | ", null)); + genTargetLink(gen, profileBaseFileName, corePath, c, tr, rt.getValue()); + if (!mustSupportMode && isMustSupport(rt) && element.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText(translate("sd.table", "This target must be supported"), "S", "white", "red", null, false); + } + first = false; + } + } + if (first) + c.getPieces().add(gen.new Piece(null, "Any", null)); + + if (ADD_REFERENCE_TO_TABLE) + c.getPieces().add(gen.new Piece(null, ")", null)); + + } else { + StructureDefinition sd = context.fetchTypeDefinition(t); + if (sd == null) { + System.out.println("Unable to find "+t); + sd = context.fetchTypeDefinition(t); + } else if (sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE) { + choicerow.getCells().add(gen.new Cell(null, null, tail(element.getPath()).replace("[x]", Utilities.capitalize(t)), sd.getDescription(), null)); + choicerow.getCells().add(gen.new Cell()); + choicerow.getCells().add(gen.new Cell(null, null, "", null, null)); + choicerow.setIcon("icon_primitive.png", HierarchicalTableGenerator.TEXT_ICON_PRIMITIVE); + Cell c = gen.new Cell(null, corePath+"datatypes.html#"+t, sd.getType(), null, null); + choicerow.getCells().add(c); + if (!mustSupportMode && isMustSupport(tr) && element.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false); + } + } else { + choicerow.getCells().add(gen.new Cell(null, null, tail(element.getPath()).replace("[x]", Utilities.capitalize(t)), sd.getDescription(), null)); + choicerow.getCells().add(gen.new Cell()); + choicerow.getCells().add(gen.new Cell(null, null, "", null, null)); + choicerow.setIcon("icon_datatype.gif", HierarchicalTableGenerator.TEXT_ICON_DATATYPE); + Cell c = gen.new Cell(null, pkp.getLinkFor(corePath, t), sd.getType(), null, null); + choicerow.getCells().add(c); + if (!mustSupportMode && isMustSupport(tr) && element.getMustSupport()) { + c.addPiece(gen.new Piece(null, " ", null)); + c.addStyledText(translate("sd.table", "This type must be supported"), "S", "white", "red", null, false); + } + } + if (tr.hasProfile()) { + Cell typeCell = choicerow.getCells().get(3); + typeCell.addPiece(gen.new Piece(null, "(", null)); + boolean first = true; + for (CanonicalType pt : tr.getProfile()) { + if (!mustSupportMode || allProfilesMustSupport(tr.getProfile()) || isMustSupport(pt)) { + if (first) first = false; else typeCell.addPiece(gen.new Piece(null, " | ", null)); + StructureDefinition psd = context.fetchResource(StructureDefinition.class, pt.getValue()); + if (psd == null) + typeCell.addPiece(gen.new Piece(null, "?gen-e2?", null)); + else + typeCell.addPiece(gen.new Piece(psd.getUserString("path"), psd.getName(), psd.present())); + if (!mustSupportMode && isMustSupport(pt) && element.getMustSupport()) { + typeCell.addPiece(gen.new Piece(null, " ", null)); + typeCell.addStyledText(translate("sd.table", "This profile must be supported"), "S", "white", "red", null, false); + } + } + } + typeCell.addPiece(gen.new Piece(null, ")", null)); + } + } + choicerow.getCells().add(gen.new Cell()); + subRows.add(choicerow); + } } } @@ -4124,7 +4243,7 @@ public class ProfileUtilities extends TranslatingUtilities { ExtensionContext extDefn = null; genCardinality(gen, element, row, hasDef, used, null); if (hasDef && !"0".equals(element.getMax())) - genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root); + genTypes(gen, row, element, profileBaseFileName, profile, corePath, imagePath, root, false); else row.getCells().add(gen.new Cell()); generateGridDescription(gen, row, element, null, used.used, null, null, profile, corePath, imagePath, root, null); @@ -4314,20 +4433,19 @@ public class ProfileUtilities extends TranslatingUtilities { if (definition != null) { ElementDefinitionBindingComponent binding = null; if (valueDefn != null && valueDefn.hasBinding() && !valueDefn.getBinding().isEmpty()) - binding = valueDefn.getBinding(); + binding = makeUnifiedBinding(valueDefn.getBinding(), valueDefn); else if (definition.hasBinding()) - binding = definition.getBinding(); + binding = makeUnifiedBinding(definition.getBinding(), definition); if (binding!=null && !binding.isEmpty()) { if (!c.getPieces().isEmpty()) c.addPiece(gen.new Piece("br")); BindingResolution br = pkp.resolveBinding(profile, binding, definition.getPath()); c.getPieces().add(checkForNoChange(binding, gen.new Piece(null, translate("sd.table", "Binding")+": ", null).addStyle("font-weight:bold"))); - c.getPieces().add(checkForNoChange(binding, gen.new Piece(br.url == null ? null : Utilities.isAbsoluteUrl(br.url) || !pkp.prependLinks() ? br.url : corePath+br.url, br.display, null))); + c.getPieces().add(checkForNoChange(binding.getValueSetElement(), gen.new Piece(br.url == null ? null : Utilities.isAbsoluteUrl(br.url) || !pkp.prependLinks() ? br.url : corePath+br.url, br.display, null))); if (binding.hasStrength()) { - c.getPieces().add(checkForNoChange(binding, gen.new Piece(null, " (", null))); - c.getPieces().add(checkForNoChange(binding, gen.new Piece(corePath+"terminologies.html#"+binding.getStrength().toCode(), egt(binding.getStrengthElement()), binding.getStrength().getDefinition()))); - - c.getPieces().add(gen.new Piece(null, ")", null)); + c.getPieces().add(checkForNoChange(binding.getStrengthElement(), gen.new Piece(null, " (", null))); + c.getPieces().add(checkForNoChange(binding.getStrengthElement(), gen.new Piece(corePath+"terminologies.html#"+binding.getStrength().toCode(), egt(binding.getStrengthElement()), binding.getStrength().getDefinition()))); + c.getPieces().add(checkForNoChange(binding.getStrengthElement(), gen.new Piece(null, ")", null))); } if (binding.hasExtension(ToolingExtensions.EXT_MAX_VALUESET)) { br = pkp.resolveBinding(profile, ToolingExtensions.readStringExtension(binding, ToolingExtensions.EXT_MAX_VALUESET), definition.getPath()); @@ -4343,8 +4461,8 @@ public class ProfileUtilities extends TranslatingUtilities { } if (binding.hasDescription() && MarkDownProcessor.isSimpleMarkdown(binding.getDescription())) { c.getPieces().add(gen.new Piece(null, ": ", null)); - c.addMarkdownNoPara(binding.getDescription()); - } + c.addMarkdownNoPara(binding.getDescription(), checkForNoChange(binding.getDescriptionElement())); + } } for (ElementDefinitionConstraintComponent inv : definition.getConstraint()) { if (!inv.hasSource() || profile == null || inv.getSource().equals(profile.getUrl()) || allInvariants) { @@ -4424,6 +4542,38 @@ public class ProfileUtilities extends TranslatingUtilities { return c; } + private ElementDefinitionBindingComponent makeUnifiedBinding(ElementDefinitionBindingComponent binding, ElementDefinition element) { + if (!element.hasUserData(DERIVATION_POINTER)) { + return binding; + } + ElementDefinition base = (ElementDefinition) element.getUserData(DERIVATION_POINTER); + if (!base.hasBinding()) { + return binding; + } + ElementDefinitionBindingComponent o = base.getBinding(); + ElementDefinitionBindingComponent b = new ElementDefinitionBindingComponent(); + b.setUserData(DERIVATION_POINTER, o); + if (binding.hasValueSet()) { + b.setValueSet(binding.getValueSet()); + } else if (o.hasValueSet()) { + b.setValueSet(o.getValueSet()); + b.getValueSetElement().setUserData(DERIVATION_EQUALS, o.getValueSetElement()); + } + if (binding.hasStrength()) { + b.setStrength(binding.getStrength()); + } else if (o.hasStrength()) { + b.setStrength(o.getStrength()); + b.getStrengthElement().setUserData(DERIVATION_EQUALS, o.getStrengthElement()); + } + if (binding.hasDescription()) { + b.setDescription(binding.getDescription()); + } else if (o.hasDescription()) { + b.setDescription(o.getDescription()); + b.getDescriptionElement().setUserData(DERIVATION_EQUALS, o.getDescriptionElement()); + } + return b; + } + private void genFixedValue(HierarchicalTableGenerator gen, Row erow, DataType value, boolean snapshot, boolean pattern, String corePath, boolean skipnoValue) { String ref = pkp.getLinkFor(corePath, value.fhirType()); if (ref != null) { @@ -4983,6 +5133,9 @@ public class ProfileUtilities extends TranslatingUtilities { if (ref.substring(1, 2).toUpperCase().equals(ref.substring(1,2))) { actual = base+(ref.substring(1)+"."+path.substring(p.length()+1)).substring(prefixLength); path = actual; + } else if (ref.startsWith("http:")) { + actual = base+(ref.substring(ref.indexOf("#")+1)+"."+path.substring(p.length()+1)).substring(prefixLength); + path = actual; } else { // Older versions of FHIR (e.g. 2016May) had reference of the style #parameter instead of #Parameters.parameter, so we have to handle that actual = base+(path.substring(0, path.indexOf(".")+1) + ref.substring(1)+"."+path.substring(p.length()+1)).substring(prefixLength); @@ -6016,7 +6169,7 @@ public class ProfileUtilities extends TranslatingUtilities { TableModel model = gen.new TableModel(id, true); model.setDocoImg(prefix+"help16.png"); - model.setDocoRef(prefix+"formats.html#table"); // todo: change to graph definition + model.setDocoRef(Utilities.pathURL(prefix, "formats.html#table")); // todo: change to graph definition model.getTitles().add(gen.new Title(null, model.getDocoRef(), "Property", "A profiled resource", null, 0)); model.getTitles().add(gen.new Title(null, model.getDocoRef(), "Card.", "Minimum and Maximum # of times the the element can appear in the instance", null, 0)); model.getTitles().add(gen.new Title(null, model.getDocoRef(), "Content", "What goes here", null, 0)); @@ -6276,6 +6429,25 @@ public class ProfileUtilities extends TranslatingUtilities { return grp; } + public static boolean allTypesMustSupport(ElementDefinition e) { + boolean all = true; + boolean any = false; + for (TypeRefComponent tr : e.getType()) { + all = all && isMustSupport(tr); + any = any || isMustSupport(tr); + } + return !all && !any; + } + + public static boolean allProfilesMustSupport(List profiles) { + boolean all = true; + boolean any = false; + for (CanonicalType u : profiles) { + all = all && isMustSupport(u); + any = any || isMustSupport(u); + } + return !all && !any; + } public static boolean isMustSupportDirect(TypeRefComponent tr) { return ("true".equals(ToolingExtensions.readStringExtension(tr, ToolingExtensions.EXT_MUST_SUPPORT))); } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java index 2033956f9..cf2331b05 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/DataRenderer.java @@ -392,12 +392,17 @@ public class DataRenderer extends Renderer { } else if (!getContext().isCanonicalUrlsAsLinks()) url = null; } - if (url == null) + if (url == null) { x.b().tx(uri.getValue()); - else if (uri.getValue().startsWith("mailto:")) + } else if (uri.getValue().startsWith("mailto:")) { x.ah(uri.getValue()).addText(uri.getValue().substring(7)); - else - x.ah(uri.getValue()).addText(uri.getValue()); + } else { + if (uri.getValue().contains("|")) { + x.ah(uri.getValue().substring(0, uri.getValue().indexOf("|"))).addText(uri.getValue()); + } else { + x.ah(uri.getValue()).addText(uri.getValue()); + } + } } protected void renderAnnotation(XhtmlNode x, Annotation annot) { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java index 12235debe..124ddd4ff 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ProfileDrivenRenderer.java @@ -824,7 +824,10 @@ public class ProfileDrivenRenderer extends ResourceRenderer { if (p == null || p.getValues().size() == 0 || p.getValues().get(0) == null) td.tx(" "); else { - renderLeaf(res, p.getValues().get(0), e, td, td, false, showCodeDetails, displayHints, path, indent); + for (BaseWrapper vv : p.getValues()) { + td.sep(", "); + renderLeaf(res, vv, e, td, td, false, showCodeDetails, displayHints, path, indent); + } } } } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireRenderer.java index 5d0d4a1ad..ead0cf012 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireRenderer.java @@ -142,7 +142,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer { rows.add(r); boolean hasExt = false; - r.setIcon("icon-q-"+i.getType().toCode()+".png", i.getType().getDisplay()); + r.setIcon("icon-q-"+i.getType().toCode().toLowerCase()+".png", i.getType().getDisplay()); r.getCells().add(gen.new Cell(null, context.getDefinitionsTarget() == null ? "" : context.getDefinitionsTarget()+"#item."+i.getLinkId(), i.getLinkId(), null, null)); String txt = (i.hasPrefix() ? i.getPrefix() + ". " : "") + i.getText(); r.getCells().add(gen.new Cell(null, null, txt, null, null)); @@ -361,7 +361,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer { rows.add(r); boolean hasExt = false; - r.setIcon("icon-q-"+i.getType().toCode()+".png", i.getType().getDisplay()); + r.setIcon("icon-q-"+i.getType().toCode().toLowerCase()+".png", i.getType().getDisplay()); r.getCells().add(gen.new Cell(null, context.getDefinitionsTarget() == null ? "" : context.getDefinitionsTarget()+"#item."+i.getLinkId(), i.getLinkId(), null, null)); Cell defn = gen.new Cell(); r.getCells().add(defn); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java index 3a4015afa..af62c7fb4 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/terminologies/ValueSetCheckerSimple.java @@ -523,14 +523,13 @@ public class ValueSetCheckerSimple implements ValueSetChecker { } else { if (vsi.hasFilter()) { boolean ok = true; - for (ConceptSetFilterComponent f : vsi.getFilter()) + for (ConceptSetFilterComponent f : vsi.getFilter()) { if (!codeInFilter(cs, system, f, code)) { ok = false; break; } - if (ok) { - return true; } + return ok; } List list = cs.getConcept(); 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 135934e47..41db374dd 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 @@ -465,6 +465,7 @@ public class SnapShotGenerationTests { fp.setHostServices(context); messages = new ArrayList(); + System.out.println("---- "+id+" -----------------------------------------"); if (test.isFail()) { boolean failed = true; try { diff --git a/org.hl7.fhir.report/pom.xml b/org.hl7.fhir.report/pom.xml index fa7b2b286..6eadb86f9 100644 --- a/org.hl7.fhir.report/pom.xml +++ b/org.hl7.fhir.report/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 5.1.21-SNAPSHOT + 5.1.23-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.utilities/pom.xml b/org.hl7.fhir.utilities/pom.xml index d6da0d28c..e363f4730 100644 --- a/org.hl7.fhir.utilities/pom.xml +++ b/org.hl7.fhir.utilities/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 5.1.21-SNAPSHOT + 5.1.23-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java index a5476d661..30903ddcd 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/VersionUtilities.java @@ -229,8 +229,14 @@ public class VersionUtilities { * @return Is {@literal current} later or equal to {@literal test}? For example, if this = 0.5 and current = 0.6 this method will return true */ public static boolean isThisOrLater(String test, String current) { + if (test == null || current == null) { + return false; + } String t = getMajMin(test); String c = getMajMin(current); + if (t == null || c == null) { + return false; + } if (c.compareTo(t) == 0) { return isMajMinOrLaterPatch(test, current); } diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/FilesystemPackageCacheManager.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/FilesystemPackageCacheManager.java index 23a23ec27..fdb9338c2 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/FilesystemPackageCacheManager.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/npm/FilesystemPackageCacheManager.java @@ -41,6 +41,7 @@ import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.VersionUtilities; import org.hl7.fhir.utilities.json.JSONUtil; +import org.hl7.fhir.utilities.json.JsonTrackingParser; import org.hl7.fhir.utilities.npm.NpmPackage.NpmPackageFolder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -352,7 +353,7 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple System.out.print(" Installing: "); } - if (npm.name() == null || id == null || !id.equals(npm.name())) { + if (npm.name() == null || id == null || !id.equalsIgnoreCase(npm.name())) { if (!id.equals("hl7.fhir.r5.core")) {// temporary work around throw new IOException("Attempt to import a mis-identified package. Expected " + id + ", got " + npm.name()); } @@ -549,7 +550,9 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple @Override public String getPackageId(String canonicalUrl) throws IOException { - String retVal = super.getPackageId(canonicalUrl); + String retVal = findCanonicalInLocalCache(canonicalUrl); + + retVal = super.getPackageId(canonicalUrl); if (retVal == null) { retVal = getPackageIdFromBuildList(canonicalUrl); @@ -559,6 +562,21 @@ public class FilesystemPackageCacheManager extends BasePackageCacheManager imple } + public String findCanonicalInLocalCache(String canonicalUrl) { + try { + for (String pf : listPackages()) { + if (new File(Utilities.path(cacheFolder, pf, "package", "package.json")).exists()) { + JsonObject npm = JsonTrackingParser.parseJsonFile(Utilities.path(cacheFolder, pf, "package", "package.json")); + if (canonicalUrl.equals(JSONUtil.str(npm, "canonical"))) { + return JSONUtil.str(npm, "name"); + } + } + } + } catch (IOException e) { + } + return null; + } + // ========================= Package Mgmt API ======================================================================= private String getPackageIdFromBuildList(String canonical) throws IOException { diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/HierarchicalTableGenerator.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/HierarchicalTableGenerator.java index 94e337d33..e6e09522c 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/HierarchicalTableGenerator.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/HierarchicalTableGenerator.java @@ -247,7 +247,7 @@ public class HierarchicalTableGenerator extends TranslatingUtilities { Node document = parser.parse(md); HtmlRenderer renderer = HtmlRenderer.builder().escapeHtml(true).build(); String html = renderer.render(document); - pieces.addAll(htmlToParagraphPieces(html)); + pieces.addAll(htmlToParagraphPieces(html, null)); } catch (Exception e) { e.printStackTrace(); } @@ -255,19 +255,23 @@ public class HierarchicalTableGenerator extends TranslatingUtilities { } public Cell addMarkdownNoPara(String md) { + return addMarkdownNoPara(md, null); + } + + public Cell addMarkdownNoPara(String md, String style) { try { Parser parser = Parser.builder().build(); Node document = parser.parse(md); HtmlRenderer renderer = HtmlRenderer.builder().escapeHtml(true).build(); String html = renderer.render(document); - pieces.addAll(htmlToParagraphPieces(html)); + pieces.addAll(htmlToParagraphPieces(html, style)); } catch (Exception e) { e.printStackTrace(); } return this; } - private List htmlToParagraphPieces(String html) { + private List htmlToParagraphPieces(String html, String style) { List myPieces = new ArrayList(); try { XhtmlNode node = new XhtmlParser().parseFragment(""+html+""); @@ -281,14 +285,17 @@ public class HierarchicalTableGenerator extends TranslatingUtilities { } if (c.getNodeType() == NodeType.Text) { if (!Utilities.isWhitespace(c.getContent())) - addNode(myPieces, c); + addNode(myPieces, c, style); } else if ("p".equals(c.getName())) { for (XhtmlNode g : c.getChildNodes()) { - addNode(myPieces, g); + addNode(myPieces, g, style); } } else { Piece x = new Piece(c.getName()); x.getChildren().addAll(c.getChildNodes()); + if (style != null) { + x.addStyle(style); + } myPieces.add(x); } } @@ -314,49 +321,56 @@ public class HierarchicalTableGenerator extends TranslatingUtilities { if (html.contains(("<"))) { XhtmlNode node = new XhtmlParser().parseFragment("

"+html+"

"); for (XhtmlNode c : node.getChildNodes()) { - addNode(myPieces, c); + addNode(myPieces, c, null); } } else myPieces.add(new Piece(null, html, null)); return myPieces; } - private void addNode(List list, XhtmlNode c) { + private void addNode(List list, XhtmlNode c, String style) { if (c.getNodeType() == NodeType.Text) - list.add(new Piece(null, c.getContent(), null)); + list.add(styleIt(new Piece(null, c.getContent(), null), style)); else if (c.getNodeType() == NodeType.Element) { if (c.getName().equals("a")) { - list.add(new Piece(c.getAttribute("href"), c.allText(), c.getAttribute("title"))); + list.add(styleIt(new Piece(c.getAttribute("href"), c.allText(), c.getAttribute("title")), style)); } else if (c.getName().equals("b") || c.getName().equals("em") || c.getName().equals("strong")) { - list.add(new Piece(null, c.allText(), null).setStyle("font-face: bold")); + list.add(styleIt(new Piece(null, c.allText(), null).setStyle("font-face: bold"), style)); } else if (c.getName().equals("code")) { - list.add(new Piece(null, c.allText(), null).setStyle("padding: 2px 4px; color: #005c00; background-color: #f9f2f4; white-space: nowrap; border-radius: 4px")); + list.add(styleIt(new Piece(null, c.allText(), null).setStyle("padding: 2px 4px; color: #005c00; background-color: #f9f2f4; white-space: nowrap; border-radius: 4px"), style)); } else if (c.getName().equals("i")) { - list.add(new Piece(null, c.allText(), null).setStyle("font-style: italic")); + list.add(styleIt(new Piece(null, c.allText(), null).setStyle("font-style: italic"), style)); } else if (c.getName().equals("pre")) { - Piece p = new Piece(c.getName()).setStyle("white-space: pre; font-family: courier"); + Piece p = styleIt(new Piece(c.getName()).setStyle("white-space: pre; font-family: courier"), style); list.add(p); p.getChildren().addAll(c.getChildNodes()); } else if (c.getName().equals("ul") || c.getName().equals("ol")) { - Piece p = new Piece(c.getName()); + Piece p = styleIt(new Piece(c.getName()), style); list.add(p); p.getChildren().addAll(c.getChildNodes()); } else if (c.getName().equals("i")) { - list.add(new Piece(null, c.allText(), null).setStyle("font-style: italic")); + list.add(styleIt(new Piece(null, c.allText(), null).setStyle("font-style: italic"), style)); } else if (c.getName().equals("h1")||c.getName().equals("h2")||c.getName().equals("h3")||c.getName().equals("h4")) { - Piece p = new Piece(c.getName()); + Piece p = styleIt(new Piece(c.getName()), style); list.add(p); p.getChildren().addAll(c.getChildNodes()); } else if (c.getName().equals("br")) { - list.add(new Piece(c.getName())); + list.add(styleIt(new Piece(c.getName()), style)); } else { - throw new Error("Not handled yet: "+c.getName()); } } else throw new Error("Unhandled type "+c.getNodeType().toString()); - } + + + private Piece styleIt(Piece piece, String style) { + if (style != null) { + piece.addStyle(style); + } + return piece; + } + public Cell addStyle(String style) { for (Piece p : pieces) p.addStyle(style); @@ -583,7 +597,7 @@ public class HierarchicalTableGenerator extends TranslatingUtilities { model.setAlternating(alternating); model.setDocoImg(prefix+"help16.png"); - model.setDocoRef(prefix+"formats.html#table"); + model.setDocoRef(Utilities.pathURL(prefix, "formats.html#table")); model.getTitles().add(new Title(null, model.getDocoRef(), translate("sd.head", "Name"), translate("sd.hint", "The logical name of the element"), null, 0)); model.getTitles().add(new Title(null, model.getDocoRef(), translate("sd.head", "Flags"), translate("sd.hint", "Information about the use of the element"), null, 0)); model.getTitles().add(new Title(null, model.getDocoRef(), translate("sd.head", "Card."), translate("sd.hint", "Minimum and Maximum # of times the the element can appear in the instance"), null, 0)); @@ -600,7 +614,7 @@ public class HierarchicalTableGenerator extends TranslatingUtilities { model.setAlternating(true); model.setDocoImg(prefix+"help16.png"); - model.setDocoRef(prefix+"formats.html#table"); + model.setDocoRef(Utilities.pathURL(prefix, "formats.html#table")); model.getTitles().add(new Title(null, model.getDocoRef(), translate("sd.head", "Name"), translate("sd.hint", "The logical name of the element"), null, 0)); model.getTitles().add(new Title(null, model.getDocoRef(), translate("sd.head", "L Flags"), translate("sd.hint", "Information about the use of the element - Left Structure"), null, 0).setStyle("border-left: 1px grey solid")); model.getTitles().add(new Title(null, model.getDocoRef(), translate("sd.head", "L Card."), translate("sd.hint", "Minimum and Maximum # of times the the element can appear in the instance - Left Structure"), null, 0)); diff --git a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlNode.java b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlNode.java index 32a8bbf02..d48e436f9 100644 --- a/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlNode.java +++ b/org.hl7.fhir.utilities/src/main/java/org/hl7/fhir/utilities/xhtml/XhtmlNode.java @@ -843,11 +843,11 @@ public class XhtmlNode implements IBaseXhtml { public XhtmlNode sep(String separator) { - // if there's already text, add the separator - if (seperated) { + // if there's already text, add the separator. otherwise, we'll add it next time + if (!seperated) { + seperated = true; return this; } - seperated = true; return tx(separator); } diff --git a/org.hl7.fhir.validation.cli/pom.xml b/org.hl7.fhir.validation.cli/pom.xml index 849541b16..38eff9a64 100644 --- a/org.hl7.fhir.validation.cli/pom.xml +++ b/org.hl7.fhir.validation.cli/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 5.1.21-SNAPSHOT + 5.1.23-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.validation/pom.xml b/org.hl7.fhir.validation/pom.xml index 7ad6a3959..53d68e504 100644 --- a/org.hl7.fhir.validation/pom.xml +++ b/org.hl7.fhir.validation/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir org.hl7.fhir.core - 5.1.21-SNAPSHOT + 5.1.23-SNAPSHOT ../pom.xml diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/StandAloneValidatorFetcher.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/StandAloneValidatorFetcher.java index 904ec8dca..f76fa0f8d 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/StandAloneValidatorFetcher.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/StandAloneValidatorFetcher.java @@ -25,7 +25,7 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher { void loadPackage(String id, String ver) throws IOException, FHIRException; } - private BasePackageCacheManager pcm; + private FilesystemPackageCacheManager pcm; private IWorkerContext context; private IPackageInstaller installer; @@ -51,19 +51,37 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher { if (!Utilities.isAbsoluteUrl(url)) { return false; } - // if we've got to here, it's a reference to a FHIR URL. We're going to try to resolve it on the fly - // first possibility: it's a reference to a version specific URL http://hl7.org/fhir/X.X/... - VersionURLInfo vu = VersionUtilities.parseVersionUrl(url); - if (vu != null) { - NpmPackage pi = pcm.loadPackage(VersionUtilities.packageForVersion(vu.getVersion()), VersionUtilities.getCurrentVersion(vu.getVersion())); - return pi.hasCanonical(vu.getUrl()); + // if we've got to here, it's a reference to a FHIR URL. We're going to try to resolve it on the fly + String pid = null; + String ver = null; + String base = findBaseUrl(url); + if (base == null) { + return false; + } + + if (base.equals("http://terminology.hl7.org")) { + pid = "hl7.terminology"; + } else if (url.startsWith("http://hl7.org/fhir")) { + pid = pcm.getPackageId(base); + } else { + pid = pcm.findCanonicalInLocalCache(base); + } + ver = url.contains("|") ? url.substring(url.indexOf("|")+1) : null; + if (pid == null) { + return false; + } + + if (url.startsWith("http://hl7.org/fhir")) { + // first possibility: it's a reference to a version specific URL http://hl7.org/fhir/X.X/... + VersionURLInfo vu = VersionUtilities.parseVersionUrl(url); + if (vu != null) { + NpmPackage pi = pcm.loadPackage(VersionUtilities.packageForVersion(vu.getVersion()), VersionUtilities.getCurrentVersion(vu.getVersion())); + return pi.hasCanonical(vu.getUrl()); + } } // ok maybe it's a reference to a package we know - String base = findBaseUrl(url); - String pid = pcm.getPackageId(base); - String ver = url.contains("|") ? url.substring(url.indexOf("|")+1) : null; if (pid != null) { if (installer.packageExists(pid, ver)) { installer.loadPackage(pid, ver); @@ -72,13 +90,8 @@ public class StandAloneValidatorFetcher implements IValidatorResourceFetcher { } } - if (!url.startsWith("http://hl7.org/fhir")) { - return true; // we don't bother with those in the standalone validator - we assume they are valid - } - - // we assume it's invalid at this point - return false; - + // we don't bother with urls outside fhir space in the standalone validator - we assume they are valid + return !url.startsWith("http://hl7.org/fhir"); } private String findBaseUrl(String url) { diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/ValidationService.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/ValidationService.java index 16417caa8..5f564f143 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/ValidationService.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/cli/services/ValidationService.java @@ -209,6 +209,7 @@ public class ValidationService { FhirPublication ver = FhirPublication.fromCode(cliContext.getSv()); ValidationEngine validator = new ValidationEngine(definitions, ver, cliContext.getSv(), tt); System.out.println(" - "+validator.getContext().countAllCaches()+" resources ("+tt.milestone()+")"); + validator.loadIg("hl7.terminology", false); System.out.print(" Terminology server " + cliContext.getTxServer()); String txver = validator.setTerminologyServer(cliContext.getTxServer(), cliContext.getTxLog(), ver); System.out.println(" - Version "+txver+" ("+tt.milestone()+")"); diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java index 1727acab8..4bb5353fe 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/InstanceValidator.java @@ -2419,8 +2419,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat String ref = reference.getReference(); if (Utilities.noString(ref)) { - if (Utilities.noString(reference.getIdentifier().getSystem()) && Utilities.noString(reference.getIdentifier().getValue())) { - warning(errors, IssueType.STRUCTURE, element.line(), element.col(), path, !Utilities.noString(element.getNamedChildValue("display")), I18nConstants.REFERENCE_REF_NODISPLAY); + if (!path.contains("element.pattern")) { // this business rule doesn't apply to patterns + if (Utilities.noString(reference.getIdentifier().getSystem()) && Utilities.noString(reference.getIdentifier().getValue())) { + warning(errors, IssueType.STRUCTURE, element.line(), element.col(), path, !Utilities.noString(element.getNamedChildValue("display")), I18nConstants.REFERENCE_REF_NODISPLAY); + } } return; } else if (Utilities.existsInList(ref, "http://tools.ietf.org/html/bcp47")) { diff --git a/pom.xml b/pom.xml index c1c73023a..e23a6f3be 100644 --- a/pom.xml +++ b/pom.xml @@ -14,12 +14,12 @@ HAPI FHIR. --> org.hl7.fhir.core - 5.1.21-SNAPSHOT + 5.1.23-SNAPSHOT pom 5.1.0 - 1.1.48-SNAPSHOT + 1.1.50 5.6.2 3.0.0-M4 0.8.5