diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/CanonicalResourceComparer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/CanonicalResourceComparer.java index b3ab7b120..970940f16 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/CanonicalResourceComparer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/CanonicalResourceComparer.java @@ -592,7 +592,7 @@ public abstract class CanonicalResourceComparer extends ResourceComparer { public XhtmlNode renderMetadata(CanonicalResourceComparison comparison, String id, String prefix) throws FHIRException, IOException { // columns: code, display (left|right), properties (left|right) - HierarchicalTableGenerator gen = new HierarchicalTableGenerator(new RenderingI18nContext(), Utilities.path("[tmp]", "compare"), false); + HierarchicalTableGenerator gen = new HierarchicalTableGenerator(new RenderingI18nContext(), Utilities.path("[tmp]", "compare"), false, "c"); TableModel model = gen.new TableModel(id, true); model.setAlternating(true); model.getTitles().add(gen.new Title(null, null, "Name", "Property Name", null, 100)); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/CapabilityStatementComparer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/CapabilityStatementComparer.java index 76184d9d0..27ff1cba3 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/CapabilityStatementComparer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/CapabilityStatementComparer.java @@ -743,7 +743,7 @@ public class CapabilityStatementComparer extends CanonicalResourceComparer { // 6 columns: path | left value | left doco | right value | right doco | comments public XhtmlNode renderStatements(CapabilityStatementComparison comparison, String id, String prefix) throws FHIRException, IOException { - HierarchicalTableGenerator gen = new HierarchicalTableGenerator(new RenderingI18nContext(), Utilities.path("[tmp]", "compare"), false); + HierarchicalTableGenerator gen = new HierarchicalTableGenerator(new RenderingI18nContext(), Utilities.path("[tmp]", "compare"), false, "c"); TableModel model = gen.new TableModel(id, true); model.setAlternating(true); model.getTitles().add(gen.new Title(null, null, "Type", "The type of item", null, 100)); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/CodeSystemComparer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/CodeSystemComparer.java index 4a4a9cd22..38cbf1068 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/CodeSystemComparer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/CodeSystemComparer.java @@ -520,7 +520,7 @@ public class CodeSystemComparer extends CanonicalResourceComparer { public XhtmlNode renderConcepts(CodeSystemComparison comparison, String id, String prefix) throws FHIRException, IOException { // columns: code, display (left|right), properties (left|right) - HierarchicalTableGenerator gen = new HierarchicalTableGenerator(new RenderingI18nContext(), Utilities.path("[tmp]", "compare"), false); + HierarchicalTableGenerator gen = new HierarchicalTableGenerator(new RenderingI18nContext(), Utilities.path("[tmp]", "compare"), false, "c"); TableModel model = gen.new TableModel(id, true); model.setAlternating(true); model.getTitles().add(gen.new Title(null, null, "Code", "The code for the concept", null, 100)); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/StructureDefinitionComparer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/StructureDefinitionComparer.java index 494be7d56..b935e8eef 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/StructureDefinitionComparer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/StructureDefinitionComparer.java @@ -1252,7 +1252,7 @@ public class StructureDefinitionComparer extends CanonicalResourceComparer imple } public XhtmlNode renderStructure(ProfileComparison comp, String id, String prefix, String corePath) throws FHIRException, IOException { - HierarchicalTableGenerator gen = new HierarchicalTableGenerator(session.getI18n(), Utilities.path("[tmp]", "compare"), false, true); + HierarchicalTableGenerator gen = new HierarchicalTableGenerator(session.getI18n(), Utilities.path("[tmp]", "compare"), false, true, "cmp"); TableModel model = gen.initComparisonTable(corePath, id); genElementComp(null /* come back to this later */, null /* come back to this later */, gen, model.getRows(), comp.combined, corePath, prefix, null, true); return gen.generate(model, prefix, 0, null); @@ -1260,13 +1260,13 @@ public class StructureDefinitionComparer extends CanonicalResourceComparer imple public XhtmlNode renderUnion(ProfileComparison comp, String id, String prefix, String corePath) throws FHIRException, IOException { StructureDefinitionRenderer sdr = new StructureDefinitionRenderer(new RenderingContext(utilsLeft.getContext(), null, utilsLeft.getTerminologyServiceOptions(), corePath, prefix, null, ResourceRendererMode.TECHNICAL, GenerationRules.IG_PUBLISHER).setPkp(this)); - return sdr.generateTable(new RenderingStatus(), corePath, comp.union, false, prefix, false, id, true, corePath, prefix, false, true, null, false, sdr.getContext(), "u", null); + return sdr.generateTable(new RenderingStatus(), corePath, comp.union, false, prefix, false, id, true, corePath, prefix, false, true, null, false, sdr.getContext().withUniqueLocalPrefix("u"), "u", null); } public XhtmlNode renderIntersection(ProfileComparison comp, String id, String prefix, String corePath) throws FHIRException, IOException { StructureDefinitionRenderer sdr = new StructureDefinitionRenderer(new RenderingContext(utilsLeft.getContext(), null, utilsLeft.getTerminologyServiceOptions(), corePath, prefix, null, ResourceRendererMode.TECHNICAL, GenerationRules.IG_PUBLISHER).setPkp(this)); - return sdr.generateTable(new RenderingStatus(), corePath, comp.intersection, false, prefix, false, id, true, corePath, prefix, false, true, null, false, sdr.getContext(), "i", null); + return sdr.generateTable(new RenderingStatus(), corePath, comp.intersection, false, prefix, false, id, true, corePath, prefix, false, true, null, false, sdr.getContext().withUniqueLocalPrefix("i"), "i", null); } private void genElementComp(String defPath, String anchorPrefix, HierarchicalTableGenerator gen, List rows, StructuralMatch combined, String corePath, String prefix, Row slicingRow, boolean root) throws IOException { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ValueSetComparer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ValueSetComparer.java index a5f8126a0..9fb1fe6fa 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ValueSetComparer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/comparison/ValueSetComparer.java @@ -589,7 +589,7 @@ public class ValueSetComparer extends CanonicalResourceComparer { } public XhtmlNode renderCompose(ValueSetComparison csc, String id, String prefix) throws FHIRException, IOException { - HierarchicalTableGenerator gen = new HierarchicalTableGenerator(new RenderingI18nContext(), Utilities.path("[tmp]", "comparison"), false); + HierarchicalTableGenerator gen = new HierarchicalTableGenerator(new RenderingI18nContext(), Utilities.path("[tmp]", "comparison"), false, "c"); TableModel model = gen.new TableModel(id, true); model.setAlternating(true); model.getTitles().add(gen.new Title(null, null, "Item", "The type of item being compared", null, 100)); @@ -780,7 +780,7 @@ public class ValueSetComparer extends CanonicalResourceComparer { boolean hasAbstract = findAbstract(csc.getExpansion()); boolean hasInactive = findInactive(csc.getExpansion()); - HierarchicalTableGenerator gen = new HierarchicalTableGenerator(new RenderingI18nContext(), Utilities.path("[tmp]", "comparison"), false); + HierarchicalTableGenerator gen = new HierarchicalTableGenerator(new RenderingI18nContext(), Utilities.path("[tmp]", "comparison"), false, "c"); TableModel model = gen.new TableModel(id, true); model.setAlternating(true); if (hasSystem) { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/BundleRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/BundleRenderer.java index af90a1187..09eff7d09 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/BundleRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/BundleRenderer.java @@ -61,16 +61,15 @@ public class BundleRenderer extends ResourceRenderer { i++; if (i >= start) { if (be.has("fullUrl")) { - root.an(context.prefixAnchor(makeInternalBundleLink(be.primitiveValue("fullUrl")))); + root.an(context.prefixAnchor(makeInternalBundleLink(b, be.primitiveValue("fullUrl")))); } if (be.has("resource")) { - if (be.child("resource").has("id")) { - root.an(context.prefixAnchor(be.child("resource").fhirType() + "_" + be.child("resource").primitiveValue("id"))); - root.an(context.prefixAnchor("hc"+be.child("resource").fhirType() + "_" + be.child("resource").primitiveValue("id"))); - } else { - String id = makeIdFromBundleEntry(be.primitiveValue("fullUrl")); - root.an(context.prefixAnchor(be.child("resource").fhirType() + "_" + id)); - root.an(context.prefixAnchor("hc"+be.child("resource").fhirType() + "_" + id)); + String id = be.child("resource").has("id") ? be.child("resource").primitiveValue("id") : makeIdFromBundleEntry(be.primitiveValue("fullUrl")); + String anchor = be.child("resource").fhirType() + "_" + id; + if (id != null && !context.hasAnchor(anchor)) { + context.addAnchor(anchor); + root.an(context.prefixAnchor(anchor)); + root.an(context.prefixAnchor("hc"+anchor)); } } root.hr(); @@ -237,31 +236,31 @@ public class BundleRenderer extends ResourceRenderer { return !b.getEntry().isEmpty(); } - private List checkInternalLinks(Bundle b, List childNodes) { - scanNodesForInternalLinks(b, childNodes); - return childNodes; - } - - private void scanNodesForInternalLinks(Bundle b, List nodes) { - for (XhtmlNode n : nodes) { - if ("a".equals(n.getName()) && n.hasAttribute("href")) { - scanInternalLink(b, n); - } - scanNodesForInternalLinks(b, n.getChildNodes()); - } - } - - private void scanInternalLink(Bundle b, XhtmlNode n) { - boolean fix = false; - for (BundleEntryComponent be : b.getEntry()) { - if (be.hasFullUrl() && be.getFullUrl().equals(n.getAttribute("href"))) { - fix = true; - } - } - if (fix) { - n.setAttribute("href", "#"+makeInternalBundleLink(n.getAttribute("href"))); - } - } +// private List checkInternalLinks(Bundle b, List childNodes) { +// scanNodesForInternalLinks(b, childNodes); +// return childNodes; +// } +// +// private void scanNodesForInternalLinks(Bundle b, List nodes) { +// for (XhtmlNode n : nodes) { +// if ("a".equals(n.getName()) && n.hasAttribute("href")) { +// scanInternalLink(b, n); +// } +// scanNodesForInternalLinks(b, n.getChildNodes()); +// } +// } +// +// private void scanInternalLink(Bundle b, XhtmlNode n) { +// boolean fix = false; +// for (BundleEntryComponent be : b.getEntry()) { +// if (be.hasFullUrl() && be.getFullUrl().equals(n.getAttribute("href"))) { +// fix = true; +// } +// } +// if (fix) { +// n.setAttribute("href", "#"+makeInternalBundleLink(b, n.getAttribute("href"))); +// } +// } private void renderSearch(XhtmlNode root, ResourceWrapper search) { StringBuilder b = new StringBuilder(); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ObligationsRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ObligationsRenderer.java index 7787d0f04..265c22d17 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ObligationsRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ObligationsRenderer.java @@ -291,7 +291,7 @@ public class ObligationsRenderer extends Renderer { } else { Piece piece = gen.new Piece("table").attr("class", "grid"); c.getPieces().add(piece); - renderTable(status, res, piece.getChildren(), false, gen.getDefPath(), gen.getAnchorPrefix(), inScopeElements); + renderTable(status, res, piece.getChildren(), false, gen.getDefPath(), gen.getUniqueLocalPrefix(), inScopeElements); } } 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 7a409505d..c685ebde2 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 @@ -86,7 +86,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer { if (doOpts) { x.b().tx(context.formatPhrase(RenderingContext.QUEST_STRUCT)); } - HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, context.getDestDir(), context.isInlineGraphics(), true); + HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, context.getDestDir(), context.isInlineGraphics(), true, ""); TableModel model = gen.new TableModel("qtree="+q.getId(), context.getRules() == GenerationRules.IG_PUBLISHER); model.setAlternating(true); if (context.getRules() == GenerationRules.VALID_RESOURCE || context.isInlineGraphics()) { @@ -493,7 +493,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer { } private void renderLogic(RenderingStatus status, XhtmlNode x, ResourceWrapper q) throws FHIRException, IOException { - HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, context.getDestDir(), context.isInlineGraphics(), true); + HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, context.getDestDir(), context.isInlineGraphics(), true, ""); TableModel model = gen.new TableModel("qtree="+q.getId(), true); model.setAlternating(true); if (context.getRules() == GenerationRules.VALID_RESOURCE || context.isInlineGraphics()) { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireResponseRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireResponseRenderer.java index c63b4c6b8..4b6de8c66 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireResponseRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/QuestionnaireResponseRenderer.java @@ -65,7 +65,7 @@ public class QuestionnaireResponseRenderer extends ResourceRenderer { } public void renderTree(RenderingStatus status, XhtmlNode x, ResourceWrapper qr) throws UnsupportedEncodingException, IOException { - HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, context.getDestDir(), context.isInlineGraphics(), true); + HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, context.getDestDir(), context.isInlineGraphics(), true, ""); TableModel model = gen.new TableModel("qtree="+qr.getId(), false); model.setAlternating(true); if (context.getRules() == GenerationRules.VALID_RESOURCE || context.isInlineGraphics()) { diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ResourceRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ResourceRenderer.java index 70f691e82..bddedcdcb 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ResourceRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ResourceRenderer.java @@ -792,8 +792,21 @@ public abstract class ResourceRenderer extends DataRenderer { } } - public static String makeInternalBundleLink(String fullUrl) { - return fullUrl.replace(":", "-"); + public static String makeInternalBundleLink(ResourceWrapper bundle, String fullUrl) { + // are we in a bundle in a bundle? Then the link is scoped + boolean inBundle = false; + ResourceWrapper rw = bundle.parent(); + while (rw != null) { + if (rw.fhirType().equals("Bundle")) { + inBundle = true; + } + rw = rw.parent(); + } + if (inBundle) { + return bundle.getScopedId()+"/"+fullUrl.replace(":", "-"); + } else { + return fullUrl.replace(":", "-"); + } } public boolean canRender(Resource resource) { 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 bdd2f3fb5..5fb15b500 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 @@ -112,7 +112,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { renderDict(status, sd, sd.getDifferential().getElement(), x.table("dict"), false, GEN_MODE_DIFF, "", r); } else { x.getChildNodes().add(generateTable(status, context.getDefinitionsTarget(), sd, true, context.getDestDir(), false, sd.getId(), false, - context.getLink(KnownLinkType.SPEC), "", sd.getKind() == StructureDefinitionKind.LOGICAL, false, null, false, context, "", r)); + context.getLink(KnownLinkType.SPEC), "", sd.getKind() == StructureDefinitionKind.LOGICAL, false, null, false, context.withUniqueLocalPrefix(null), "r", r)); } status.setExtensions(true); } @@ -322,6 +322,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { private List keyRows = new ArrayList<>(); private Map> sdMapCache = new HashMap<>(); private IMarkdownProcessor hostMd; + private Map anchors = new HashMap<>(); public Map> getSdMapCache() { @@ -492,8 +493,9 @@ public class StructureDefinitionRenderer extends ResourceRenderer { // return null; } - public XhtmlNode generateGrid(String defFile, StructureDefinition profile, String imageFolder, boolean inlineGraphics, String profileBaseFileName, String corePath, String imagePath, Set outputTracker) throws IOException, FHIRException { - HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, imageFolder, inlineGraphics, true); + public XhtmlNode generateGrid(String defFile, StructureDefinition profile, String imageFolder, boolean inlineGraphics, String profileBaseFileName, String corePath, String imagePath, Set outputTracker) throws IOException, FHIRException { + anchors.clear(); + HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, imageFolder, inlineGraphics, true, "g"); TableModel model = gen.initGridTable(corePath, profile.getId()); List list = profile.getSnapshot().getElement(); List profiles = new ArrayList(); @@ -532,10 +534,9 @@ public class StructureDefinitionRenderer extends ResourceRenderer { public XhtmlNode generateTable(RenderingStatus status, 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 mustSupport, RenderingContext rc, String anchorPrefix, ResourceWrapper res) throws IOException, FHIRException { assert(diff != snapshot);// check it's ok to get rid of one of these - HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, imageFolder, inlineGraphics, true, defFile, anchorPrefix); + anchors.clear(); + HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, imageFolder, inlineGraphics, true, defFile, rc.getUniqueLocalPrefix()); - gen.setUniqueLocalPrefix(context.getUniqueLocalPrefix()); - List list; if (diff) list = supplementMissingDiffElements(profile); @@ -710,9 +711,12 @@ public class StructureDefinitionRenderer extends ResourceRenderer { // return; if (!onlyInformationIsMapping(all, element)) { - Row row = gen.new Row(); - row.setId(element.getPath()); - row.setAnchor(element.getPath()); + Row row = gen.new Row(); + // in deeply sliced things, there can be duplicate paths that are not usefully differentiated by id, and anyway, we want path + String anchor = element.getPath(); + anchor = makeAnchorUnique(anchor); + row.setId(anchor); + row.setAnchor(anchor); row.setColor(context.getProfileUtilities().getRowColor(element, isConstraintMode)); if (element.hasSlicing()) row.setLineColor(1); @@ -830,9 +834,10 @@ public class StructureDefinitionRenderer extends ResourceRenderer { } else { if (slicingRow != originalRow && !children.isEmpty()) { // we've entered a slice; we're going to create a holder row for the slice children - Row hrow = gen.new Row(); - hrow.setId(element.getPath()); - hrow.setAnchor(element.getPath()); + Row hrow = gen.new Row(); + String anchorE = makeAnchorUnique(element.getPath()); + hrow.setId(anchorE); + hrow.setAnchor(anchorE); hrow.setColor(context.getProfileUtilities().getRowColor(element, isConstraintMode)); hrow.setLineColor(1); hrow.setIcon("icon_element.gif", context.formatPhrase(RenderingContext.TEXT_ICON_ELEMENT)); @@ -857,8 +862,10 @@ public class StructureDefinitionRenderer extends ResourceRenderer { if (typesRow != null && !children.isEmpty()) { // we've entered a typing slice; we're going to create a holder row for the all types children Row hrow = gen.new Row(); - hrow.setId(element.getPath()); - hrow.setAnchor(element.getPath()); + String anchorE = element.getPath(); + anchorE = makeAnchorUnique(anchorE); + hrow.setId(anchorE); + hrow.setAnchor(anchorE); hrow.setColor(context.getProfileUtilities().getRowColor(element, isConstraintMode)); hrow.setLineColor(1); hrow.setIcon("icon_element.gif", context.formatPhrase(RenderingContext.TEXT_ICON_ELEMENT)); @@ -890,8 +897,10 @@ public class StructureDefinitionRenderer extends ResourceRenderer { // ok, we're a slice if (slicer == null || !slicer.getId().equals(child.getPath())) { parent = gen.new Row(); - parent.setId(child.getPath()); - parent.setAnchor(child.getPath()); + String anchorE = child.getPath(); + anchorE = makeAnchorUnique(anchorE); + parent.setId(anchorE); + parent.setAnchor(anchorE); parent.setColor(context.getProfileUtilities().getRowColor(child, isConstraintMode)); parent.setLineColor(1); parent.setIcon("icon_slice.png", context.formatPhrase(RenderingContext.TEXT_ICON_SLICE)); @@ -934,6 +943,17 @@ public class StructureDefinitionRenderer extends ResourceRenderer { } } return slicingRow; + } + + private String makeAnchorUnique(String anchor) { + if (anchors.containsKey(anchor)) { + int c = anchors.get(anchor)+1; + anchors.put(anchor, c); + anchor = anchor+"."+c; + } else { + anchors.put(anchor, 1); + } + return anchor; } private boolean isTypeSlice(ElementDefinition child) { @@ -2107,7 +2127,9 @@ public class StructureDefinitionRenderer extends ResourceRenderer { if (!onlyInformationIsMapping(all, element)) { Row row = gen.new Row(); row.setId(s); - row.setAnchor(element.getPath()); + String anchor = element.getPath(); + anchor = makeAnchorUnique(anchor); + row.setAnchor(anchor); row.setColor(context.getProfileUtilities().getRowColor(element, isConstraintMode)); if (element.hasSlicing()) row.setLineColor(1); @@ -3034,8 +3056,9 @@ public class StructureDefinitionRenderer extends ResourceRenderer { } - public XhtmlNode generateSpanningTable(StructureDefinition profile, String imageFolder, boolean onlyConstraints, String constraintPrefix, Set outputTracker) throws IOException, FHIRException { - HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, imageFolder, false, true, "", ""); + public XhtmlNode generateSpanningTable(StructureDefinition profile, String imageFolder, boolean onlyConstraints, String constraintPrefix, Set outputTracker, String anchorPrefix) throws IOException, FHIRException { + anchors.clear(); + HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, imageFolder, false, true, "", anchorPrefix); TableModel model = initSpanningTable(gen, "", false, profile.getId()); Set processed = new HashSet(); SpanEntry span = buildSpanningTable("(focus)", "", profile, processed, onlyConstraints, constraintPrefix); @@ -3139,6 +3162,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer { } public XhtmlNode generateExtensionTable(RenderingStatus status, String defFile, StructureDefinition ed, String imageFolder, boolean inlineGraphics, boolean full, String corePath, String imagePath, Set outputTracker, RenderingContext rc, String defPath, String anchorPrefix, ResourceWrapper res) throws IOException, FHIRException { + anchors.clear(); HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, imageFolder, inlineGraphics, true, defPath, anchorPrefix); TableModel model = gen.initNormalTable(corePath, false, true, ed.getId()+(full ? "f" : "n"), true, TableGenerationMode.XHTML); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ValueSetRenderer.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ValueSetRenderer.java index 2655d077d..bb56a2f37 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ValueSetRenderer.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/ValueSetRenderer.java @@ -1025,7 +1025,7 @@ public class ValueSetRenderer extends TerminologyRenderer { } x.br(); x.tx(s); - HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, context.getDestDir(), context.isInlineGraphics(), true); + HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, context.getDestDir(), context.isInlineGraphics(), true, "exp"); TableModel model = gen.new TableModel("exp.h="+index, context.getRules() == GenerationRules.IG_PUBLISHER); model.setAlternating(true); model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatPhrase(RenderingContext.GENERAL_CODE), context.formatPhrase(RenderingContext.VALUE_SET_CODE_ITEM), null, 0)); diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/RenderingContext.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/RenderingContext.java index 1b9dc364d..2e02f04a5 100644 --- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/RenderingContext.java +++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/renderers/utils/RenderingContext.java @@ -273,6 +273,7 @@ public class RenderingContext extends RenderingI18nContext { private int base64Limit = 1024; private boolean shortPatientForm; private String uniqueLocalPrefix; + private Set anchors = new HashSet<>(); /** * @@ -1004,4 +1005,11 @@ public class RenderingContext extends RenderingI18nContext { return self; } + public boolean hasAnchor(String anchor) { + return anchors.contains(anchor); + } + + public void addAnchor(String anchor) { + anchors.add(anchor); + } } \ No newline at end of file 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 dbfa422a6..3b6375bb0 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 @@ -84,6 +84,7 @@ import org.commonmark.parser.Parser; import org.commonmark.renderer.html.HtmlRenderer; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; +import org.hl7.fhir.utilities.DebugUtilities; import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.filesystem.ManagedFileAccess; @@ -618,7 +619,6 @@ public class HierarchicalTableGenerator { private String dest; private boolean makeTargets; private String defPath = ""; - private String anchorPrefix = ""; /** * There are circumstances where the table has to present in the absence of a stable supporting infrastructure. @@ -637,6 +637,12 @@ public class HierarchicalTableGenerator { this.i18n = i18n; } + public HierarchicalTableGenerator(RenderingI18nContext i18n, String uniqueLocalPrefix) { + super(); + this.i18n = i18n; + this.uniqueLocalPrefix = uniqueLocalPrefix; + } + public HierarchicalTableGenerator(RenderingI18nContext i18n, String dest, boolean inlineGraphics) { super(); this.i18n = i18n; @@ -646,29 +652,34 @@ public class HierarchicalTableGenerator { checkSetup(); } - public String getDefPath() { - return defPath; + public HierarchicalTableGenerator(RenderingI18nContext i18n, String dest, boolean inlineGraphics, String uniqueLocalPrefix) { + super(); + this.i18n = i18n; + this.dest = dest; + this.inLineGraphics = inlineGraphics; + this.makeTargets = true; + this.uniqueLocalPrefix = uniqueLocalPrefix; + checkSetup(); } - public String getAnchorPrefix() { - return anchorPrefix; - } - - private void checkSetup() { - if (dest == null) { - throw new Error("what"); - } - - } - - public HierarchicalTableGenerator(RenderingI18nContext i18n, String dest, boolean inlineGraphics, boolean makeTargets, String defPath, String anchorPrefix) { + public HierarchicalTableGenerator(RenderingI18nContext i18n, String dest, boolean inlineGraphics, boolean makeTargets, String defPath, String uniqueLocalPrefix) { super(); this.i18n = i18n; this.dest = dest; this.inLineGraphics = inlineGraphics; this.makeTargets = makeTargets; this.defPath = defPath; - this.anchorPrefix = anchorPrefix; + this.uniqueLocalPrefix = uniqueLocalPrefix; + checkSetup(); + } + + public HierarchicalTableGenerator(RenderingI18nContext i18n, String dest, boolean inlineGraphics, boolean makeTargets, String uniqueLocalPrefix) { + super(); + this.i18n = i18n; + this.dest = dest; + this.inLineGraphics = inlineGraphics; + this.makeTargets = makeTargets; + this.uniqueLocalPrefix = uniqueLocalPrefix; checkSetup(); } @@ -681,6 +692,16 @@ public class HierarchicalTableGenerator { checkSetup(); } + private void checkSetup() { + if (dest == null) { + throw new Error("what"); + } + } + + public String getDefPath() { + return defPath; + } + public TableModel initNormalTable(String prefix, boolean isLogical, boolean alternating, String id, boolean isActive, TableGenerationMode mode) throws IOException { this.mode = mode; @@ -1141,6 +1162,9 @@ public class HierarchicalTableGenerator { } public void setUniqueLocalPrefix(String uniqueLocalPrefix) { + if (Utilities.noString(uniqueLocalPrefix)) { + throw new Error("what?"); + } this.uniqueLocalPrefix = uniqueLocalPrefix; }