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