001package org.hl7.fhir.r5.renderers.utils; 002 003import java.io.IOException; 004import java.io.UnsupportedEncodingException; 005import java.util.ArrayList; 006import java.util.List; 007 008import org.hl7.fhir.exceptions.FHIRException; 009import org.hl7.fhir.exceptions.FHIRFormatError; 010import org.hl7.fhir.r5.conformance.ProfileUtilities; 011import org.hl7.fhir.r5.model.Base; 012import org.hl7.fhir.r5.model.ElementDefinition; 013import org.hl7.fhir.r5.model.StructureDefinition; 014import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind; 015import org.hl7.fhir.r5.renderers.ResourceRenderer; 016import org.hl7.fhir.r5.renderers.utils.BaseWrappers.BaseWrapper; 017import org.hl7.fhir.r5.renderers.utils.BaseWrappers.PropertyWrapper; 018import org.hl7.fhir.r5.renderers.utils.BaseWrappers.RendererWrapperImpl; 019import org.hl7.fhir.r5.renderers.utils.BaseWrappers.ResourceWrapper; 020import org.hl7.fhir.r5.renderers.utils.BaseWrappers.WrapperBaseImpl; 021import org.hl7.fhir.r5.utils.NarrativeGenerator; 022import org.hl7.fhir.utilities.Utilities; 023import org.hl7.fhir.utilities.xhtml.XhtmlNode; 024import org.hl7.fhir.utilities.xhtml.XhtmlParser; 025import org.hl7.fhir.utilities.xml.XMLUtil; 026import org.hl7.fhir.utilities.xml.XmlGenerator; 027import org.w3c.dom.Element; 028 029public class DOMWrappers { 030 031 032 public static class BaseWrapperElement extends WrapperBaseImpl implements BaseWrapper { 033 private Element element; 034 private String type; 035 private StructureDefinition structure; 036 private ElementDefinition definition; 037 private List<ElementDefinition> children; 038 private List<PropertyWrapper> list; 039 040 public BaseWrapperElement(ResourceRenderer renderer, Element element, String type, StructureDefinition structure, ElementDefinition definition) { 041 super(renderer); 042 this.element = element; 043 this.type = type; 044 this.structure = structure; 045 this.definition = definition; 046 } 047 048 @Override 049 public Base getBase() throws UnsupportedEncodingException, IOException, FHIRException { 050 if (type == null || type.equals("Resource") || type.equals("BackboneElement") || type.equals("Element")) 051 return null; 052 053 String xml; 054 try { 055 xml = new XmlGenerator().generate(element); 056 } catch (org.hl7.fhir.exceptions.FHIRException e) { 057 throw new FHIRException(e.getMessage(), e); 058 } 059 return renderer.parseType(xml, type); 060 } 061 062 @Override 063 public List<PropertyWrapper> children() { 064 if (list == null) { 065 children = renderer.getContext().getProfileUtilities().getChildList(structure, definition); 066 list = new ArrayList<PropertyWrapper>(); 067 for (ElementDefinition child : children) { 068 List<Element> elements = new ArrayList<Element>(); 069 XMLUtil.getNamedChildrenWithWildcard(element, tail(child.getPath()), elements); 070 list.add(new PropertyWrapperElement(renderer, structure, child, elements)); 071 } 072 } 073 return list; 074 } 075 076 @Override 077 public PropertyWrapper getChildByName(String name) { 078 for (PropertyWrapper p : children()) 079 if (p.getName().equals(name)) 080 return p; 081 return null; 082 } 083 084 } 085 086 public static class PropertyWrapperElement extends RendererWrapperImpl implements PropertyWrapper { 087 088 private StructureDefinition structure; 089 private ElementDefinition definition; 090 private List<Element> values; 091 private List<BaseWrapper> list; 092 093 public PropertyWrapperElement(ResourceRenderer renderer, StructureDefinition structure, ElementDefinition definition, List<Element> values) { 094 super(renderer); 095 this.structure = structure; 096 this.definition = definition; 097 this.values = values; 098 } 099 100 @Override 101 public String getName() { 102 return tail(definition.getPath()); 103 } 104 105 @Override 106 public boolean hasValues() { 107 return values.size() > 0; 108 } 109 110 @Override 111 public List<BaseWrapper> getValues() { 112 if (list == null) { 113 list = new ArrayList<BaseWrapper>(); 114 for (Element e : values) 115 list.add(new BaseWrapperElement(renderer, e, determineType(e), structure, definition)); 116 } 117 return list; 118 } 119 private String determineType(Element e) { 120 if (definition.getType().isEmpty()) 121 return null; 122 if (definition.getType().size() == 1) { 123 if (definition.getType().get(0).getWorkingCode().equals("Element") || definition.getType().get(0).getWorkingCode().equals("BackboneElement")) 124 return null; 125 return definition.getType().get(0).getWorkingCode(); 126 } 127 String t = e.getNodeName().substring(tail(definition.getPath()).length()-3); 128 129 if (isPrimitive(Utilities.uncapitalize(t))) 130 return Utilities.uncapitalize(t); 131 else 132 return t; 133 } 134 135 private boolean isPrimitive(String code) { 136 StructureDefinition sd = renderer.getContext().getWorker().fetchTypeDefinition(code); 137 return sd != null && sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE; 138 } 139 140 @Override 141 public String getTypeCode() { 142 if (definition == null || definition.getType().size() != 1) 143 throw new Error("not handled"); 144 return definition.getType().get(0).getWorkingCode(); 145 } 146 147 @Override 148 public String getDefinition() { 149 if (definition == null) 150 throw new Error("not handled"); 151 return definition.getDefinition(); 152 } 153 154 @Override 155 public int getMinCardinality() { 156 if (definition == null) 157 throw new Error("not handled"); 158 return definition.getMin(); 159 } 160 161 @Override 162 public int getMaxCardinality() { 163 if (definition == null) 164 throw new Error("not handled"); 165 return definition.getMax().equals("*") ? Integer.MAX_VALUE : Integer.parseInt(definition.getMax()); 166 } 167 168 @Override 169 public StructureDefinition getStructure() { 170 return structure; 171 } 172 173 @Override 174 public BaseWrapper value() { 175 if (getValues().size() != 1) 176 throw new Error("Access single value, but value count is "+getValues().size()); 177 return getValues().get(0); 178 } 179 180 } 181 182 public static class ResourceWrapperElement extends WrapperBaseImpl implements ResourceWrapper { 183 184 private Element wrapped; 185 private StructureDefinition definition; 186 private List<ResourceWrapper> list; 187 private List<PropertyWrapper> list2; 188 189 public ResourceWrapperElement(ResourceRenderer renderer, Element wrapped, StructureDefinition definition) { 190 super(renderer); 191 this.wrapped = wrapped; 192 this.definition = definition; 193 } 194 195 @Override 196 public List<ResourceWrapper> getContained() { 197 if (list == null) { 198 List<Element> children = new ArrayList<Element>(); 199 XMLUtil.getNamedChildren(wrapped, "contained", children); 200 list = new ArrayList<ResourceWrapper>(); 201 for (Element e : children) { 202 Element c = XMLUtil.getFirstChild(e); 203 list.add(new ResourceWrapperElement(renderer, c, renderer.getContext().getWorker().fetchTypeDefinition(c.getNodeName()))); 204 } 205 } 206 return list; 207 } 208 209 @Override 210 public String getId() { 211 return XMLUtil.getNamedChildValue(wrapped, "id"); 212 } 213 214 @Override 215 public XhtmlNode getNarrative() throws FHIRFormatError, IOException, FHIRException { 216 Element txt = XMLUtil.getNamedChild(wrapped, "text"); 217 if (txt == null) 218 return null; 219 Element div = XMLUtil.getNamedChild(txt, "div"); 220 if (div == null) 221 return null; 222 try { 223 return new XhtmlParser().parse(new XmlGenerator().generate(div), "div"); 224 } catch (org.hl7.fhir.exceptions.FHIRFormatError e) { 225 throw new FHIRFormatError(e.getMessage(), e); 226 } catch (org.hl7.fhir.exceptions.FHIRException e) { 227 throw new FHIRException(e.getMessage(), e); 228 } 229 } 230 231 @Override 232 public String getName() { 233 return wrapped.getNodeName(); 234 } 235 236 @Override 237 public List<PropertyWrapper> children() { 238 if (list2 == null) { 239 List<ElementDefinition> children = renderer.getContext().getProfileUtilities().getChildList(definition, definition.getSnapshot().getElement().get(0)); 240 list2 = new ArrayList<PropertyWrapper>(); 241 for (ElementDefinition child : children) { 242 List<Element> elements = new ArrayList<Element>(); 243 XMLUtil.getNamedChildrenWithWildcard(wrapped, tail(child.getPath()), elements); 244 list2.add(new PropertyWrapperElement(renderer, definition, child, elements)); 245 } 246 } 247 return list2; 248 } 249 250 251 252 @Override 253 public void describe(XhtmlNode x) { 254 throw new Error("Not done yet"); 255 } 256 } 257 258}