001package org.hl7.fhir.r5.renderers.utils; 002 003import java.io.IOException; 004import java.text.NumberFormat; 005import java.time.ZoneId; 006import java.time.format.DateTimeFormatter; 007import java.util.ArrayList; 008import java.util.HashMap; 009import java.util.HashSet; 010import java.util.List; 011import java.util.Locale; 012import java.util.Map; 013import java.util.Set; 014 015import org.hl7.fhir.exceptions.FHIRException; 016import org.hl7.fhir.exceptions.FHIRFormatError; 017import org.hl7.fhir.r5.conformance.profile.ProfileKnowledgeProvider; 018import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; 019import org.hl7.fhir.r5.context.ContextUtilities; 020import org.hl7.fhir.r5.context.IWorkerContext; 021import org.hl7.fhir.r5.elementmodel.Element; 022import org.hl7.fhir.r5.fhirpath.FHIRPathEngine.IEvaluationContext; 023import org.hl7.fhir.r5.model.Base; 024import org.hl7.fhir.r5.model.DomainResource; 025import org.hl7.fhir.r5.model.Enumeration; 026import org.hl7.fhir.r5.model.PrimitiveType; 027import org.hl7.fhir.r5.model.StringType; 028import org.hl7.fhir.r5.renderers.utils.Resolver.IReferenceResolver; 029import org.hl7.fhir.r5.terminologies.utilities.ValidationResult; 030import org.hl7.fhir.r5.utils.ToolingExtensions; 031import org.hl7.fhir.utilities.FhirPublication; 032import org.hl7.fhir.utilities.MarkDownProcessor; 033import org.hl7.fhir.utilities.MarkDownProcessor.Dialect; 034import org.hl7.fhir.utilities.StandardsStatus; 035import org.hl7.fhir.utilities.Utilities; 036import org.hl7.fhir.utilities.i18n.RenderingI18nContext; 037import org.hl7.fhir.utilities.validation.ValidationOptions; 038 039/** 040 * Managing Language when rendering 041 * 042 * You can specify a language to use when rendering resources by setting the setLocale() on 043 * the super class. The locale drives the following: 044 * - choice of java supplied rendering phrase, if translations are provided for the locale 045 * - integer and date formats used (but see below for date formats) 046 * - automatic translation of coded values, if language supplements are available 047 * - choosing text representation considering the FHIR translation extension 048 * 049 * By default, the locale is null, and the default locale for the underlying system is used. 050 * If you set locale to a specific value, then that value will be used instead of the default locale. 051 * 052 * By default, only a single language is rendered, based on the locale. Where resources contain 053 * multiple language content (designations in CodeSystem and ValueSet, or using the translation 054 * extension), you can control what languages are presented using the properties multiLanguagePolicy 055 * and languages 056 * - multiLanguagePolicy: NONE (default), DESIGNATIONS, ALL 057 * - languages: a list of allowed languages. Default is empty which means all languages in scope via multiLanguagePolicy 058 * 059 * Managing Date/Time Formatting 060 * 061 * This class has multiple parameters that influence date/time formatting when rendering resources 062 * 063 * - The default rendering is using the default java locale as above 064 * - If you setLocale() to something, then the defaults for the locale will be used 065 * - Else you can set the values of dateTimeFormat, dateFormat, dateYearFormat and dateYearMonthFormat 066 * 067 * If you set the value of locale, the values of dateTimeFormat, dateFormat, dateYearFormat and dateYearMonthFormat are 068 * reset to the system defaults 069 * 070 * Timezones: by default, date/times are rendered in their source timezone 071 * 072 */ 073public class RenderingContext extends RenderingI18nContext { 074 075 // provides liquid templates, if they are available for the content 076 public interface ILiquidTemplateProvider { 077 String findTemplate(RenderingContext rcontext, DomainResource r); 078 String findTemplate(RenderingContext rcontext, String resourceName); 079 } 080 081 // parses xml to an XML instance. Whatever codes provides this needs to provide something that parses the right version 082 public interface ITypeParser { 083 Base parseType(String xml, String type) throws FHIRFormatError, IOException, FHIRException ; 084 Base parseType(Element base) throws FHIRFormatError, IOException, FHIRException ; 085 } 086 087 /** 088 * What kind of user the renderer is targeting - end users, or technical users 089 * 090 * This affects the way codes and references are rendered 091 * 092 * @author graha 093 * 094 */ 095 public enum ResourceRendererMode { 096 /** 097 * The user has no interest in the contents of the FHIR resource, and just wants to see the data 098 * 099 */ 100 END_USER, 101 102 /** 103 * The user wants to see the resource, but a technical view so they can see what's going on with the content - this includes content like the meta header 104 */ 105 TECHNICAL 106 } 107 108 public enum GenerationRules { 109 /** 110 * The output must be valid XHTML for a resource: no active content, etc. The only external dependency allowed is fhir.css 111 */ 112 VALID_RESOURCE, 113 114 /** 115 * The output must be valid for an implementation guide according ot the base FHIR template. 116 * This means active content is allowed, though the default presentation must be *show everything* for balloting purposes 117 * Active content is allowed 118 */ 119 IG_PUBLISHER 120 } 121 122 public enum StructureDefinitionRendererMode { 123 SUMMARY, // 5 cells: tree/name | flags | cardinality | type | details 124 BINDINGS, // tree/name + column for each kind of binding found, cells are lists of bindings 125 OBLIGATIONS, // tree/name + column for each actor that has obligations 126 DATA_DICT, // detailed element view 127 } 128 129 public enum ExampleScenarioRendererMode { 130 /** 131 * A visual presentation of the questionnaire, with a set of property panes that can be toggled on and off. 132 * Note that this is not the same as how the questionnaire would like on a form filler, since all dynamic behavior is ignored 133 */ 134 ACTORS, 135 136 /** 137 * A table listing all the instances (and versions there-of) used in a scenario 138 */ 139 INSTANCES, 140 141 /** 142 * Information about the processes (and sub-processes) defined in a scenario 143 */ 144 PROCESSES, 145 146 /** 147 * A diagram showing interactions between the actors as part of the process steps 148 */ 149 DIAGRAM 150 } 151 152 public enum QuestionnaireRendererMode { 153 /** 154 * A visual presentation of the questionnaire, with a set of property panes that can be toggled on and off. 155 * Note that this is not the same as how the questionnaire would like on a form filler, since all dynamic behavior is ignored 156 */ 157 FORM, 158 159 /** 160 * a structured tree that presents the content of the questionnaire in a logical fashion 161 */ 162 TREE, 163 164 /** 165 * A structured tree that presents the enableWhen, terminology and expression bindings for the questionnaire 166 */ 167 LOGIC, 168 169 /** 170 * A presentation that lists all the items, with full details about them 171 */ 172 DEFNS, 173 174 /** 175 * Rendered links to various openly available Form Filler applications that know how to render a questionnaire published in a package 176 */ 177 LINKS 178 } 179 180 181 public enum KnownLinkType { 182 SELF, // absolute link to where the content is to be found (only used in a few circumstances when making external references to tools) 183 SPEC, // version specific link to core specification 184 JSON_NAMES 185 186 } 187 188 public enum FixedValueFormat { 189 JSON, JSON_ALL, XML, XML_ALL; 190 191 public static FixedValueFormat fromCode(String value) { 192 if (value == null) { 193 return JSON; 194 } 195 switch (value.toLowerCase()) { 196 case "json" : return JSON; 197 case "json-all" : return JSON_ALL; 198 case "xml" : return XML; 199 case "xml-all" : return XML_ALL; 200 } 201 return JSON; 202 } 203 204 public boolean notPrimitives() { 205 return this == JSON || this == XML; 206 } 207 208 public boolean isXml() { 209 return this == XML_ALL || this == XML; 210 } 211 } 212 213 public enum MultiLanguagePolicy { 214 NONE, // ONLY render the language in the locale 215 DESIGNATIONS, // in addition to the locale language, render designations from other languages (eg. as found in code systems and value sets 216 ALL // in addition to translations in designations, look for an render translations (WIP) 217 } 218 219 private IWorkerContext worker; 220 private MarkDownProcessor markdown; 221 private ResourceRendererMode mode; 222 private GenerationRules rules; 223 private IReferenceResolver resolver; 224 private ILiquidTemplateProvider templateProvider; 225 private IEvaluationContext services; 226 private ITypeParser parser; 227 228 // i18n related fields 229 private boolean secondaryLang; // true if this is not the primary language for the resource 230 private MultiLanguagePolicy multiLanguagePolicy = MultiLanguagePolicy.NONE; 231 private Set<String> allowedLanguages = new HashSet<>(); 232 private ZoneId timeZoneId; 233 private DateTimeFormatter dateTimeFormat; 234 private DateTimeFormatter dateFormat; 235 private DateTimeFormatter dateYearFormat; 236 private DateTimeFormatter dateYearMonthFormat; 237 238 private String localPrefix; // relative link within local context 239 private int headerLevelContext; 240 private boolean canonicalUrlsAsLinks; 241 private boolean pretty; 242 private boolean showSummaryTable; // for canonical resources 243 private boolean contained; 244 245 private ValidationOptions terminologyServiceOptions = new ValidationOptions(FhirPublication.R5); 246 private boolean noSlowLookup; 247 private List<String> codeSystemPropList = new ArrayList<>(); 248 249 private ProfileUtilities profileUtilitiesR; 250 private ContextUtilities contextUtilities; 251 private String definitionsTarget; 252 private String destDir; 253 private boolean inlineGraphics; 254 private StandardsStatus defaultStandardsStatus; 255 256 private ExampleScenarioRendererMode scenarioMode = null; 257 private QuestionnaireRendererMode questionnaireMode = QuestionnaireRendererMode.FORM; 258 private StructureDefinitionRendererMode structureMode = StructureDefinitionRendererMode.SUMMARY; 259 private FixedValueFormat fixedFormat = FixedValueFormat.JSON; 260 261 private boolean showComments = false; 262 263 private FhirPublication targetVersion; 264 private boolean copyButton; 265 private ProfileKnowledgeProvider pkp; 266 private String changeVersion; 267 private List<String> files = new ArrayList<String>(); // files created as by-products in destDir 268 269 private Map<KnownLinkType, String> links = new HashMap<>(); 270 private Map<String, String> namedLinks = new HashMap<>(); 271 private boolean addName = false; 272 private Map<String, String> typeMap = new HashMap<>(); // type aliases that can be resolved in Markdown type links (mainly for cross-version usage) 273 private int base64Limit = 1024; 274 private boolean shortPatientForm; 275 private String uniqueLocalPrefix; 276 private Set<String> anchors = new HashSet<>(); 277 private boolean unknownLocalReferencesNotLinks; 278 279 /** 280 * 281 * @param context - access to all related resources that might be needed 282 * @param markdown - appropriate markdown processing engine 283 * @param terminologyServiceOptions - options to use when looking up codes 284 * @param specLink - path to FHIR specification 285 * @param locale - i18n for rendering 286 */ 287 public RenderingContext(IWorkerContext worker, MarkDownProcessor markdown, ValidationOptions terminologyServiceOptions, String specLink, String localPrefix, Locale locale, ResourceRendererMode mode, GenerationRules rules) { 288 super(); 289 this.worker = worker; 290 this.markdown = markdown; 291 this.locale = locale; 292 this.links.put(KnownLinkType.SPEC, specLink); 293 this.localPrefix = localPrefix; 294 this.mode = mode; 295 this.rules = rules; 296 if (terminologyServiceOptions != null) { 297 this.terminologyServiceOptions = terminologyServiceOptions; 298 } 299 } 300 301 public RenderingContext copy(boolean copyAnchors) { 302 RenderingContext res = new RenderingContext(worker, markdown, terminologyServiceOptions, getLink(KnownLinkType.SPEC), localPrefix, locale, mode, rules); 303 304 res.resolver = resolver; 305 res.templateProvider = templateProvider; 306 res.services = services; 307 res.parser = parser; 308 309 res.headerLevelContext = headerLevelContext; 310 res.canonicalUrlsAsLinks = canonicalUrlsAsLinks; 311 res.pretty = pretty; 312 res.contained = contained; 313 314 res.noSlowLookup = noSlowLookup; 315 res.codeSystemPropList.addAll(codeSystemPropList); 316 317 res.profileUtilitiesR = profileUtilitiesR; 318 res.contextUtilities = contextUtilities; 319 res.definitionsTarget = definitionsTarget; 320 res.destDir = destDir; 321 res.scenarioMode = scenarioMode; 322 res.questionnaireMode = questionnaireMode; 323 res.structureMode = structureMode; 324 res.showSummaryTable = showSummaryTable; 325 res.links.putAll(links); 326 res.inlineGraphics = inlineGraphics; 327 res.timeZoneId = timeZoneId; 328 res.dateTimeFormat = dateTimeFormat; 329 res.dateFormat = dateFormat; 330 res.dateYearFormat = dateYearFormat; 331 res.dateYearMonthFormat = dateYearMonthFormat; 332 res.targetVersion = targetVersion; 333 res.showComments = showComments; 334 res.copyButton = copyButton; 335 res.pkp = pkp; 336 res.defaultStandardsStatus = defaultStandardsStatus; 337 res.changeVersion = changeVersion; 338 339 res.terminologyServiceOptions = terminologyServiceOptions.copy(); 340 res.typeMap.putAll(typeMap); 341 res.multiLanguagePolicy = multiLanguagePolicy; 342 res.allowedLanguages.addAll(allowedLanguages); 343 if (copyAnchors) { 344 res.anchors = anchors; 345 } 346 res.unknownLocalReferencesNotLinks = unknownLocalReferencesNotLinks; 347 return res; 348 } 349 350 351 public IWorkerContext getContext() { 352 return worker; 353 } 354 355 356 357 // -- 2. Markdown support ------------------------------------------------------- 358 359 public ProfileUtilities getProfileUtilities() { 360 if (profileUtilitiesR == null) { 361 profileUtilitiesR = new ProfileUtilities(worker, null, pkp); 362 } 363 return profileUtilitiesR; 364 } 365 366 public IWorkerContext getWorker() { 367 return worker; 368 } 369 370 public boolean isCanonicalUrlsAsLinks() { 371 return canonicalUrlsAsLinks; 372 } 373 374 public RenderingContext setCanonicalUrlsAsLinks(boolean canonicalUrlsAsLinks) { 375 this.canonicalUrlsAsLinks = canonicalUrlsAsLinks; 376 return this; 377 } 378 379 public MarkDownProcessor getMarkdown() { 380 if (markdown == null) { 381 markdown = new MarkDownProcessor(Dialect.COMMON_MARK); 382 } 383 return markdown; 384 } 385 386 public MultiLanguagePolicy getMultiLanguagePolicy() { 387 return multiLanguagePolicy; 388 } 389 390 public void setMultiLanguagePolicy(MultiLanguagePolicy multiLanguagePolicy) { 391 this.multiLanguagePolicy = multiLanguagePolicy; 392 } 393 394 public Set<String> getAllowedLanguages() { 395 return allowedLanguages; 396 } 397 398 public String getLocalPrefix() { 399 return localPrefix; 400 } 401 402 public ValidationOptions getTerminologyServiceOptions() { 403 return terminologyServiceOptions; 404 } 405 406 public int getHeaderLevelContext() { 407 return headerLevelContext; 408 } 409 410 public RenderingContext setHeaderLevelContext(int headerLevelContext) { 411 this.headerLevelContext = headerLevelContext; 412 return this; 413 } 414 415 public IReferenceResolver getResolver() { 416 return resolver; 417 } 418 419 public RenderingContext setResolver(IReferenceResolver resolver) { 420 this.resolver = resolver; 421 return this; 422 } 423 424 public RenderingContext setTerminologyServiceOptions(ValidationOptions terminologyServiceOptions) { 425 this.terminologyServiceOptions = terminologyServiceOptions; 426 return this; 427 } 428 429 public boolean isNoSlowLookup() { 430 return noSlowLookup; 431 } 432 433 public RenderingContext setNoSlowLookup(boolean noSlowLookup) { 434 this.noSlowLookup = noSlowLookup; 435 return this; 436 } 437 438 public String getDefinitionsTarget() { 439 return definitionsTarget; 440 } 441 442 public RenderingContext setDefinitionsTarget(String definitionsTarget) { 443 this.definitionsTarget = definitionsTarget; 444 return this; 445 } 446 447 public String getDestDir() { 448 return destDir; 449 } 450 451 public RenderingContext setDestDir(String destDir) { 452 this.destDir = destDir; 453 return this; 454 } 455 456 public RenderingContext setProfileUtilities(ProfileUtilities profileUtilities) { 457 this.profileUtilitiesR = profileUtilities; 458 if (pkp == null && profileUtilities.getPkp() != null) { 459 pkp = profileUtilities.getPkp(); 460 } 461 return this; 462 } 463 464 public ILiquidTemplateProvider getTemplateProvider() { 465 return templateProvider; 466 } 467 468 public RenderingContext setTemplateProvider(ILiquidTemplateProvider templateProvider) { 469 this.templateProvider = templateProvider; 470 return this; 471 } 472 473 public IEvaluationContext getServices() { 474 return services; 475 } 476 477 public RenderingContext setServices(IEvaluationContext services) { 478 this.services = services; 479 return this; 480 } 481 482 public boolean isPretty() { 483 return pretty; 484 } 485 486 public RenderingContext setPretty(boolean pretty) { 487 this.pretty = pretty; 488 return this; 489 } 490 491 public ITypeParser getParser() { 492 return parser; 493 } 494 495 public RenderingContext setParser(ITypeParser parser) { 496 this.parser = parser; 497 return this; 498 } 499 500 501 public List<String> getCodeSystemPropList() { 502 return codeSystemPropList; 503 } 504 505 public RenderingContext setCodeSystemPropList(List<String> codeSystemPropList) { 506 this.codeSystemPropList = codeSystemPropList; 507 return this; 508 } 509 510 511 public boolean isInlineGraphics() { 512 return inlineGraphics; 513 } 514 515 public RenderingContext setInlineGraphics(boolean inlineGraphics) { 516 this.inlineGraphics = inlineGraphics; 517 return this; 518 } 519 520 public boolean isShowSummaryTable() { 521 return showSummaryTable; 522 } 523 524 public RenderingContext setShowSummaryTable(boolean header) { 525 this.showSummaryTable = header; 526 return this; 527 } 528 529 public ExampleScenarioRendererMode getScenarioMode() { 530 return scenarioMode; 531 } 532 533 public RenderingContext setScenarioMode(ExampleScenarioRendererMode scenarioMode) { 534 this.scenarioMode = scenarioMode; 535 return this; 536 } 537 538 public QuestionnaireRendererMode getQuestionnaireMode() { 539 return questionnaireMode; 540 } 541 542 public RenderingContext setQuestionnaireMode(QuestionnaireRendererMode questionnaireMode) { 543 this.questionnaireMode = questionnaireMode; 544 return this; 545 } 546 547 public StructureDefinitionRendererMode getStructureMode() { 548 return structureMode; 549 } 550 551 public RenderingContext setStructureMode(StructureDefinitionRendererMode structureMode) { 552 this.structureMode = structureMode; 553 return this; 554 } 555 556 public String fixReference(String ref) { 557 if (ref == null) { 558 return null; 559 } 560 if (!Utilities.isAbsoluteUrl(ref)) { 561 return (localPrefix == null ? "" : localPrefix)+ref; 562 } 563 if (ref.startsWith("http://hl7.org/fhir") && !ref.substring(20).contains("/")) { 564 return getLink(KnownLinkType.SPEC)+ref.substring(20); 565 } 566 return ref; 567 } 568 569 public RenderingContext setLocalPrefix(String localPrefix) { 570 this.localPrefix = localPrefix; 571 return this; 572 } 573 574 public FhirPublication getTargetVersion() { 575 return targetVersion; 576 } 577 578 public RenderingContext setTargetVersion(FhirPublication targetVersion) { 579 this.targetVersion = targetVersion; 580 return this; 581 } 582 583 public boolean isTechnicalMode() { 584 return mode == ResourceRendererMode.TECHNICAL; 585 } 586 587 /** 588 * if the timezone is null, the rendering will default to the source timezone 589 * in the resource 590 * 591 * Note that if you're working server side, the FHIR project recommends the use 592 * of the Date header so that clients know what timezone the server defaults to, 593 * 594 * There is no standard way for the server to know what the client timezone is. 595 * In the case where the client timezone is unknown, the timezone should be null 596 * 597 * @return the specified timezone to render in 598 */ 599 public ZoneId getTimeZoneId() { 600 return timeZoneId; 601 } 602 603 public RenderingContext setTimeZoneId(ZoneId timeZoneId) { 604 this.timeZoneId = timeZoneId; 605 return this; 606 } 607 608 609 /** 610 * In the absence of a specified format, the renderers will default to 611 * the FormatStyle.MEDIUM for the current locale. 612 * 613 * @return the format to use 614 */ 615 public DateTimeFormatter getDateTimeFormat() { 616 return this.dateTimeFormat; 617 } 618 619 public RenderingContext setDateTimeFormat(DateTimeFormatter dateTimeFormat) { 620 this.dateTimeFormat = dateTimeFormat; 621 return this; 622 } 623 624 public RenderingContext setDateTimeFormatString(String dateTimeFormat) { 625 this.dateTimeFormat = DateTimeFormatter.ofPattern(dateTimeFormat); 626 return this; 627 } 628 629 /** 630 * In the absence of a specified format, the renderers will default to 631 * the FormatStyle.MEDIUM for the current locale. 632 * 633 * @return the format to use 634 */ 635 public DateTimeFormatter getDateFormat() { 636 return this.dateFormat; 637 } 638 639 public RenderingContext setDateFormat(DateTimeFormatter dateFormat) { 640 this.dateFormat = dateFormat; 641 return this; 642 } 643 644 public RenderingContext setDateFormatString(String dateFormat) { 645 this.dateFormat = DateTimeFormatter.ofPattern(dateFormat); 646 return this; 647 } 648 649 public DateTimeFormatter getDateYearFormat() { 650 return dateYearFormat; 651 } 652 653 public RenderingContext setDateYearFormat(DateTimeFormatter dateYearFormat) { 654 this.dateYearFormat = dateYearFormat; 655 return this; 656 } 657 658 public RenderingContext setDateYearFormatString(String dateYearFormat) { 659 this.dateYearFormat = DateTimeFormatter.ofPattern(dateYearFormat); 660 return this; 661 } 662 663 public DateTimeFormatter getDateYearMonthFormat() { 664 return dateYearMonthFormat; 665 } 666 667 public RenderingContext setDateYearMonthFormat(DateTimeFormatter dateYearMonthFormat) { 668 this.dateYearMonthFormat = dateYearMonthFormat; 669 return this; 670 } 671 672 public RenderingContext setDateYearMonthFormatString(String dateYearMonthFormat) { 673 this.dateYearMonthFormat = DateTimeFormatter.ofPattern(dateYearMonthFormat); 674 return this; 675 } 676 677 public ResourceRendererMode getMode() { 678 return mode; 679 } 680 681 public RenderingContext setMode(ResourceRendererMode mode) { 682 this.mode = mode; 683 return this; 684 } 685 686 public boolean isContained() { 687 return contained; 688 } 689 690 public RenderingContext setContained(boolean contained) { 691 this.contained = contained; 692 return this; 693 } 694 public boolean isShowComments() { 695 return showComments; 696 } 697 public RenderingContext setShowComments(boolean showComments) { 698 this.showComments = showComments; 699 return this; 700 } 701 public boolean isCopyButton() { 702 return copyButton; 703 } 704 public RenderingContext setCopyButton(boolean copyButton) { 705 this.copyButton = copyButton; 706 return this; 707 } 708 709 public RenderingContext setPkp(ProfileKnowledgeProvider pkp) { 710 this.pkp = pkp; 711 return this; 712 } 713 public ProfileKnowledgeProvider getPkp() { 714 return pkp; 715 } 716 717 public boolean hasLink(KnownLinkType link) { 718 return links.containsKey(link); 719 } 720 721 public String getLink(KnownLinkType link) { 722 return links.get(link); 723 } 724 public void addLink(KnownLinkType type, String link) { 725 links.put(type, link); 726 727 } 728 public GenerationRules getRules() { 729 return rules; 730 } 731 public RenderingContext setRules(GenerationRules rules) { 732 this.rules = rules; 733 return this; 734 } 735 public StandardsStatus getDefaultStandardsStatus() { 736 return defaultStandardsStatus; 737 } 738 public RenderingContext setDefaultStandardsStatus(StandardsStatus defaultStandardsStatus) { 739 this.defaultStandardsStatus = defaultStandardsStatus; 740 return this; 741 } 742 743 public String getChangeVersion() { 744 return changeVersion; 745 } 746 747 public RenderingContext setChangeVersion(String changeVersion) { 748 this.changeVersion = changeVersion; 749 return this; 750 } 751 752 public Map<String, String> getNamedLinks() { 753 return namedLinks; 754 } 755 756 public void registerFile(String n) { 757 try { 758 files.add(Utilities.path(destDir, n)); 759 } catch (IOException e) { 760 } 761 } 762 763 public List<String> getFiles() { 764 return files; 765 } 766 767 public FixedValueFormat getFixedFormat() { 768 return fixedFormat; 769 } 770 771 public void setFixedFormat(FixedValueFormat fixedFormat) { 772 this.fixedFormat = fixedFormat; 773 } 774 775 public boolean isAddName() { 776 return addName; 777 } 778 779 public RenderingContext setAddName(boolean addName) { 780 this.addName = addName; 781 return this; 782 } 783 784 public Map<String, String> getTypeMap() { 785 return typeMap; 786 } 787 788 789 public String toStr(int v) { 790 NumberFormat nf = NumberFormat.getInstance(locale); 791 return nf.format(v); 792 } 793 794 795 public String getTranslated(PrimitiveType<?> t) { 796 if (locale != null) { 797 String v = ToolingExtensions.getLanguageTranslation(t, locale.toString()); 798 if (v != null) { 799 return v; 800 } 801 } 802 return t.asStringValue(); 803 } 804 805 public String getTranslated(ResourceWrapper t) { 806 if (t == null) { 807 return null; 808 } 809 if (locale != null) { 810 for (ResourceWrapper e : t.extensions(ToolingExtensions.EXT_TRANSLATION)) { 811 String l = e.extensionString("lang"); 812 if (l != null && l.equals(locale.toString())) { 813 String v = e.extensionString("content"); 814 if (v != null) { 815 return v; 816 } 817 } 818 } 819 } 820 return t.primitiveValue(); 821 } 822 823 public StringType getTranslatedElement(PrimitiveType<?> t) { 824 if (locale != null) { 825 StringType v = ToolingExtensions.getLanguageTranslationElement(t, locale.toString()); 826 if (v != null) { 827 return v; 828 } 829 } 830 if (t instanceof StringType) { 831 return (StringType) t; 832 } else { 833 return new StringType(t.asStringValue()); 834 } 835 } 836 837 public String getTranslatedCode(Base b, String codeSystem) { 838 839 if (b instanceof org.hl7.fhir.r5.model.Element) { 840 org.hl7.fhir.r5.model.Element e = (org.hl7.fhir.r5.model.Element) b; 841 if (locale != null) { 842 String v = ToolingExtensions.getLanguageTranslation(e, locale.toString()); 843 if (v != null) { 844 return v; 845 } 846 // no? then see if the tx service can translate it for us 847 try { 848 ValidationResult t = getContext().validateCode(getTerminologyServiceOptions().withLanguage(locale.toString()).withVersionFlexible(true), 849 codeSystem, null, e.primitiveValue(), null); 850 if (t.isOk() && t.getDisplay() != null) { 851 return t.getDisplay(); 852 } 853 } catch (Exception ex) { 854 // nothing 855 } 856 } 857 if (e instanceof Enumeration<?>) { 858 return ((Enumeration<?>) e).getDisplay(); 859 } else { 860 return e.primitiveValue(); 861 } 862 } else if (b instanceof Element) { 863 return getTranslatedCode((Element) b, codeSystem); 864 } else { 865 return "??"; 866 } 867 } 868 869 public String getTranslatedCode(String code, String codeSystem) { 870 871 if (locale != null) { 872 try { 873 ValidationResult t = getContext().validateCode(getTerminologyServiceOptions().withLanguage(locale.toString()).withVersionFlexible(true), codeSystem, null, code, null); 874 if (t.isOk() && t.getDisplay() != null) { 875 return t.getDisplay(); 876 } 877 } catch (Exception ex) { 878 // nothing 879 } 880 } 881 return code; 882 } 883 884 public String getTranslatedCode(Enumeration<?> e, String codeSystem) { 885 if (locale != null) { 886 String v = ToolingExtensions.getLanguageTranslation(e, locale.toString()); 887 if (v != null) { 888 return v; 889 } 890 // no? then see if the tx service can translate it for us 891 try { 892 ValidationResult t = getContext().validateCode(getTerminologyServiceOptions().withLanguage(locale.toString()).withVersionFlexible(true), 893 codeSystem, null, e.getCode(), null); 894 if (t.isOk() && t.getDisplay() != null) { 895 return t.getDisplay(); 896 } 897 } catch (Exception ex) { 898 // nothing 899 } 900 } 901 try { 902 ValidationResult t = getContext().validateCode(getTerminologyServiceOptions().withVersionFlexible(true), 903 codeSystem, null, e.getCode(), null); 904 if (t.isOk() && t.getDisplay() != null) { 905 return t.getDisplay(); 906 } 907 } catch (Exception ex) { 908 // nothing 909 } 910 911 return e.getCode(); 912 } 913 914 public String getTranslatedCode(Element e, String codeSystem) { 915 if (locale != null) { 916 // first we look through the translation extensions 917 for (Element ext : e.getChildrenByName("extension")) { 918 String url = ext.getNamedChildValue("url"); 919 if (url.equals(ToolingExtensions.EXT_TRANSLATION)) { 920 Base e1 = ext.getExtensionValue("lang"); 921 922 if (e1 != null && e1.primitiveValue() != null && e1.primitiveValue().equals(locale.toString())) { 923 e1 = ext.getExtensionValue("content"); 924 if (e1 != null && e1.isPrimitive()) { 925 return e1.primitiveValue(); 926 } 927 } 928 } 929 } 930 // no? then see if the tx service can translate it for us 931 try { 932 ValidationResult t = getContext().validateCode(getTerminologyServiceOptions().withLanguage(locale.toString()).withVersionFlexible(true), 933 codeSystem, null, e.primitiveValue(), null); 934 if (t.isOk() && t.getDisplay() != null) { 935 return t.getDisplay(); 936 } 937 } catch (Exception ex) { 938 // nothing 939 } 940 } 941 return e.primitiveValue(); 942 } 943 944 public RenderingContext withLocale(Locale locale) { 945 setLocale(locale); 946 return this; 947 } 948 949 public RenderingContext withLocaleCode(String locale) { 950 setLocale(new Locale(locale)); 951 return this; 952 } 953 954 public ContextUtilities getContextUtilities() { 955 if (contextUtilities == null) { 956 contextUtilities = new ContextUtilities(worker); 957 } 958 return contextUtilities; 959 } 960 961 public int getBase64Limit() { 962 return base64Limit; 963 } 964 965 public void setBase64Limit(int base64Limit) { 966 this.base64Limit = base64Limit; 967 } 968 969 public boolean isShortPatientForm() { 970 return shortPatientForm; 971 } 972 973 public void setShortPatientForm(boolean shortPatientForm) { 974 this.shortPatientForm = shortPatientForm; 975 } 976 977 public boolean isSecondaryLang() { 978 return secondaryLang; 979 } 980 981 public void setSecondaryLang(boolean secondaryLang) { 982 this.secondaryLang = secondaryLang; 983 } 984 985 public String prefixAnchor(String anchor) { 986 return uniqueLocalPrefix == null ? anchor : uniqueLocalPrefix+"-" + anchor; 987 } 988 989 public String prefixLocalHref(String url) { 990 if (url == null || uniqueLocalPrefix == null || !url.startsWith("#")) { 991 return url; 992 } 993 return "#"+uniqueLocalPrefix+"-"+url.substring(1); 994 } 995 996 public String getUniqueLocalPrefix() { 997 return uniqueLocalPrefix; 998 } 999 1000 public void setUniqueLocalPrefix(String uniqueLocalPrefix) { 1001 this.uniqueLocalPrefix = uniqueLocalPrefix; 1002 } 1003 1004 public RenderingContext withUniqueLocalPrefix(String uniqueLocalPrefix) { 1005 RenderingContext self = this.copy(true); 1006 self.uniqueLocalPrefix = uniqueLocalPrefix; 1007 return self; 1008 } 1009 1010 public RenderingContext forContained() { 1011 RenderingContext self = this.copy(true); 1012 self.contained = true; 1013 return self; 1014 } 1015 1016 public boolean hasAnchor(String anchor) { 1017 return anchors.contains(anchor); 1018 } 1019 1020 public void addAnchor(String anchor) { 1021 anchors.add(anchor); 1022 } 1023 1024 public Set<String> getAnchors() { 1025 return anchors; 1026 } 1027 1028 public void clearAnchors() { 1029 anchors.clear(); 1030 } 1031 1032 public boolean isUnknownLocalReferencesNotLinks() { 1033 return unknownLocalReferencesNotLinks; 1034 } 1035 1036 public void setUnknownLocalReferencesNotLinks(boolean unknownLocalReferencesNotLinks) { 1037 this.unknownLocalReferencesNotLinks = unknownLocalReferencesNotLinks; 1038 } 1039}