diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/AdditionalBindingsRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/AdditionalBindingsRenderer.java index f4cf40a0b..dcbe9e08b 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/AdditionalBindingsRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/conformance/AdditionalBindingsRenderer.java @@ -2,6 +2,7 @@ package org.hl7.fhir.r5.conformance; import java.io.IOException; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import org.hl7.fhir.exceptions.DefinitionException; @@ -32,10 +33,46 @@ public class AdditionalBindingsRenderer { private String doco; private String docoShort; private UsageContext usage; - private boolean any; - private boolean unchanged; + private boolean any = false; + private boolean isUnchanged = false; + private boolean matched = false; + private boolean removed = false; + private AdditionalBindingDetail compare; + private int count = 1; + private String getKey() { + // Todo: Consider extending this with content from usageContext if purpose isn't sufficiently differentiating + return purpose + Integer.toString(count); + } + private void incrementCount() { + count++; + } + private void setCompare(AdditionalBindingDetail match) { + compare = match; + match.matched = true; + } + private boolean alreadyMatched() { + return matched; + } + public String getDoco(boolean full) { + return full ? doco : docoShort; + } + public boolean unchanged() { + if (!isUnchanged) + return false; + if (compare==null) + return true; + isUnchanged = true; + isUnchanged = isUnchanged && ((purpose==null && compare.purpose==null) || purpose.equals(compare.purpose)); + isUnchanged = isUnchanged && ((valueSet==null && compare.valueSet==null) || valueSet.equals(compare.valueSet)); + isUnchanged = isUnchanged && ((doco==null && compare.doco==null) || doco.equals(compare.doco)); + isUnchanged = isUnchanged && ((usage==null && compare.usage==null) || usage.equals(compare.usage)); + return isUnchanged; + } } + private static String STYLE_UNCHANGED = "opacity: 0.5;"; + private static String STYLE_REMOVED = STYLE_UNCHANGED + "text-decoration: line-through;"; + private List bindings = new ArrayList<>(); private ProfileKnowledgeProvider pkp; private String corePath; @@ -53,35 +90,87 @@ public class AdditionalBindingsRenderer { this.md = md; } - public void seeMaxBinding(Extension ext) { + public void seeMaxBinding(Extension ext) { + seeMaxBinding(ext, null, false); + } + + public void seeMaxBinding(Extension ext, Extension compExt, boolean compare) { + seeBinding(ext, compExt, compare, "maximum"); + } + + protected void seeBinding(Extension ext, Extension compExt, boolean compare, String label) { AdditionalBindingDetail abr = new AdditionalBindingDetail(); - abr.purpose = "maximum"; + abr.purpose = label; abr.valueSet = ext.getValue().primitiveValue(); - abr.unchanged = ext.hasUserData(ProfileUtilities.DERIVATION_EQUALS); - bindings.add(abr); + if (compare) { + abr.isUnchanged = compExt!=null && ext.getValue().primitiveValue().equals(compExt.getValue().primitiveValue()); + + abr.compare = new AdditionalBindingDetail(); + abr.compare.valueSet = compExt==null ? null : compExt.getValue().primitiveValue(); + } else { + abr.isUnchanged = ext.hasUserData(ProfileUtilities.DERIVATION_EQUALS); + } + bindings.add(abr); } public void seeMinBinding(Extension ext) { - AdditionalBindingDetail abr = new AdditionalBindingDetail(); - abr.purpose = "minimum"; - abr.valueSet = ext.getValue().primitiveValue(); - abr.unchanged = ext.hasUserData(ProfileUtilities.DERIVATION_EQUALS); - bindings.add(abr); + seeMinBinding(ext, null, false); + } + + public void seeMinBinding(Extension ext, Extension compExt, boolean compare) { + seeBinding(ext, compExt, compare, "minimum"); } public void seeAdditionalBindings(List list) { - for (Extension ext : list) { - AdditionalBindingDetail abr = new AdditionalBindingDetail(); - abr.purpose = ext.getExtensionString("purpose"); - abr.valueSet = ext.getExtensionString("valueSet"); - abr.doco = ext.getExtensionString("documentation"); - abr.docoShort = ext.getExtensionString("shortDoco"); - abr.usage = (ext.hasExtension("usage")) && ext.getExtensionByUrl("usage").hasValueUsageContext() ? ext.getExtensionByUrl("usage").getValueUsageContext() : null; - abr.any = "any".equals(ext.getExtensionString("scope")); - abr.unchanged = ext.hasUserData(ProfileUtilities.DERIVATION_EQUALS); - bindings.add(abr); + seeAdditionalBindings(list, null, false); + } + + public void seeAdditionalBindings(List list, List compList, boolean compare) { + HashMap compBindings = new HashMap(); + if (compare && compList!=null) { + for (Extension ext : compList) { + AdditionalBindingDetail abr = additionalBinding(ext); + if (compBindings.containsKey(abr.getKey())) { + abr.incrementCount(); + } + compBindings.put(abr.getKey(), abr); + } } - } + + for (Extension ext : list) { + AdditionalBindingDetail abr = additionalBinding(ext); + if (compare && compList!=null) { + AdditionalBindingDetail match = null; + do { + match = compBindings.get(abr.getKey()); + if (abr.alreadyMatched()) + abr.incrementCount(); + } while (match!=null && abr.alreadyMatched()); + if (match!=null) + abr.setCompare(match); + bindings.add(abr); + if (abr.compare!=null) + compBindings.remove(abr.compare.getKey()); + } else + bindings.add(abr); + } + for (AdditionalBindingDetail b: compBindings.values()) { + b.removed = true; + bindings.add(b); + } + } + + protected AdditionalBindingDetail additionalBinding(Extension ext) { + AdditionalBindingDetail abr = new AdditionalBindingDetail(); + abr.purpose = ext.getExtensionString("purpose"); + abr.valueSet = ext.getExtensionString("valueSet"); + abr.doco = ext.getExtensionString("documentation"); + abr.docoShort = ext.getExtensionString("shortDoco"); + abr.usage = (ext.hasExtension("usage")) && ext.getExtensionByUrl("usage").hasValueUsageContext() ? ext.getExtensionByUrl("usage").getValueUsageContext() : null; + abr.any = "any".equals(ext.getExtensionString("scope")); + abr.isUnchanged = ext.hasUserData(ProfileUtilities.DERIVATION_EQUALS); + return abr; + } public String render() throws IOException { if (bindings.isEmpty()) { @@ -109,12 +198,11 @@ public class AdditionalBindingsRenderer { boolean usage = false; boolean any = false; for (AdditionalBindingDetail binding : bindings) { - doco = doco || (fullDoco && binding.doco != null) || (!fullDoco && binding.docoShort != null) ; - usage = usage || binding.usage != null; - any = any || binding.any; + doco = doco || binding.getDoco(fullDoco)!=null || (binding.compare!=null && binding.compare.getDoco(fullDoco)!=null); + usage = usage || binding.usage != null || (binding.compare!=null && binding.compare.usage!=null); + any = any || binding.any || (binding.compare!=null && binding.compare.any); } - XhtmlNode tr = new XhtmlNode(NodeType.Element, "tr"); children.add(tr); tr.td().style("font-size: 11px").b().tx("Additional Bindings"); @@ -130,37 +218,62 @@ public class AdditionalBindingsRenderer { } for (AdditionalBindingDetail binding : bindings) { tr = new XhtmlNode(NodeType.Element, "tr"); - if (binding.unchanged) { - tr.style("opacity: 0.5"); + if (binding.unchanged()) { + tr.style(STYLE_REMOVED); + } else if (binding.removed) { + tr.style(STYLE_REMOVED); } children.add(tr); BindingResolution br = pkp == null ? makeNullBr(binding) : pkp.resolveBinding(profile, binding.valueSet, path); + BindingResolution compBr = null; + if (binding.compare!=null && binding.compare.valueSet!=null) + compBr = pkp == null ? makeNullBr(binding.compare) : pkp.resolveBinding(profile, binding.compare.valueSet, path); + XhtmlNode valueset = tr.td().style("font-size: 11px"); + if (binding.compare!=null && binding.valueSet.equals(binding.compare.valueSet)) + valueset.style(STYLE_UNCHANGED); if (br.url != null) { - tr.td().style("font-size: 11px").ah(Utilities.isAbsoluteUrl(br.url) || !pkp.prependLinks() ? br.url : corePath+br.url, binding.valueSet).tx(br.display); + valueset.ah(determineUrl(br.url), binding.valueSet).tx(br.display); } else { - tr.td().style("font-size: 11px").span(null, binding.valueSet).tx(br.display); + valueset.span(null, binding.valueSet).tx(br.display); + } + if (binding.compare!=null && binding.compare.valueSet!=null && !binding.valueSet.equals(binding.compare.valueSet)) { + valueset.br(); + valueset = valueset.span(STYLE_REMOVED, null); + if (compBr.url != null) { + valueset.ah(determineUrl(compBr.url), binding.compare.valueSet).tx(compBr.display); + } else { + valueset.span(null, binding.compare.valueSet).tx(compBr.display); + } + } + + XhtmlNode purpose = tr.td().style("font-size: 11px"); + if (binding.compare!=null && binding.purpose.equals(binding.compare.purpose)) + purpose.style("font-color: darkgray"); + renderPurpose(purpose, binding.purpose); + if (binding.compare!=null && binding.compare.purpose!=null && !binding.purpose.equals(binding.compare.purpose)) { + purpose.br(); + purpose = purpose.span(STYLE_UNCHANGED, null); + renderPurpose(purpose, binding.compare.purpose); } - renderPurpose(tr.td().style("font-size: 11px"), binding.purpose); if (usage) { if (binding.usage != null) { + // TODO: This isn't rendered at all yet. Ideally, we want it to render with comparison... new DataRenderer(context).render(tr.td(), binding.usage); } else { tr.td(); } } if (any) { - if (binding.any) { - tr.td().style("font-size: 11px").tx("Any repeat"); - } else { - tr.td().style("font-size: 11px").tx("All repeats"); - } + String newRepeat = binding.any ? "Any repeats" : "All repeats"; + String oldRepeat = binding.compare!=null && binding.compare.any ? "Any repeats" : "All repeats"; + compareString(tr.td().style("font-size: 11px"), newRepeat, oldRepeat); } if (doco) { - String ds = fullDoco ? binding.doco : binding.docoShort; - if (ds != null) { - String d = fullDoco ? md.processMarkdown("Binding.description", ds) : ds; - tr.td().style("font-size: 11px").innerHTML(d); + if (binding.doco != null) { + String d = md.processMarkdown("Binding.description", fullDoco ? binding.doco : binding.docoShort); + String oldD = binding.compare==null ? null : md.processMarkdown("Binding.description.compare", fullDoco ? binding.compare.doco : binding.compare.docoShort); + tr.td().style("font-size: 11px").innerHTML(compareHtml(d, oldD)); } else { tr.td().style("font-size: 11px"); } @@ -168,6 +281,28 @@ public class AdditionalBindingsRenderer { } } + private XhtmlNode compareString(XhtmlNode node, String newS, String oldS) { + if (oldS==null) + return node.tx(newS); + if (newS.equals(oldS)) + return node.style(STYLE_UNCHANGED).tx(newS); + node.tx(newS); + node.br(); + return node.span(STYLE_REMOVED,null).tx(oldS); + } + + private String compareHtml(String newS, String oldS) { + if (oldS==null) + return newS; + if (newS.equals(oldS)) + return "" + newS + ""; + return newS + "
" + oldS + ""; + } + + private String determineUrl(String url) { + return Utilities.isAbsoluteUrl(url) || !pkp.prependLinks() ? url : corePath + url; + } + private void renderPurpose(XhtmlNode td, String purpose) { switch (purpose) { case "maximum": 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 c6090619f..b79e31157 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 @@ -325,7 +325,8 @@ public class ProfileUtilities extends TranslatingUtilities { public static final int STATUS_ERROR = 3; public static final int STATUS_FATAL = 4; - + public static final String BASE_MODEL = "base.model"; + public static final String BASE_PATH = "base.path"; public static final String DERIVATION_EQUALS = "derivation.equals"; public static final String DERIVATION_POINTER = "derived.pointer"; public static final String IS_DERIVED = "derived.fact"; @@ -430,8 +431,6 @@ public class ProfileUtilities extends TranslatingUtilities { String getLinkForUrl(String corePath, String s); } - - public List getChildMap(StructureDefinition profile, ElementDefinition element) throws DefinitionException { if (childMapCache .containsKey(element)) { return childMapCache.get(element); @@ -504,7 +503,7 @@ public class ProfileUtilities extends TranslatingUtilities { /** * Given a Structure, navigate to the element given by the path and return the direct children of that element * - * @param structure The structure to navigate into + * @param profile The structure to navigate into * @param path The path of the element within the structure to get the children for * @return A List containing the element children (all of them are Elements) */ @@ -615,10 +614,9 @@ public class ProfileUtilities extends TranslatingUtilities { * Given a base (snapshot) profile structure, and a differential profile, generate a new snapshot profile * * @param base - the base structure on which the differential will be applied - * @param differential - the differential to apply to the base + * @param derived - 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 (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 * @return * @throws FHIRException * @throws DefinitionException @@ -1142,7 +1140,7 @@ public class ProfileUtilities extends TranslatingUtilities { // so we just copy it in ElementDefinition outcome = updateURLs(url, webUrl, currentBase.copy()); outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); - updateFromBase(outcome, currentBase); + updateFromBase(outcome, currentBase, srcSD.getUrl()); updateConstraintSources(outcome, srcSD.getUrl()); markDerived(outcome); if (resultPathBase == null) @@ -1289,7 +1287,7 @@ public class ProfileUtilities extends TranslatingUtilities { outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); if (res == null) res = outcome; - updateFromBase(outcome, currentBase); + updateFromBase(outcome, currentBase, srcSD.getUrl()); 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()) { @@ -1552,7 +1550,7 @@ public class ProfileUtilities extends TranslatingUtilities { // we're just going to accept the differential slicing at face value ElementDefinition outcome = updateURLs(url, webUrl, currentBase.copy()); outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); - updateFromBase(outcome, currentBase); + updateFromBase(outcome, currentBase, srcSD.getUrl()); if (!diffMatches.get(0).hasSlicing()) outcome.setSlicing(makeExtensionSlicing()); @@ -1627,7 +1625,7 @@ public class ProfileUtilities extends TranslatingUtilities { // so we just copy it in ElementDefinition outcome = updateURLs(url, webUrl, currentBase.copy()); outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); - updateFromBase(outcome, currentBase); + updateFromBase(outcome, currentBase, srcSD.getUrl()); markDerived(outcome); if (resultPathBase == null) resultPathBase = outcome.getPath(); @@ -1664,6 +1662,8 @@ public class ProfileUtilities extends TranslatingUtilities { if (!outcome.getPath().startsWith(resultPathBase)) throw new DefinitionException(context.formatMessage(I18nConstants.ADDING_WRONG_PATH_IN_PROFILE___VS_, profileName, outcome.getPath(), resultPathBase)); result.getElement().add(outcome); // so we just copy it in + outcome.setUserData(BASE_MODEL, srcSD.getUrl()); + outcome.setUserData(BASE_PATH, resultPathBase); baseCursor++; } } @@ -1824,7 +1824,7 @@ public class ProfileUtilities extends TranslatingUtilities { } ElementDefinition outcome = updateURLs(url, webUrl, currentBase.copy()); outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); - updateFromBase(outcome, currentBase); + updateFromBase(outcome, currentBase, srcSD.getUrl()); if (diffMatches.get(0).hasSlicing() || !diffMatches.get(0).hasSliceName()) { updateFromSlicing(outcome.getSlicing(), diffMatches.get(0).getSlicing()); updateFromDefinition(outcome, diffMatches.get(0), profileName, closed, url, srcSD); // if there's no slice, we don't want to update the unsliced description @@ -1876,7 +1876,7 @@ public class ProfileUtilities extends TranslatingUtilities { for (ElementDefinition baseItem : baseMatches) { baseCursor = base.getElement().indexOf(baseItem); outcome = updateURLs(url, webUrl, baseItem.copy()); - updateFromBase(outcome, currentBase); + updateFromBase(outcome, currentBase, srcSD.getUrl()); outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); outcome.setSlicing(null); if (!outcome.getPath().startsWith(resultPathBase)) @@ -1903,6 +1903,8 @@ public class ProfileUtilities extends TranslatingUtilities { outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); if (!outcome.getPath().startsWith(resultPathBase)) throw new DefinitionException(context.formatMessage(I18nConstants.ADDING_WRONG_PATH)); + outcome.setUserData(BASE_PATH, outcome.getPath()); + outcome.setUserData(BASE_MODEL, srcSD.getUrl()); result.getElement().add(outcome); baseCursor++; } @@ -1932,7 +1934,7 @@ public class ProfileUtilities extends TranslatingUtilities { outcome = updateURLs(url, webUrl, currentBase.copy()); // outcome = updateURLs(url, diffItem.copy()); outcome.setPath(fixedPathDest(contextPathDst, outcome.getPath(), redirector, contextPathSrc)); - updateFromBase(outcome, currentBase); + updateFromBase(outcome, currentBase, srcSD.getUrl()); outcome.setSlicing(null); 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)) @@ -2439,7 +2441,9 @@ public class ProfileUtilities extends TranslatingUtilities { } - private void updateFromBase(ElementDefinition derived, ElementDefinition base) { + private void updateFromBase(ElementDefinition derived, ElementDefinition base, String baseProfileUrl) { + derived.setUserData(BASE_MODEL, baseProfileUrl); + derived.setUserData(BASE_PATH, base.getPath()); if (base.hasBase()) { if (!derived.hasBase()) derived.setBase(new ElementDefinitionBaseComponent()); @@ -3535,7 +3539,7 @@ public class ProfileUtilities extends TranslatingUtilities { if (!child.getPath().endsWith(".id")) { List sdl = new ArrayList<>(); sdl.add(ed); - genElement(defFile == null ? "" : defFile+"-definitions.html#extension.", gen, r.getSubRows(), child, ed.getSnapshot().getElement(), sdl, true, defFile, true, full, corePath, imagePath, true, false, false, false, null, false, rc); + genElement(defFile == null ? "" : defFile+"-definitions.html#extension.", gen, r.getSubRows(), child, ed.getSnapshot().getElement(), sdl, true, defFile, true, full, corePath, imagePath, true, false, false, false, null, false, rc, ""); } } else if (deep) { List children = new ArrayList(); @@ -4016,19 +4020,14 @@ public class ProfileUtilities extends TranslatingUtilities { return piece; } - public XhtmlNode generateTable(String defFile, StructureDefinition profile, boolean diff, String imageFolder, boolean inlineGraphics, String profileBaseFileName, boolean snapshot, String corePath, String imagePath, - boolean logicalModel, boolean allInvariants, Set outputTracker, boolean active, boolean mustSupport, RenderingContext rc) throws IOException, FHIRException { - assert(diff != snapshot);// check it's ok to get rid of one of these - HierarchicalTableGenerator gen = new HierarchicalTableGenerator(imageFolder, inlineGraphics, true); - gen.setTranslator(getTranslator()); - TableModel model = gen.initNormalTable(corePath, false, true, profile.getId()+(diff ? "d" : "s"), active); + public XhtmlNode generateTable(String defFile, StructureDefinition profile, boolean diff, String imageFolder, boolean inlineGraphics, String profileBaseFileName, boolean snapshot, String corePath, String imagePath, + boolean logicalModel, boolean allInvariants, Set outputTracker, boolean active, boolean mustSupport, RenderingContext rc) throws IOException, FHIRException { + return generateTable(defFile, profile, diff, imageFolder, inlineGraphics, profileBaseFileName, snapshot, corePath, imagePath, logicalModel, allInvariants, outputTracker, active, mustSupport, rc, ""); + } + + public List supplementMissingDiffElements(StructureDefinition profile) { List list = new ArrayList<>(); - if (diff) - list.addAll(profile.getDifferential().getElement()); - else - list.addAll(profile.getSnapshot().getElement()); - List profiles = new ArrayList(); - profiles.add(profile); + list.addAll(profile.getDifferential().getElement()); if (list.isEmpty()) { ElementDefinition root = new ElementDefinition().setPath(profile.getType()); root.setId(profile.getType()); @@ -4040,10 +4039,27 @@ public class ProfileUtilities extends TranslatingUtilities { list.add(0, root); } } - if (diff) { - insertMissingSparseElements(list); + insertMissingSparseElements(list); + return list; + } + + public XhtmlNode generateTable(String defFile, StructureDefinition profile, boolean diff, String imageFolder, boolean inlineGraphics, String profileBaseFileName, boolean snapshot, String corePath, String imagePath, + boolean logicalModel, boolean allInvariants, Set outputTracker, boolean active, boolean mustSupport, RenderingContext rc, String anchorPrefix) throws IOException, FHIRException { + assert(diff != snapshot);// check it's ok to get rid of one of these + HierarchicalTableGenerator gen = new HierarchicalTableGenerator(imageFolder, inlineGraphics, true); + gen.setTranslator(getTranslator()); + TableModel model = gen.initNormalTable(corePath, false, true, profile.getId()+(diff ? "d" : "s"), active); + List list; + if (diff) + list = supplementMissingDiffElements(profile); + else { + list = new ArrayList<>(); + list.addAll(profile.getSnapshot().getElement()); } - genElement(defFile == null ? null : defFile+"#", gen, model.getRows(), list.get(0), list, profiles, diff, profileBaseFileName, null, snapshot, corePath, imagePath, true, logicalModel, profile.getDerivation() == TypeDerivationRule.CONSTRAINT && usesMustSupport(list), allInvariants, null, mustSupport, rc); + List profiles = new ArrayList(); + profiles.add(profile); + + genElement(defFile == null ? null : defFile+"#", gen, model.getRows(), list.get(0), list, profiles, diff, profileBaseFileName, null, snapshot, corePath, imagePath, true, logicalModel, profile.getDerivation() == TypeDerivationRule.CONSTRAINT && usesMustSupport(list), allInvariants, null, mustSupport, rc, anchorPrefix); try { return gen.generate(model, imagePath, 0, outputTracker); } catch (org.hl7.fhir.exceptions.FHIRException e) { @@ -4139,7 +4155,7 @@ public class ProfileUtilities extends TranslatingUtilities { private Row genElement(String defPath, HierarchicalTableGenerator gen, List rows, ElementDefinition element, List all, List profiles, boolean showMissing, String profileBaseFileName, Boolean extensions, - boolean snapshot, String corePath, String imagePath, boolean root, boolean logicalModel, boolean isConstraintMode, boolean allInvariants, Row slicingRow, boolean mustSupport, RenderingContext rc) throws IOException, FHIRException { + boolean snapshot, String corePath, String imagePath, boolean root, boolean logicalModel, boolean isConstraintMode, boolean allInvariants, Row slicingRow, boolean mustSupport, RenderingContext rc, String anchorPrefix) throws IOException, FHIRException { Row originalRow = slicingRow; StructureDefinition profile = profiles == null ? null : profiles.get(profiles.size()-1); Row typesRow = null; @@ -4201,7 +4217,7 @@ public class ProfileUtilities extends TranslatingUtilities { row.setOpacity("0.5"); } UnusedTracker used = new UnusedTracker(); - String ref = defPath == null ? null : defPath + element.getId(); + String ref = defPath == null ? null : defPath + anchorPrefix + element.getId(); String sName = tail(element.getPath()); if (element.hasSliceName()) sName = sName +":"+element.getSliceName(); @@ -4276,7 +4292,7 @@ public class ProfileUtilities extends TranslatingUtilities { Row childRow = chooseChildRowByGroup(gen, currRow, groups, child, element, isConstraintMode); if (logicalModel || !child.getPath().endsWith(".id") || (child.getPath().endsWith(".id") && (profile != null) && (profile.getDerivation() == TypeDerivationRule.CONSTRAINT))) { - currRow = genElement(defPath, gen, childRow.getSubRows(), child, all, profiles, showMissing, profileBaseFileName, isExtension, snapshot, corePath, imagePath, false, logicalModel, isConstraintMode, allInvariants, currRow, mustSupport, rc); + currRow = genElement(defPath, gen, childRow.getSubRows(), child, all, profiles, showMissing, profileBaseFileName, isExtension, snapshot, corePath, imagePath, false, logicalModel, isConstraintMode, allInvariants, currRow, mustSupport, rc, anchorPrefix); } } } diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureDefinitionRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureDefinitionRenderer.java index 480686c89..a5962056e 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureDefinitionRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/StructureDefinitionRenderer.java @@ -28,7 +28,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { } public boolean render(XhtmlNode x, StructureDefinition sd) throws FHIRFormatError, DefinitionException, IOException { - x.getChildNodes().add(context.getProfileUtilities().generateTable(context.getDefinitionsTarget(), sd, true, context.getDestDir(), false, sd.getId(), false, context.getSpecificationLink(), "", false, false, null, false, false, context)); + x.getChildNodes().add(context.getProfileUtilities().generateTable(context.getDefinitionsTarget(), sd, true, context.getDestDir(), false, sd.getId(), false, context.getSpecificationLink(), "", false, false, null, false, false, context, "")); return true; }