fix various rendering problems leading to non-unique html anchors

This commit is contained in:
Grahame Grieve 2024-07-01 06:27:51 +09:30
parent 185427a975
commit 437687f5cd
14 changed files with 151 additions and 83 deletions

View File

@ -592,7 +592,7 @@ public abstract class CanonicalResourceComparer extends ResourceComparer {
public XhtmlNode renderMetadata(CanonicalResourceComparison<? extends CanonicalResource> comparison, String id, String prefix) throws FHIRException, IOException { public XhtmlNode renderMetadata(CanonicalResourceComparison<? extends CanonicalResource> comparison, String id, String prefix) throws FHIRException, IOException {
// columns: code, display (left|right), properties (left|right) // 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); TableModel model = gen.new TableModel(id, true);
model.setAlternating(true); model.setAlternating(true);
model.getTitles().add(gen.new Title(null, null, "Name", "Property Name", null, 100)); model.getTitles().add(gen.new Title(null, null, "Name", "Property Name", null, 100));

View File

@ -743,7 +743,7 @@ public class CapabilityStatementComparer extends CanonicalResourceComparer {
// 6 columns: path | left value | left doco | right value | right doco | comments // 6 columns: path | left value | left doco | right value | right doco | comments
public XhtmlNode renderStatements(CapabilityStatementComparison comparison, String id, String prefix) throws FHIRException, IOException { 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); TableModel model = gen.new TableModel(id, true);
model.setAlternating(true); model.setAlternating(true);
model.getTitles().add(gen.new Title(null, null, "Type", "The type of item", null, 100)); model.getTitles().add(gen.new Title(null, null, "Type", "The type of item", null, 100));

View File

@ -520,7 +520,7 @@ public class CodeSystemComparer extends CanonicalResourceComparer {
public XhtmlNode renderConcepts(CodeSystemComparison comparison, String id, String prefix) throws FHIRException, IOException { public XhtmlNode renderConcepts(CodeSystemComparison comparison, String id, String prefix) throws FHIRException, IOException {
// columns: code, display (left|right), properties (left|right) // 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); TableModel model = gen.new TableModel(id, true);
model.setAlternating(true); model.setAlternating(true);
model.getTitles().add(gen.new Title(null, null, "Code", "The code for the concept", null, 100)); model.getTitles().add(gen.new Title(null, null, "Code", "The code for the concept", null, 100));

View File

@ -1252,7 +1252,7 @@ public class StructureDefinitionComparer extends CanonicalResourceComparer imple
} }
public XhtmlNode renderStructure(ProfileComparison comp, String id, String prefix, String corePath) throws FHIRException, IOException { 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); 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); 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); 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 { 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)); 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 { 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)); 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<Row> rows, StructuralMatch<ElementDefinitionNode> combined, String corePath, String prefix, Row slicingRow, boolean root) throws IOException { private void genElementComp(String defPath, String anchorPrefix, HierarchicalTableGenerator gen, List<Row> rows, StructuralMatch<ElementDefinitionNode> combined, String corePath, String prefix, Row slicingRow, boolean root) throws IOException {

View File

@ -589,7 +589,7 @@ public class ValueSetComparer extends CanonicalResourceComparer {
} }
public XhtmlNode renderCompose(ValueSetComparison csc, String id, String prefix) throws FHIRException, IOException { 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); TableModel model = gen.new TableModel(id, true);
model.setAlternating(true); model.setAlternating(true);
model.getTitles().add(gen.new Title(null, null, "Item", "The type of item being compared", null, 100)); 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 hasAbstract = findAbstract(csc.getExpansion());
boolean hasInactive = findInactive(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); TableModel model = gen.new TableModel(id, true);
model.setAlternating(true); model.setAlternating(true);
if (hasSystem) { if (hasSystem) {

View File

@ -61,16 +61,15 @@ public class BundleRenderer extends ResourceRenderer {
i++; i++;
if (i >= start) { if (i >= start) {
if (be.has("fullUrl")) { 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.has("resource")) {
if (be.child("resource").has("id")) { String id = be.child("resource").has("id") ? be.child("resource").primitiveValue("id") : makeIdFromBundleEntry(be.primitiveValue("fullUrl"));
root.an(context.prefixAnchor(be.child("resource").fhirType() + "_" + be.child("resource").primitiveValue("id"))); String anchor = be.child("resource").fhirType() + "_" + id;
root.an(context.prefixAnchor("hc"+be.child("resource").fhirType() + "_" + be.child("resource").primitiveValue("id"))); if (id != null && !context.hasAnchor(anchor)) {
} else { context.addAnchor(anchor);
String id = makeIdFromBundleEntry(be.primitiveValue("fullUrl")); root.an(context.prefixAnchor(anchor));
root.an(context.prefixAnchor(be.child("resource").fhirType() + "_" + id)); root.an(context.prefixAnchor("hc"+anchor));
root.an(context.prefixAnchor("hc"+be.child("resource").fhirType() + "_" + id));
} }
} }
root.hr(); root.hr();
@ -237,31 +236,31 @@ public class BundleRenderer extends ResourceRenderer {
return !b.getEntry().isEmpty(); return !b.getEntry().isEmpty();
} }
private List<XhtmlNode> checkInternalLinks(Bundle b, List<XhtmlNode> childNodes) { // private List<XhtmlNode> checkInternalLinks(Bundle b, List<XhtmlNode> childNodes) {
scanNodesForInternalLinks(b, childNodes); // scanNodesForInternalLinks(b, childNodes);
return childNodes; // return childNodes;
} // }
//
private void scanNodesForInternalLinks(Bundle b, List<XhtmlNode> nodes) { // private void scanNodesForInternalLinks(Bundle b, List<XhtmlNode> nodes) {
for (XhtmlNode n : nodes) { // for (XhtmlNode n : nodes) {
if ("a".equals(n.getName()) && n.hasAttribute("href")) { // if ("a".equals(n.getName()) && n.hasAttribute("href")) {
scanInternalLink(b, n); // scanInternalLink(b, n);
} // }
scanNodesForInternalLinks(b, n.getChildNodes()); // scanNodesForInternalLinks(b, n.getChildNodes());
} // }
} // }
//
private void scanInternalLink(Bundle b, XhtmlNode n) { // private void scanInternalLink(Bundle b, XhtmlNode n) {
boolean fix = false; // boolean fix = false;
for (BundleEntryComponent be : b.getEntry()) { // for (BundleEntryComponent be : b.getEntry()) {
if (be.hasFullUrl() && be.getFullUrl().equals(n.getAttribute("href"))) { // if (be.hasFullUrl() && be.getFullUrl().equals(n.getAttribute("href"))) {
fix = true; // fix = true;
} // }
} // }
if (fix) { // if (fix) {
n.setAttribute("href", "#"+makeInternalBundleLink(n.getAttribute("href"))); // n.setAttribute("href", "#"+makeInternalBundleLink(b, n.getAttribute("href")));
} // }
} // }
private void renderSearch(XhtmlNode root, ResourceWrapper search) { private void renderSearch(XhtmlNode root, ResourceWrapper search) {
StringBuilder b = new StringBuilder(); StringBuilder b = new StringBuilder();

View File

@ -291,7 +291,7 @@ public class ObligationsRenderer extends Renderer {
} else { } else {
Piece piece = gen.new Piece("table").attr("class", "grid"); Piece piece = gen.new Piece("table").attr("class", "grid");
c.getPieces().add(piece); 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);
} }
} }

View File

@ -86,7 +86,7 @@ public class QuestionnaireRenderer extends TerminologyRenderer {
if (doOpts) { if (doOpts) {
x.b().tx(context.formatPhrase(RenderingContext.QUEST_STRUCT)); 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); TableModel model = gen.new TableModel("qtree="+q.getId(), context.getRules() == GenerationRules.IG_PUBLISHER);
model.setAlternating(true); model.setAlternating(true);
if (context.getRules() == GenerationRules.VALID_RESOURCE || context.isInlineGraphics()) { 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 { 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); TableModel model = gen.new TableModel("qtree="+q.getId(), true);
model.setAlternating(true); model.setAlternating(true);
if (context.getRules() == GenerationRules.VALID_RESOURCE || context.isInlineGraphics()) { if (context.getRules() == GenerationRules.VALID_RESOURCE || context.isInlineGraphics()) {

View File

@ -65,7 +65,7 @@ public class QuestionnaireResponseRenderer extends ResourceRenderer {
} }
public void renderTree(RenderingStatus status, XhtmlNode x, ResourceWrapper qr) throws UnsupportedEncodingException, IOException { 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); TableModel model = gen.new TableModel("qtree="+qr.getId(), false);
model.setAlternating(true); model.setAlternating(true);
if (context.getRules() == GenerationRules.VALID_RESOURCE || context.isInlineGraphics()) { if (context.getRules() == GenerationRules.VALID_RESOURCE || context.isInlineGraphics()) {

View File

@ -792,8 +792,21 @@ public abstract class ResourceRenderer extends DataRenderer {
} }
} }
public static String makeInternalBundleLink(String fullUrl) { public static String makeInternalBundleLink(ResourceWrapper bundle, String fullUrl) {
return fullUrl.replace(":", "-"); // 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) { public boolean canRender(Resource resource) {

View File

@ -112,7 +112,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
renderDict(status, sd, sd.getDifferential().getElement(), x.table("dict"), false, GEN_MODE_DIFF, "", r); renderDict(status, sd, sd.getDifferential().getElement(), x.table("dict"), false, GEN_MODE_DIFF, "", r);
} else { } else {
x.getChildNodes().add(generateTable(status, context.getDefinitionsTarget(), sd, true, context.getDestDir(), false, sd.getId(), false, 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); status.setExtensions(true);
} }
@ -322,6 +322,7 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
private List<String> keyRows = new ArrayList<>(); private List<String> keyRows = new ArrayList<>();
private Map<String, Map<String, ElementDefinition>> sdMapCache = new HashMap<>(); private Map<String, Map<String, ElementDefinition>> sdMapCache = new HashMap<>();
private IMarkdownProcessor hostMd; private IMarkdownProcessor hostMd;
private Map<String, Integer> anchors = new HashMap<>();
public Map<String, Map<String, ElementDefinition>> getSdMapCache() { public Map<String, Map<String, ElementDefinition>> getSdMapCache() {
@ -492,8 +493,9 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
// return null; // return null;
} }
public XhtmlNode generateGrid(String defFile, StructureDefinition profile, String imageFolder, boolean inlineGraphics, String profileBaseFileName, String corePath, String imagePath, Set<String> outputTracker) throws IOException, FHIRException { public XhtmlNode generateGrid(String defFile, StructureDefinition profile, String imageFolder, boolean inlineGraphics, String profileBaseFileName, String corePath, String imagePath, Set<String> outputTracker) throws IOException, FHIRException {
HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, imageFolder, inlineGraphics, true); anchors.clear();
HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, imageFolder, inlineGraphics, true, "g");
TableModel model = gen.initGridTable(corePath, profile.getId()); TableModel model = gen.initGridTable(corePath, profile.getId());
List<ElementDefinition> list = profile.getSnapshot().getElement(); List<ElementDefinition> list = profile.getSnapshot().getElement();
List<StructureDefinition> profiles = new ArrayList<StructureDefinition>(); List<StructureDefinition> profiles = new ArrayList<StructureDefinition>();
@ -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, 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<String> outputTracker, boolean mustSupport, RenderingContext rc, String anchorPrefix, ResourceWrapper res) throws IOException, FHIRException { boolean logicalModel, boolean allInvariants, Set<String> 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 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<ElementDefinition> list; List<ElementDefinition> list;
if (diff) if (diff)
list = supplementMissingDiffElements(profile); list = supplementMissingDiffElements(profile);
@ -710,9 +711,12 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
// return; // return;
if (!onlyInformationIsMapping(all, element)) { if (!onlyInformationIsMapping(all, element)) {
Row row = gen.new Row(); Row row = gen.new Row();
row.setId(element.getPath()); // in deeply sliced things, there can be duplicate paths that are not usefully differentiated by id, and anyway, we want path
row.setAnchor(element.getPath()); String anchor = element.getPath();
anchor = makeAnchorUnique(anchor);
row.setId(anchor);
row.setAnchor(anchor);
row.setColor(context.getProfileUtilities().getRowColor(element, isConstraintMode)); row.setColor(context.getProfileUtilities().getRowColor(element, isConstraintMode));
if (element.hasSlicing()) if (element.hasSlicing())
row.setLineColor(1); row.setLineColor(1);
@ -830,9 +834,10 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
} else { } else {
if (slicingRow != originalRow && !children.isEmpty()) { if (slicingRow != originalRow && !children.isEmpty()) {
// we've entered a slice; we're going to create a holder row for the slice children // we've entered a slice; we're going to create a holder row for the slice children
Row hrow = gen.new Row(); Row hrow = gen.new Row();
hrow.setId(element.getPath()); String anchorE = makeAnchorUnique(element.getPath());
hrow.setAnchor(element.getPath()); hrow.setId(anchorE);
hrow.setAnchor(anchorE);
hrow.setColor(context.getProfileUtilities().getRowColor(element, isConstraintMode)); hrow.setColor(context.getProfileUtilities().getRowColor(element, isConstraintMode));
hrow.setLineColor(1); hrow.setLineColor(1);
hrow.setIcon("icon_element.gif", context.formatPhrase(RenderingContext.TEXT_ICON_ELEMENT)); 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()) { if (typesRow != null && !children.isEmpty()) {
// we've entered a typing slice; we're going to create a holder row for the all types children // we've entered a typing slice; we're going to create a holder row for the all types children
Row hrow = gen.new Row(); Row hrow = gen.new Row();
hrow.setId(element.getPath()); String anchorE = element.getPath();
hrow.setAnchor(element.getPath()); anchorE = makeAnchorUnique(anchorE);
hrow.setId(anchorE);
hrow.setAnchor(anchorE);
hrow.setColor(context.getProfileUtilities().getRowColor(element, isConstraintMode)); hrow.setColor(context.getProfileUtilities().getRowColor(element, isConstraintMode));
hrow.setLineColor(1); hrow.setLineColor(1);
hrow.setIcon("icon_element.gif", context.formatPhrase(RenderingContext.TEXT_ICON_ELEMENT)); 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 // ok, we're a slice
if (slicer == null || !slicer.getId().equals(child.getPath())) { if (slicer == null || !slicer.getId().equals(child.getPath())) {
parent = gen.new Row(); parent = gen.new Row();
parent.setId(child.getPath()); String anchorE = child.getPath();
parent.setAnchor(child.getPath()); anchorE = makeAnchorUnique(anchorE);
parent.setId(anchorE);
parent.setAnchor(anchorE);
parent.setColor(context.getProfileUtilities().getRowColor(child, isConstraintMode)); parent.setColor(context.getProfileUtilities().getRowColor(child, isConstraintMode));
parent.setLineColor(1); parent.setLineColor(1);
parent.setIcon("icon_slice.png", context.formatPhrase(RenderingContext.TEXT_ICON_SLICE)); parent.setIcon("icon_slice.png", context.formatPhrase(RenderingContext.TEXT_ICON_SLICE));
@ -934,6 +943,17 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
} }
} }
return slicingRow; 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) { private boolean isTypeSlice(ElementDefinition child) {
@ -2107,7 +2127,9 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
if (!onlyInformationIsMapping(all, element)) { if (!onlyInformationIsMapping(all, element)) {
Row row = gen.new Row(); Row row = gen.new Row();
row.setId(s); row.setId(s);
row.setAnchor(element.getPath()); String anchor = element.getPath();
anchor = makeAnchorUnique(anchor);
row.setAnchor(anchor);
row.setColor(context.getProfileUtilities().getRowColor(element, isConstraintMode)); row.setColor(context.getProfileUtilities().getRowColor(element, isConstraintMode));
if (element.hasSlicing()) if (element.hasSlicing())
row.setLineColor(1); row.setLineColor(1);
@ -3034,8 +3056,9 @@ public class StructureDefinitionRenderer extends ResourceRenderer {
} }
public XhtmlNode generateSpanningTable(StructureDefinition profile, String imageFolder, boolean onlyConstraints, String constraintPrefix, Set<String> outputTracker) throws IOException, FHIRException { public XhtmlNode generateSpanningTable(StructureDefinition profile, String imageFolder, boolean onlyConstraints, String constraintPrefix, Set<String> outputTracker, String anchorPrefix) throws IOException, FHIRException {
HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, imageFolder, false, true, "", ""); anchors.clear();
HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, imageFolder, false, true, "", anchorPrefix);
TableModel model = initSpanningTable(gen, "", false, profile.getId()); TableModel model = initSpanningTable(gen, "", false, profile.getId());
Set<String> processed = new HashSet<String>(); Set<String> processed = new HashSet<String>();
SpanEntry span = buildSpanningTable("(focus)", "", profile, processed, onlyConstraints, constraintPrefix); 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<String> outputTracker, RenderingContext rc, String defPath, String anchorPrefix, ResourceWrapper res) throws IOException, FHIRException { public XhtmlNode generateExtensionTable(RenderingStatus status, String defFile, StructureDefinition ed, String imageFolder, boolean inlineGraphics, boolean full, String corePath, String imagePath, Set<String> outputTracker, RenderingContext rc, String defPath, String anchorPrefix, ResourceWrapper res) throws IOException, FHIRException {
anchors.clear();
HierarchicalTableGenerator gen = new HierarchicalTableGenerator(context, imageFolder, inlineGraphics, true, defPath, anchorPrefix); 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); TableModel model = gen.initNormalTable(corePath, false, true, ed.getId()+(full ? "f" : "n"), true, TableGenerationMode.XHTML);

View File

@ -1025,7 +1025,7 @@ public class ValueSetRenderer extends TerminologyRenderer {
} }
x.br(); x.br();
x.tx(s); 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); TableModel model = gen.new TableModel("exp.h="+index, context.getRules() == GenerationRules.IG_PUBLISHER);
model.setAlternating(true); 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)); model.getTitles().add(gen.new Title(null, model.getDocoRef(), context.formatPhrase(RenderingContext.GENERAL_CODE), context.formatPhrase(RenderingContext.VALUE_SET_CODE_ITEM), null, 0));

View File

@ -273,6 +273,7 @@ public class RenderingContext extends RenderingI18nContext {
private int base64Limit = 1024; private int base64Limit = 1024;
private boolean shortPatientForm; private boolean shortPatientForm;
private String uniqueLocalPrefix; private String uniqueLocalPrefix;
private Set<String> anchors = new HashSet<>();
/** /**
* *
@ -1004,4 +1005,11 @@ public class RenderingContext extends RenderingI18nContext {
return self; return self;
} }
public boolean hasAnchor(String anchor) {
return anchors.contains(anchor);
}
public void addAnchor(String anchor) {
anchors.add(anchor);
}
} }

View File

@ -84,6 +84,7 @@ import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.HtmlRenderer; import org.commonmark.renderer.html.HtmlRenderer;
import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.DebugUtilities;
import org.hl7.fhir.utilities.TextFile; import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.utilities.Utilities;
import org.hl7.fhir.utilities.filesystem.ManagedFileAccess; import org.hl7.fhir.utilities.filesystem.ManagedFileAccess;
@ -618,7 +619,6 @@ public class HierarchicalTableGenerator {
private String dest; private String dest;
private boolean makeTargets; private boolean makeTargets;
private String defPath = ""; private String defPath = "";
private String anchorPrefix = "";
/** /**
* There are circumstances where the table has to present in the absence of a stable supporting infrastructure. * 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; this.i18n = i18n;
} }
public HierarchicalTableGenerator(RenderingI18nContext i18n, String uniqueLocalPrefix) {
super();
this.i18n = i18n;
this.uniqueLocalPrefix = uniqueLocalPrefix;
}
public HierarchicalTableGenerator(RenderingI18nContext i18n, String dest, boolean inlineGraphics) { public HierarchicalTableGenerator(RenderingI18nContext i18n, String dest, boolean inlineGraphics) {
super(); super();
this.i18n = i18n; this.i18n = i18n;
@ -646,29 +652,34 @@ public class HierarchicalTableGenerator {
checkSetup(); checkSetup();
} }
public String getDefPath() { public HierarchicalTableGenerator(RenderingI18nContext i18n, String dest, boolean inlineGraphics, String uniqueLocalPrefix) {
return defPath; super();
this.i18n = i18n;
this.dest = dest;
this.inLineGraphics = inlineGraphics;
this.makeTargets = true;
this.uniqueLocalPrefix = uniqueLocalPrefix;
checkSetup();
} }
public String getAnchorPrefix() { public HierarchicalTableGenerator(RenderingI18nContext i18n, String dest, boolean inlineGraphics, boolean makeTargets, String defPath, String uniqueLocalPrefix) {
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) {
super(); super();
this.i18n = i18n; this.i18n = i18n;
this.dest = dest; this.dest = dest;
this.inLineGraphics = inlineGraphics; this.inLineGraphics = inlineGraphics;
this.makeTargets = makeTargets; this.makeTargets = makeTargets;
this.defPath = defPath; 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(); checkSetup();
} }
@ -681,6 +692,16 @@ public class HierarchicalTableGenerator {
checkSetup(); 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 { public TableModel initNormalTable(String prefix, boolean isLogical, boolean alternating, String id, boolean isActive, TableGenerationMode mode) throws IOException {
this.mode = mode; this.mode = mode;
@ -1141,6 +1162,9 @@ public class HierarchicalTableGenerator {
} }
public void setUniqueLocalPrefix(String uniqueLocalPrefix) { public void setUniqueLocalPrefix(String uniqueLocalPrefix) {
if (Utilities.noString(uniqueLocalPrefix)) {
throw new Error("what?");
}
this.uniqueLocalPrefix = uniqueLocalPrefix; this.uniqueLocalPrefix = uniqueLocalPrefix;
} }