GF#18121 - fix so relative links in source markdown don't generate broken linke in IGs

This commit is contained in:
Grahame Grieve 2019-03-04 11:53:14 +11:00
parent cde0df1118
commit 5691333e98
7 changed files with 87 additions and 38 deletions

View File

@ -376,14 +376,15 @@ public class ProfileUtilities extends TranslatingUtilities {
* *
* @param base - the base structure on which the differential will be applied * @param base - the base structure on which the differential will be applied
* @param differential - the differential to apply to the base * @param differential - the differential to apply to the base
* @param url - where the base has relative urls for profile references, these need to be converted to absolutes by prepending this URL * @param url - where the base has relative urls for profile references, these need to be converted to absolutes by prepending this URL (e.g. the canonical URL)
* @param webUrl - where the base has relative urls in markdown, these need to be converted to absolutes by prepending this URL (this is not the same as the canonical URL)
* @param trimDifferential - if this is true, then the snap short generator will remove any material in the element definitions that is not different to the base * @param trimDifferential - if this is true, then the snap short generator will remove any material in the element definitions that is not different to the base
* @return * @return
* @throws FHIRException * @throws FHIRException
* @throws DefinitionException * @throws DefinitionException
* @throws Exception * @throws Exception
*/ */
public void generateSnapshot(StructureDefinition base, StructureDefinition derived, String url, String profileName) throws DefinitionException, FHIRException { public void generateSnapshot(StructureDefinition base, StructureDefinition derived, String url, String webUrl, String profileName) throws DefinitionException, FHIRException {
if (base == null) if (base == null)
throw new DefinitionException("no base profile provided"); throw new DefinitionException("no base profile provided");
if (derived == null) if (derived == null)
@ -392,7 +393,9 @@ public class ProfileUtilities extends TranslatingUtilities {
if (snapshotStack.contains(derived.getUrl())) if (snapshotStack.contains(derived.getUrl()))
throw new DefinitionException("Circular snapshot references detected; cannot generate snapshot (stack = "+snapshotStack.toString()+")"); throw new DefinitionException("Circular snapshot references detected; cannot generate snapshot (stack = "+snapshotStack.toString()+")");
snapshotStack.add(derived.getUrl()); snapshotStack.add(derived.getUrl());
if (webUrl != null && !webUrl.endsWith("/"))
webUrl = webUrl + '/';
derived.setSnapshot(new StructureDefinitionSnapshotComponent()); derived.setSnapshot(new StructureDefinitionSnapshotComponent());
@ -415,7 +418,7 @@ public class ProfileUtilities extends TranslatingUtilities {
// we actually delegate the work to a subroutine so we can re-enter it with a different cursors // we actually delegate the work to a subroutine so we can re-enter it with a different cursors
processPaths("", derived.getSnapshot(), base.getSnapshot(), derived.getDifferential(), baseCursor, diffCursor, base.getSnapshot().getElement().size()-1, processPaths("", derived.getSnapshot(), base.getSnapshot(), derived.getDifferential(), baseCursor, diffCursor, base.getSnapshot().getElement().size()-1,
derived.getDifferential().hasElement() ? derived.getDifferential().getElement().size()-1 : -1, url, derived.getId(), null, null, false, base.getUrl(), null, false, new ArrayList<ElementRedirection>()); derived.getDifferential().hasElement() ? derived.getDifferential().getElement().size()-1 : -1, url, webUrl, derived.getId(), null, null, false, base.getUrl(), null, false, new ArrayList<ElementRedirection>());
if (!derived.getSnapshot().getElementFirstRep().getType().isEmpty()) 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()); throw new Error("type on first snapshot element for "+derived.getSnapshot().getElementFirstRep().getPath()+" in "+derived.getUrl()+" from "+base.getUrl());
updateMaps(base, derived); updateMaps(base, derived);
@ -531,7 +534,7 @@ public class ProfileUtilities extends TranslatingUtilities {
* @throws Exception * @throws Exception
*/ */
private ElementDefinition processPaths(String indent, StructureDefinitionSnapshotComponent result, StructureDefinitionSnapshotComponent base, StructureDefinitionDifferentialComponent differential, int baseCursor, int diffCursor, int baseLimit, private ElementDefinition processPaths(String indent, StructureDefinitionSnapshotComponent result, StructureDefinitionSnapshotComponent base, StructureDefinitionDifferentialComponent differential, int baseCursor, int diffCursor, int baseLimit,
int diffLimit, String url, String profileName, String contextPathSrc, String contextPathDst, boolean trimDifferential, String contextName, String resultPathBase, boolean slicingDone, List<ElementRedirection> redirector) throws DefinitionException, FHIRException { int diffLimit, String url, String webUrl, String profileName, String contextPathSrc, String contextPathDst, boolean trimDifferential, String contextName, String resultPathBase, boolean slicingDone, List<ElementRedirection> redirector) 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())+")"); 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; ElementDefinition res = null;
@ -542,13 +545,13 @@ public class ProfileUtilities extends TranslatingUtilities {
String cpath = fixedPathSource(contextPathSrc, currentBase.getPath(), redirector); 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")+")"); System.out.println(indent+" - "+cpath+": base = "+baseCursor+" to "+baseLimit+", diff = "+diffCursor+" to "+diffLimit+" (slicingDone = "+slicingDone+") (diffpath= "+(differential.getElement().size() > diffCursor ? differential.getElement().get(diffCursor).getPath() : "n/a")+")");
List<ElementDefinition> diffMatches = getDiffMatches(differential, cpath, diffCursor, diffLimit, profileName, url); // get a list of matching elements in scope List<ElementDefinition> diffMatches = getDiffMatches(differential, cpath, diffCursor, diffLimit, profileName); // get a list of matching elements in scope
// in the simple case, source is not sliced. // in the simple case, source is not sliced.
if (!currentBase.hasSlicing()) { if (!currentBase.hasSlicing()) {
if (diffMatches.isEmpty()) { // the differential doesn't say anything about this item if (diffMatches.isEmpty()) { // the differential doesn't say anything about this item
// so we just copy it in // so we just copy it in
ElementDefinition outcome = updateURLs(url, currentBase.copy()); ElementDefinition outcome = updateURLs(url, webUrl, currentBase.copy());
outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc));
updateFromBase(outcome, currentBase); updateFromBase(outcome, currentBase);
markDerived(outcome); markDerived(outcome);
@ -573,7 +576,7 @@ public class ProfileUtilities extends TranslatingUtilities {
while (differential.getElement().size() > diffCursor && pathStartsWith(differential.getElement().get(diffCursor).getPath(), cpath+".")) while (differential.getElement().size() > diffCursor && pathStartsWith(differential.getElement().get(diffCursor).getPath(), cpath+"."))
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, 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, profileName, cpath, outcome.getPath(), trimDifferential, contextName, resultPathBase, false, redirector); diffCursor-1, url, webUrl, profileName, cpath, outcome.getPath(), trimDifferential, contextName, resultPathBase, false, redirector);
} }
baseCursor++; baseCursor++;
} else if (diffMatches.size() == 1 && (slicingDone || !(diffMatches.get(0).hasSlicing() || (isExtension(diffMatches.get(0)) && diffMatches.get(0).hasSliceName())))) {// one matching element in the differential } else if (diffMatches.size() == 1 && (slicingDone || !(diffMatches.get(0).hasSlicing() || (isExtension(diffMatches.get(0)) && diffMatches.get(0).hasSliceName())))) {// one matching element in the differential
@ -586,7 +589,7 @@ public class ProfileUtilities extends TranslatingUtilities {
StructureDefinition sdb = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition()); StructureDefinition sdb = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition());
if (sdb == null) if (sdb == null)
throw new DefinitionException("no base for "+sd.getBaseDefinition()); throw new DefinitionException("no base for "+sd.getBaseDefinition());
generateSnapshot(sdb, sd, sd.getUrl(), sd.getName()); generateSnapshot(sdb, sd, sd.getUrl(), (sdb.hasUserData("path")) ? Utilities.extractBaseUrl(sdb.getUserString("path")) : webUrl, sd.getName());
} }
ElementDefinition src; ElementDefinition src;
if (p.hasExtension(ToolingExtensions.EXT_PROFILE_ELEMENT)) { if (p.hasExtension(ToolingExtensions.EXT_PROFILE_ELEMENT)) {
@ -615,7 +618,7 @@ public class ProfileUtilities extends TranslatingUtilities {
// some of what's in currentBase overrides template // some of what's in currentBase overrides template
template = overWriteWithCurrent(template, currentBase); template = overWriteWithCurrent(template, currentBase);
ElementDefinition outcome = updateURLs(url, template); ElementDefinition outcome = updateURLs(url, webUrl, template);
outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc));
if (res == null) if (res == null)
res = outcome; res = outcome;
@ -672,14 +675,14 @@ public class ProfileUtilities extends TranslatingUtilities {
int nbl = nbc; int nbl = nbc;
while (nbl < base.getElement().size() && base.getElement().get(nbl).getPath().startsWith(tgt.getPath()+".")) while (nbl < base.getElement().size() && base.getElement().get(nbl).getPath().startsWith(tgt.getPath()+"."))
nbl++; nbl++;
processPaths(indent+" ", result, base, differential, nbc, start - 1, nbl-1, diffCursor - 1, url, profileName, tgt.getPath(), diffMatches.get(0).getPath(), trimDifferential, contextName, resultPathBase, false, redirectorStack(redirector, outcome, cpath)); 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, redirectorStack(redirector, outcome, cpath));
} else { } else {
StructureDefinition dt = outcome.getType().size() == 1 ? getProfileForDataType(outcome.getType().get(0)) : getProfileForDataType("Element"); StructureDefinition dt = outcome.getType().size() == 1 ? getProfileForDataType(outcome.getType().get(0)) : getProfileForDataType("Element");
if (dt == null) if (dt == null)
throw new DefinitionException(diffMatches.get(0).getPath()+" has children ("+differential.getElement().get(diffCursor).getPath()+") for type "+typeCode(outcome.getType())+" in profile "+profileName+", but can't find type"); throw new DefinitionException(diffMatches.get(0).getPath()+" has children ("+differential.getElement().get(diffCursor).getPath()+") for type "+typeCode(outcome.getType())+" in profile "+profileName+", but can't find type");
contextName = dt.getUrl(); 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, 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, profileName+pathTail(diffMatches, 0), diffMatches.get(0).getPath(), outcome.getPath(), trimDifferential, contextName, resultPathBase, false, new ArrayList<ElementRedirection>()); diffCursor - 1, url, webUrl, profileName+pathTail(diffMatches, 0), diffMatches.get(0).getPath(), outcome.getPath(), trimDifferential, contextName, resultPathBase, false, new ArrayList<ElementRedirection>());
} }
} }
} }
@ -690,7 +693,7 @@ public class ProfileUtilities extends TranslatingUtilities {
int nbl = findEndOfElement(base, baseCursor); int nbl = findEndOfElement(base, baseCursor);
int ndc = differential.getElement().indexOf(diffMatches.get(0)); int ndc = differential.getElement().indexOf(diffMatches.get(0));
int ndl = findEndOfElement(differential, ndc); int ndl = findEndOfElement(differential, ndc);
ElementDefinition e = processPaths(indent+" ", result, base, differential, baseCursor, ndc, nbl, ndl, url, profileName+pathTail(diffMatches, 0), contextPathSrc, contextPathDst, ElementDefinition e = processPaths(indent+" ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName+pathTail(diffMatches, 0), contextPathSrc, contextPathDst,
trimDifferential, contextName, resultPathBase, true, redirector); trimDifferential, contextName, resultPathBase, true, redirector);
if (e==null) if (e==null)
throw new FHIRException("Did not find type root: " + diffMatches.get(0).getPath()); throw new FHIRException("Did not find type root: " + diffMatches.get(0).getPath());
@ -701,7 +704,7 @@ public class ProfileUtilities extends TranslatingUtilities {
// our processing scope for the differential is the item in the list, and all the items before the next one in the list // our processing scope for the differential is the item in the list, and all the items before the next one in the list
ndc = differential.getElement().indexOf(diffMatches.get(i)); ndc = differential.getElement().indexOf(diffMatches.get(i));
ndl = findEndOfElement(differential, ndc); ndl = findEndOfElement(differential, ndc);
processPaths(indent+" ", result, base, differential, baseCursor, ndc, nbl, ndl, url, profileName+pathTail(diffMatches, i), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, redirector); processPaths(indent+" ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName+pathTail(diffMatches, i), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, redirector);
} }
// ok, done with that - next in the base list // ok, done with that - next in the base list
baseCursor = nbl+1; baseCursor = nbl+1;
@ -723,7 +726,7 @@ public class ProfileUtilities extends TranslatingUtilities {
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 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 ndc = differential.getElement().indexOf(diffMatches.get(0));
int ndl = findEndOfElement(differential, ndc); int ndl = findEndOfElement(differential, ndc);
ElementDefinition e = processPaths(indent+" ", result, base, differential, baseCursor, ndc, nbl, ndl, url, profileName+pathTail(diffMatches, 0), contextPathSrc, contextPathDst, ElementDefinition e = processPaths(indent+" ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName+pathTail(diffMatches, 0), contextPathSrc, contextPathDst,
trimDifferential, contextName, resultPathBase, true, redirector); trimDifferential, contextName, resultPathBase, true, redirector);
if (e==null) if (e==null)
throw new FHIRException("Did not find single slice: " + diffMatches.get(0).getPath()); throw new FHIRException("Did not find single slice: " + diffMatches.get(0).getPath());
@ -731,7 +734,7 @@ public class ProfileUtilities extends TranslatingUtilities {
start++; start++;
} else { } else {
// we're just going to accept the differential slicing at face value // we're just going to accept the differential slicing at face value
ElementDefinition outcome = updateURLs(url, currentBase.copy()); ElementDefinition outcome = updateURLs(url, webUrl, currentBase.copy());
outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc));
updateFromBase(outcome, currentBase); updateFromBase(outcome, currentBase);
@ -768,7 +771,7 @@ public class ProfileUtilities extends TranslatingUtilities {
continue; continue;
}*/ }*/
// now we process the base scope repeatedly for each instance of the item in the differential list // 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, profileName+pathTail(diffMatches, i), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, redirector); processPaths(indent+" ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName+pathTail(diffMatches, i), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, redirector);
} }
// ok, done with that - next in the base list // ok, done with that - next in the base list
baseCursor = nbl+1; baseCursor = nbl+1;
@ -789,7 +792,7 @@ public class ProfileUtilities extends TranslatingUtilities {
if (diffMatches.isEmpty()) { // the differential doesn't say anything about this item if (diffMatches.isEmpty()) { // the differential doesn't say anything about this item
// copy across the currentbase, and all of its children and siblings // copy across the currentbase, and all of its children and siblings
while (baseCursor < base.getElement().size() && base.getElement().get(baseCursor).getPath().startsWith(path)) { while (baseCursor < base.getElement().size() && base.getElement().get(baseCursor).getPath().startsWith(path)) {
ElementDefinition outcome = updateURLs(url, base.getElement().get(baseCursor).copy()); ElementDefinition outcome = updateURLs(url, webUrl, base.getElement().get(baseCursor).copy());
outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc));
if (!outcome.getPath().startsWith(resultPathBase)) if (!outcome.getPath().startsWith(resultPathBase))
throw new DefinitionException("Adding wrong path in profile " + profileName + ": "+outcome.getPath()+" vs " + resultPathBase); throw new DefinitionException("Adding wrong path in profile " + profileName + ": "+outcome.getPath()+" vs " + resultPathBase);
@ -813,7 +816,7 @@ public class ProfileUtilities extends TranslatingUtilities {
if (!ruleMatches(dSlice.getRules(), bSlice.getRules())) if (!ruleMatches(dSlice.getRules(), bSlice.getRules()))
throw new DefinitionException("Slicing rules on differential ("+summarizeSlicing(dSlice)+") do not match those on base ("+summarizeSlicing(bSlice)+") - rule @ "+path+" ("+contextName+")"); throw new DefinitionException("Slicing rules on differential ("+summarizeSlicing(dSlice)+") do not match those on base ("+summarizeSlicing(bSlice)+") - rule @ "+path+" ("+contextName+")");
} }
ElementDefinition outcome = updateURLs(url, currentBase.copy()); ElementDefinition outcome = updateURLs(url, webUrl, currentBase.copy());
outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc));
updateFromBase(outcome, currentBase); updateFromBase(outcome, currentBase);
if (diffMatches.get(0).hasSlicing() || !diffMatches.get(0).hasSliceName()) { if (diffMatches.get(0).hasSlicing() || !diffMatches.get(0).hasSliceName()) {
@ -831,14 +834,14 @@ public class ProfileUtilities extends TranslatingUtilities {
int nbl = findEndOfElement(base, baseCursor); int nbl = findEndOfElement(base, baseCursor);
int ndc = differential.getElement().indexOf(diffMatches.get(0)); int ndc = differential.getElement().indexOf(diffMatches.get(0));
int ndl = findEndOfElement(differential, ndc); int ndl = findEndOfElement(differential, ndc);
processPaths(indent+" ", result, base, differential, baseCursor+1, ndc, nbl, ndl, url, profileName+pathTail(diffMatches, 0), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, null); processPaths(indent+" ", result, base, differential, baseCursor+1, ndc, nbl, ndl, url, webUrl, profileName+pathTail(diffMatches, 0), contextPathSrc, contextPathDst, trimDifferential, contextName, resultPathBase, true, null);
// throw new Error("Not done yet"); // throw new Error("Not done yet");
// } else if (currentBase.getType().get(0).getCode().equals("BackboneElement") && diffMatches.size() > 0 && diffMatches.get(0).hasSliceName()) { // } else if (currentBase.getType().get(0).getCode().equals("BackboneElement") && diffMatches.size() > 0 && diffMatches.get(0).hasSliceName()) {
} else if (currentBase.getType().get(0).getCode().equals("BackboneElement")) { } else if (currentBase.getType().get(0).getCode().equals("BackboneElement")) {
// We need to copy children of the backbone element before we start messing around with slices // We need to copy children of the backbone element before we start messing around with slices
int nbl = findEndOfElement(base, baseCursor); int nbl = findEndOfElement(base, baseCursor);
for (int i = baseCursor+1; i<=nbl; i++) { for (int i = baseCursor+1; i<=nbl; i++) {
outcome = updateURLs(url, base.getElement().get(i).copy()); outcome = updateURLs(url, webUrl, base.getElement().get(i).copy());
result.getElement().add(outcome); result.getElement().add(outcome);
} }
} }
@ -847,7 +850,7 @@ public class ProfileUtilities extends TranslatingUtilities {
List<ElementDefinition> baseMatches = getSiblings(base.getElement(), currentBase); List<ElementDefinition> baseMatches = getSiblings(base.getElement(), currentBase);
for (ElementDefinition baseItem : baseMatches) { for (ElementDefinition baseItem : baseMatches) {
baseCursor = base.getElement().indexOf(baseItem); baseCursor = base.getElement().indexOf(baseItem);
outcome = updateURLs(url, baseItem.copy()); outcome = updateURLs(url, webUrl, baseItem.copy());
updateFromBase(outcome, currentBase); updateFromBase(outcome, currentBase);
outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc));
outcome.setSlicing(null); outcome.setSlicing(null);
@ -861,7 +864,7 @@ public class ProfileUtilities extends TranslatingUtilities {
int ndc = differential.getElement().indexOf(diffMatches.get(diffpos)); int ndc = differential.getElement().indexOf(diffMatches.get(diffpos));
int ndl = findEndOfElement(differential, ndc); int ndl = findEndOfElement(differential, ndc);
// now we process the base scope repeatedly for each instance of the item in the differential list // 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, profileName+pathTail(diffMatches, diffpos), contextPathSrc, contextPathDst, closed, contextName, resultPathBase, true, redirector); processPaths(indent+" ", result, base, differential, baseCursor, ndc, nbl, ndl, url, webUrl, profileName+pathTail(diffMatches, diffpos), contextPathSrc, contextPathDst, closed, contextName, resultPathBase, true, redirector);
// ok, done with that - now set the cursors for if this is the end // ok, done with that - now set the cursors for if this is the end
baseCursor = nbl; baseCursor = nbl;
diffCursor = ndl+1; diffCursor = ndl+1;
@ -871,7 +874,7 @@ public class ProfileUtilities extends TranslatingUtilities {
baseCursor++; baseCursor++;
// just copy any children on the base // just copy any children on the base
while (baseCursor < base.getElement().size() && base.getElement().get(baseCursor).getPath().startsWith(path) && !base.getElement().get(baseCursor).getPath().equals(path)) { while (baseCursor < base.getElement().size() && base.getElement().get(baseCursor).getPath().startsWith(path) && !base.getElement().get(baseCursor).getPath().equals(path)) {
outcome = updateURLs(url, base.getElement().get(baseCursor).copy()); outcome = updateURLs(url, webUrl, base.getElement().get(baseCursor).copy());
outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc));
if (!outcome.getPath().startsWith(resultPathBase)) if (!outcome.getPath().startsWith(resultPathBase))
throw new DefinitionException("Adding wrong path"); throw new DefinitionException("Adding wrong path");
@ -894,7 +897,7 @@ public class ProfileUtilities extends TranslatingUtilities {
for (ElementDefinition baseItem : baseMatches) for (ElementDefinition baseItem : baseMatches)
if (baseItem.getSliceName().equals(diffItem.getSliceName())) if (baseItem.getSliceName().equals(diffItem.getSliceName()))
throw new DefinitionException("Named items are out of order in the slice"); throw new DefinitionException("Named items are out of order in the slice");
outcome = updateURLs(url, currentBase.copy()); outcome = updateURLs(url, webUrl, currentBase.copy());
// outcome = updateURLs(url, diffItem.copy()); // outcome = updateURLs(url, diffItem.copy());
outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc));
updateFromBase(outcome, currentBase); updateFromBase(outcome, currentBase);
@ -923,7 +926,7 @@ public class ProfileUtilities extends TranslatingUtilities {
while (differential.getElement().size() > diffCursor && pathStartsWith(differential.getElement().get(diffCursor).getPath(), diffMatches.get(0).getPath()+".")) while (differential.getElement().size() > diffCursor && pathStartsWith(differential.getElement().get(diffCursor).getPath(), diffMatches.get(0).getPath()+"."))
diffCursor++; diffCursor++;
processPaths(indent+" ", result, base, differential, baseStart, start-1, baseMax-1, processPaths(indent+" ", result, base, differential, baseStart, start-1, baseMax-1,
diffCursor - 1, url, profileName+pathTail(diffMatches, 0), base.getElement().get(0).getPath(), base.getElement().get(0).getPath(), trimDifferential, contextName, resultPathBase, false, redirector); diffCursor - 1, url, webUrl, profileName+pathTail(diffMatches, 0), base.getElement().get(0).getPath(), base.getElement().get(0).getPath(), trimDifferential, contextName, resultPathBase, false, redirector);
} else { } else {
StructureDefinition dt = getProfileForDataType(outcome.getType().get(0)); StructureDefinition dt = getProfileForDataType(outcome.getType().get(0));
@ -937,7 +940,7 @@ public class ProfileUtilities extends TranslatingUtilities {
while (differential.getElement().size() > diffCursor && pathStartsWith(differential.getElement().get(diffCursor).getPath(), diffMatches.get(0).getPath()+".")) while (differential.getElement().size() > diffCursor && pathStartsWith(differential.getElement().get(diffCursor).getPath(), diffMatches.get(0).getPath()+"."))
diffCursor++; 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, 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, profileName+pathTail(diffMatches, 0), diffMatches.get(0).getPath(), outcome.getPath(), trimDifferential, contextName, resultPathBase, false, redirector); diffCursor - 1, url, webUrl, profileName+pathTail(diffMatches, 0), diffMatches.get(0).getPath(), outcome.getPath(), trimDifferential, contextName, resultPathBase, false, redirector);
} }
} else if (outcome.getType().get(0).getCode().equals("Extension")) { } else if (outcome.getType().get(0).getCode().equals("Extension")) {
// Force URL to appear if we're dealing with an extension. (This is a kludge - may need to drill down in other cases where we're slicing and the type has a profile declaration that could be setting the fixed value) // Force URL to appear if we're dealing with an extension. (This is a kludge - may need to drill down in other cases where we're slicing and the type has a profile declaration that could be setting the fixed value)
@ -945,7 +948,7 @@ public class ProfileUtilities extends TranslatingUtilities {
for (ElementDefinition extEd : dt.getSnapshot().getElement()) { for (ElementDefinition extEd : dt.getSnapshot().getElement()) {
// We only want the children that aren't the root // We only want the children that aren't the root
if (extEd.getPath().contains(".")) { if (extEd.getPath().contains(".")) {
ElementDefinition extUrlEd = updateURLs(url, extEd.copy()); ElementDefinition extUrlEd = updateURLs(url, webUrl, extEd.copy());
extUrlEd.setPath(fixedPathDest(outcome.getPath(), extUrlEd.getPath(), redirector, null)); extUrlEd.setPath(fixedPathDest(outcome.getPath(), extUrlEd.getPath(), redirector, null));
// updateFromBase(extUrlEd, currentBase); // updateFromBase(extUrlEd, currentBase);
markDerived(extUrlEd); markDerived(extUrlEd);
@ -1241,7 +1244,7 @@ public class ProfileUtilities extends TranslatingUtilities {
* @param element - the Element to update * @param element - the Element to update
* @return - the updated Element * @return - the updated Element
*/ */
private ElementDefinition updateURLs(String url, ElementDefinition element) { private ElementDefinition updateURLs(String url, String webUrl, ElementDefinition element) {
if (element != null) { if (element != null) {
ElementDefinition defn = element; ElementDefinition defn = element;
if (defn.hasBinding() && defn.getBinding().hasValueSet() && defn.getBinding().getValueSet().startsWith("#")) if (defn.hasBinding() && defn.getBinding().hasValueSet() && defn.getBinding().getValueSet().startsWith("#"))
@ -1256,10 +1259,48 @@ public class ProfileUtilities extends TranslatingUtilities {
u.setValue(url+t.getTargetProfile()); u.setValue(url+t.getTargetProfile());
} }
} }
if (webUrl != null) {
// also, must touch up the markdown
if (element.hasDefinition())
element.setDefinition(processRelativeUrls(element.getDefinition(), webUrl));
if (element.hasComment())
element.setComment(processRelativeUrls(element.getComment(), webUrl));
if (element.hasRequirements())
element.setRequirements(processRelativeUrls(element.getRequirements(), webUrl));
if (element.hasMeaningWhenMissing())
element.setMeaningWhenMissing(processRelativeUrls(element.getMeaningWhenMissing(), webUrl));
}
} }
return element; return element;
} }
private String processRelativeUrls(String markdown, String webUrl) {
StringBuilder b = new StringBuilder();
int i = 0;
while (i < markdown.length()) {
if (i < markdown.length()-3 && markdown.substring(i, i+2).equals("](")) {
int j = i + 2;
while (j < markdown.length() && markdown.charAt(j) != ')')
j++;
if (j < markdown.length()) {
String url = markdown.substring(i+2, j);
if (!Utilities.isAbsoluteUrl(url)) {
b.append("](");
b.append(webUrl);
i = i + 1;
} else
b.append(markdown.charAt(i));
} else
b.append(markdown.charAt(i));
} else {
b.append(markdown.charAt(i));
}
i++;
}
return b.toString();
}
private List<ElementDefinition> getSiblings(List<ElementDefinition> list, ElementDefinition current) { private List<ElementDefinition> getSiblings(List<ElementDefinition> list, ElementDefinition current) {
List<ElementDefinition> result = new ArrayList<ElementDefinition>(); List<ElementDefinition> result = new ArrayList<ElementDefinition>();
String path = current.getPath(); String path = current.getPath();
@ -1353,7 +1394,7 @@ public class ProfileUtilities extends TranslatingUtilities {
return false; return false;
} }
private List<ElementDefinition> getDiffMatches(StructureDefinitionDifferentialComponent context, String path, int start, int end, String profileName, String url) throws DefinitionException { private List<ElementDefinition> getDiffMatches(StructureDefinitionDifferentialComponent context, String path, int start, int end, String profileName) throws DefinitionException {
List<ElementDefinition> result = new ArrayList<ElementDefinition>(); List<ElementDefinition> result = new ArrayList<ElementDefinition>();
for (int i = start; i <= end; i++) { for (int i = start; i <= end; i++) {
String statedPath = context.getElement().get(i).getPath(); String statedPath = context.getElement().get(i).getPath();

View File

@ -582,7 +582,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
pu.sortDifferential(sd, p, p.getUrl(), errors); pu.sortDifferential(sd, p, p.getUrl(), errors);
for (String err : errors) for (String err : errors)
msgs.add(new ValidationMessage(Source.ProfileValidator, IssueType.EXCEPTION, p.getUserString("path"), "Error sorting Differential: "+err, ValidationMessage.IssueSeverity.ERROR)); msgs.add(new ValidationMessage(Source.ProfileValidator, IssueType.EXCEPTION, p.getUserString("path"), "Error sorting Differential: "+err, ValidationMessage.IssueSeverity.ERROR));
pu.generateSnapshot(sd, p, p.getUrl(), p.getName()); pu.generateSnapshot(sd, p, p.getUrl(), Utilities.extractBaseUrl(sd.getUserString("path")), p.getName());
for (ValidationMessage msg : msgs) { for (ValidationMessage msg : msgs) {
if ((!ignoreProfileErrors && msg.getLevel() == ValidationMessage.IssueSeverity.ERROR) || msg.getLevel() == ValidationMessage.IssueSeverity.FATAL) if ((!ignoreProfileErrors && msg.getLevel() == ValidationMessage.IssueSeverity.ERROR) || msg.getLevel() == ValidationMessage.IssueSeverity.FATAL)
throw new DefinitionException("Profile "+p.getName()+" ("+p.getUrl()+"). Error generating snapshot: "+msg.getMessage()); throw new DefinitionException("Profile "+p.getName()+" ("+p.getUrl()+"). Error generating snapshot: "+msg.getMessage());

View File

@ -43,7 +43,7 @@ public class ProfileUtilitiesTests {
focus.setType("Patient"); focus.setType("Patient");
focus.setDerivation(TypeDerivationRule.CONSTRAINT); focus.setDerivation(TypeDerivationRule.CONSTRAINT);
List<ValidationMessage> messages = new ArrayList<ValidationMessage>(); List<ValidationMessage> messages = new ArrayList<ValidationMessage>();
new ProfileUtilities(TestingUtilities.context(), messages, null).generateSnapshot(base, focus, focus.getUrl(), "Simple Test"); new ProfileUtilities(TestingUtilities.context(), messages, null).generateSnapshot(base, focus, focus.getUrl(), "http://test.org/test", "Simple Test");
boolean ok = base.getSnapshot().getElement().size() == focus.getSnapshot().getElement().size(); boolean ok = base.getSnapshot().getElement().size() == focus.getSnapshot().getElement().size();
for (int i = 0; i < base.getSnapshot().getElement().size(); i++) { for (int i = 0; i < base.getSnapshot().getElement().size(); i++) {
@ -86,7 +86,7 @@ public class ProfileUtilitiesTests {
focus.setSnapshot(null); focus.setSnapshot(null);
focus.setDifferential(null); focus.setDifferential(null);
List<ValidationMessage> messages = new ArrayList<ValidationMessage>(); List<ValidationMessage> messages = new ArrayList<ValidationMessage>();
new ProfileUtilities(TestingUtilities.context(), messages, null).generateSnapshot(base, focus, focus.getUrl(), "Simple Test" ); new ProfileUtilities(TestingUtilities.context(), messages, null).generateSnapshot(base, focus, focus.getUrl(), "http://test.org", "Simple Test" );
boolean ok = base.getSnapshot().getElement().size() == focus.getSnapshot().getElement().size(); boolean ok = base.getSnapshot().getElement().size() == focus.getSnapshot().getElement().size();
for (int i = 0; i < base.getSnapshot().getElement().size(); i++) { for (int i = 0; i < base.getSnapshot().getElement().size(); i++) {

View File

@ -311,7 +311,7 @@ public class SnapShotGenerationTests {
if (TestingUtilities.context().fetchResource(StructureDefinition.class, sd.getUrl()) == null) { if (TestingUtilities.context().fetchResource(StructureDefinition.class, sd.getUrl()) == null) {
sd.setUserData("path", "test-"+sd.getId()+".html"); sd.setUserData("path", "test-"+sd.getId()+".html");
StructureDefinition extd = TestingUtilities.context().fetchResource(StructureDefinition.class, sd.getBaseDefinition()); StructureDefinition extd = TestingUtilities.context().fetchResource(StructureDefinition.class, sd.getBaseDefinition());
new ProfileUtilities(TestingUtilities.context(), null, null).generateSnapshot(extd, sd, sd.getUrl(), sd.getName()); new ProfileUtilities(TestingUtilities.context(), null, null).generateSnapshot(extd, sd, sd.getUrl(), "http://test.org/extension", sd.getName());
TestingUtilities.context().cacheResource(sd); TestingUtilities.context().cacheResource(sd);
debugSaveResource(sd); debugSaveResource(sd);
} }
@ -346,7 +346,7 @@ public class SnapShotGenerationTests {
throw new FHIRException("Sort failed: "+errors.toString()); throw new FHIRException("Sort failed: "+errors.toString());
} }
pu.generateSnapshot(base, output, source.getUrl(), source.getName()); pu.generateSnapshot(base, output, source.getUrl(), "http://test.org/profile", source.getName());
debugSaveResource(output); debugSaveResource(output);
context.fixtures.put(op.getResponseId(), output); context.fixtures.put(op.getResponseId(), output);
context.snapshots.put(output.getUrl(), output); context.snapshots.put(output.getUrl(), output);
@ -439,7 +439,7 @@ public class SnapShotGenerationTests {
pu.sortDifferential(getSD(p.getBaseDefinition()), p, url, errors); pu.sortDifferential(getSD(p.getBaseDefinition()), p, url, errors);
if (!errors.isEmpty()) if (!errors.isEmpty())
throw new FHIRException(errors.get(0)); throw new FHIRException(errors.get(0));
pu.generateSnapshot(getSD(p.getBaseDefinition()), p, p.getUrl(), p.getName()); pu.generateSnapshot(getSD(p.getBaseDefinition()), p, p.getUrl(), "http://test.org/contained", p.getName());
debugSaveResource(p); debugSaveResource(p);
return p; return p;
} }

View File

@ -1148,5 +1148,13 @@ public class Utilities {
} }
} }
public static String extractBaseUrl(String url) {
if (url.contains("/"))
return url.substring(0, url.lastIndexOf("/"));
else
return url;
}
} }

View File

@ -1015,7 +1015,7 @@ public class ValidationEngine {
StructureDefinition sd = (StructureDefinition) res; StructureDefinition sd = (StructureDefinition) res;
StructureDefinition base = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition()); StructureDefinition base = context.fetchResource(StructureDefinition.class, sd.getBaseDefinition());
new ProfileUtilities(context, null, null).generateSnapshot(base, sd, sd.getUrl(), sd.getName()); new ProfileUtilities(context, null, null).generateSnapshot(base, sd, sd.getUrl(), null, sd.getName());
return sd; return sd;
} }

View File

@ -161,7 +161,7 @@ public class ValidationTestSuite implements IEvaluationContext, IValidatorResour
if (!sd.hasSnapshot()) { if (!sd.hasSnapshot()) {
ProfileUtilities pu = new ProfileUtilities(TestingUtilities.context(), null, null); ProfileUtilities pu = new ProfileUtilities(TestingUtilities.context(), null, null);
StructureDefinition base = TestingUtilities.context().fetchResource(StructureDefinition.class, sd.getBaseDefinition()); StructureDefinition base = TestingUtilities.context().fetchResource(StructureDefinition.class, sd.getBaseDefinition());
pu.generateSnapshot(base, sd, sd.getUrl(), sd.getTitle()); pu.generateSnapshot(base, sd, sd.getUrl(), null, sd.getTitle());
// (debugging) new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path("[tmp]", sd.getId()+".xml")), sd); // (debugging) new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path("[tmp]", sd.getId()+".xml")), sd);
} }
return sd; return sd;