
001package org.hl7.fhir.r5.renderers.utils; 002 003import java.util.Collection; 004import java.util.Locale; 005 006import org.hl7.fhir.r5.model.Base; 007import org.hl7.fhir.r5.model.DomainResource; 008import org.hl7.fhir.r5.model.ElementDefinition; 009import org.hl7.fhir.r5.model.Enumeration; 010import org.hl7.fhir.r5.model.Narrative; 011import org.hl7.fhir.r5.model.Property; 012import org.hl7.fhir.r5.model.Resource; 013import org.hl7.fhir.r5.utils.UserDataNames; 014import org.hl7.fhir.utilities.MarkedToMoveToAdjunctPackage; 015import org.hl7.fhir.utilities.xhtml.NodeType; 016import org.hl7.fhir.utilities.xhtml.XhtmlNode; 017 018/** 019 * This class is used to walk through the resources when rendering, whether 020 * the resource is a native resource or loaded by the element model 021 */ 022@MarkedToMoveToAdjunctPackage 023public class ResourceWrapperNative extends ResourceWrapper { 024 025 protected Base element; 026 027 ResourceWrapperNative() { 028 super(); 029 } 030 031 private ResourceWrapper makeChild(String name, int index, ElementKind kind, Base element) { 032 ResourceWrapperNative self = new ResourceWrapperNative(); 033 self.contextUtils = this.contextUtils; 034 self.parent = this; 035 self.name = name; 036 self.index = index; 037 self.kind = kind; 038 self.element = element; 039 return self; 040 } 041 042 public String fhirVersion() { 043 return element.getFHIRPublicationVersion().toCode(); 044 } 045 046 public String fhirType() { 047 if (kind == ElementKind.BackboneElement) { 048 return basePath(); 049 } else { 050 return element.fhirType(); 051 } 052 } 053 054 public boolean isPrimitive() { 055 return element.isPrimitive(); 056 } 057 058 public boolean hasPrimitiveValue() { 059 return element.hasPrimitiveValue(); 060 } 061 062 public String primitiveValue() { 063 return element.primitiveValue(); 064 } 065 066 protected void loadTheChildren() { 067 068 for (Property p : element.children()) { 069 String name = p.getName(); 070 int i = 0; 071 for (Base v : p.getValues()) { 072 loadElementChild(p, name, i, v); 073 i++; 074 } 075 } 076 } 077 078 private void loadElementChild(Property p, String name, int i, Base v) { 079 ElementKind kind = determineModelKind(p, v); 080 int index = p.isList() ? i : -1; 081 ElementDefinition ed = null; 082 children.add(makeChild(name, index, kind, v)); 083 } 084 085 private ElementKind determineModelKind(Property p, Base v) { 086 if (v.isPrimitive()) { 087 return ElementKind.PrimitiveType; 088 } else if (contextUtils.isDatatype(v.fhirType())) { 089 return ElementKind.DataType; 090 } else if (!v.isResource()) { 091 return ElementKind.BackboneElement; 092 } else if ("Bundle.entry".equals(fhirType()) && "resource".equals(p.getName())) { 093 return ElementKind.BundleEntry; 094 } else if ("Bundle".equals(fhirType()) && "outcome".equals(p.getName())) { 095 return ElementKind.InlineResource; 096 } else if ("Bundle".equals(fhirType()) && "issues".equals(p.getName())) { 097 return ElementKind.InlineResource; 098 } else if (isResource() && "contained".equals(p.getName())) { 099 return ElementKind.ContainedResource; 100 } else { 101 return ElementKind.InlineResource; 102 } 103 } 104 105 public boolean isResource() { 106 return element.isResource(); 107 } 108 109 public boolean canHaveNarrative() { 110 if (!isResource()) { 111 return false; 112 } 113 return element instanceof DomainResource; 114 } 115 116 public XhtmlNode getNarrative() { 117 if (!canHaveNarrative()) { 118 return null; 119 } 120 ResourceWrapper text = child("text"); 121 if (text == null) { 122 return null; 123 } 124 ResourceWrapper div = text.child("div"); 125 if (div == null) { 126 return null; 127 } 128 return ((ResourceWrapperNative) div).element.getXhtml(); 129 } 130 131 public boolean hasNarrative() { 132 if (!canHaveNarrative()) { 133 return false; 134 } 135 ResourceWrapper text = child("text"); 136 if (text == null) { 137 return false; 138 } 139 ResourceWrapper div = text.child("div"); 140 if (div == null) { 141 return false; 142 } 143 return ((ResourceWrapperNative) div).element.getXhtml() != null; 144 } 145 146 public void setNarrative(XhtmlNode x, String status, boolean multiLangMode, Locale locale, boolean isPretty) { 147 if (element instanceof DomainResource) { 148 DomainResource r = (DomainResource) element; 149 r.getText().setUserData(UserDataNames.renderer_is_generated, true); 150 if (!r.hasText() || !r.getText().hasDiv()) { 151 r.setText(new Narrative()); 152 r.getText().setStatusAsString(status); 153 } 154 if (multiLangMode) { 155 if (!r.getText().hasDiv()) { 156 XhtmlNode div = new XhtmlNode(NodeType.Element, "div"); 157 div.setAttribute("xmlns", "http://www.w3.org/1999/xhtml"); 158 r.getText().setDiv(div); 159 } else { 160 r.getText().getDiv().getChildNodes().removeIf(c -> !"div".equals(c.getName()) || !c.hasAttribute("xml:lang")); 161 } 162 markLanguage(x, locale); 163 r.getText().getDiv().addChildNode(x); 164 } else { 165 if (!x.hasAttribute("xmlns")) 166 x.setAttribute("xmlns", "http://www.w3.org/1999/xhtml"); 167 if (r.hasLanguage()) { 168 // use both - see https://www.w3.org/TR/i18n-html-tech-lang/#langvalues 169 x.setAttribute("lang", r.getLanguage()); 170 x.setAttribute("xml:lang", r.getLanguage()); 171 } 172 r.getText().setDiv(x); 173 } 174 } else { 175 throw new Error("Cannot call setNarrative on a "+element.fhirType()); 176 } 177 } 178 179 public void markLanguage(XhtmlNode x, Locale locale) { 180 x.setAttribute("lang", locale.toLanguageTag()); 181 x.setAttribute("xml:lang", locale.toLanguageTag()); 182 x.addTag(0, "hr"); 183 x.addTag(0, "p").b().tx(locale.getDisplayName()); 184 x.addTag(0, "hr"); 185 } 186 187 188 public String getId() { 189 return element.getIdBase(); 190 } 191 192 @Override 193 public String toString() { 194 return name + (index == -1 ? "" : "["+index+"]")+": "+fhirType()+" ("+kind+"/"+path()+"): native = "+element.fhirType()+" -> "+element.toString(); 195 } 196 197 public Resource getResourceNative() { 198 ResourceWrapper focus = getResourceWrapper(); 199 return focus == null ? null : (Resource) ((ResourceWrapperNative) focus).element; 200 } 201 202 public boolean hasFormatComment() { 203 return element.hasFormatComment(); 204 } 205 206 public Collection<String> getFormatCommentsPre() { 207 return element.getFormatCommentsPre(); 208 } 209 210 public XhtmlNode getXhtml() { 211 return element.getXhtml(); 212 } 213 214 public Base getBase() { 215 return element; 216 } 217 218 public boolean isDirect() { 219 return true; 220 } 221 222 public String getWebPath() { 223 if (isResource()) { 224 return ((Resource) element).getWebPath(); 225 } else { 226 return null; 227 } 228 } 229 230 public String getCodeSystemUri() { 231 if (element instanceof Enumeration<?>) { 232 return ((Enumeration<?>) element).getSystem(); 233 } 234 return null; 235 } 236 237 @Override 238 public boolean hasUserData(String name) { 239 return element.hasUserData(name); 240 } 241 242 @Override 243 public Object getUserData(String name) { 244 return element.getUserData(name); 245 } 246 247}