001package org.hl7.fhir.r5.elementmodel; 002 003import java.io.IOException; 004import java.io.InputStream; 005import java.io.OutputStream; 006import java.util.List; 007 008import org.apache.commons.lang3.NotImplementedException; 009import org.hl7.fhir.exceptions.DefinitionException; 010import org.hl7.fhir.exceptions.FHIRException; 011import org.hl7.fhir.exceptions.FHIRFormatError; 012import org.hl7.fhir.r5.conformance.profile.ProfileUtilities; 013import org.hl7.fhir.r5.context.IWorkerContext; 014import org.hl7.fhir.r5.elementmodel.Element.SpecialElement; 015import org.hl7.fhir.r5.formats.IParser.OutputStyle; 016import org.hl7.fhir.r5.model.Base; 017import org.hl7.fhir.r5.model.Resource; 018import org.hl7.fhir.r5.model.StructureDefinition; 019import org.hl7.fhir.utilities.Utilities; 020import org.hl7.fhir.utilities.i18n.I18nConstants; 021import org.hl7.fhir.utilities.xhtml.XhtmlComposer; 022 023public class ResourceParser extends ParserBase { 024 025 public ResourceParser(IWorkerContext context) { 026 super(context); 027 } 028 029 @Override 030 public List<ValidatedFragment> parse(InputStream stream) throws IOException, FHIRFormatError, DefinitionException, FHIRException { 031 throw new NotImplementedException("parse(InputStream stream)"); // doesns't make sense 032 } 033 034 @Override 035 public void compose(Element e, OutputStream destination, OutputStyle style, String base) 036 throws FHIRException, IOException { 037 throw new NotImplementedException("compose(Element e, OutputStream destination, OutputStyle style, String base)"); // doesns't make sense 038 } 039 040 /** 041 * It's possible to get an element model from an resource by writing it to a stream, and reading it, 042 * but this loads it directly, and links to the element model from the resource model 043 * 044 * @param resource 045 * @return 046 * @throws IOException 047 */ 048 public Element parse(Resource resource) { 049 StructureDefinition sd = context.fetchTypeDefinition(resource.fhirType()); 050 if (sd == null) { 051 throw new FHIRException("No definition exists for "+resource.fhirType()); 052 } 053 Property p = new Property(context, sd.getSnapshot().getElement().get(0), sd, getProfileUtilities(), getContextUtilities()); 054 String path = resource.fhirType(); 055 056 Element e = new Element(resource.fhirType(), p); 057 e.setPath(path); 058 e.setType(resource.fhirType()); 059 parseChildren(path, resource, e); 060 e.numberChildren(); 061 return e; 062 } 063 064 private void parseChildren(String path, Base src, Element dst) { 065 dst.setSource(src); 066 dst.copyFormatComments(src); 067 List<Property> properties = dst.getProperty().getChildProperties(dst.getName(), null); 068 for (org.hl7.fhir.r5.model.Property c : src.children()) { 069 if (c.hasValues()) { 070 Property p = getPropertyByName(properties, c.getName()); 071 if (p == null) { 072 throw new FHIRException("Unable to find property for "+path+"."+c.getName()); 073 } 074 int i = 0; 075 for (Base v : c.getValues()) { 076 String npath = path+"."+c.getName()+(p.isList() ? "["+i+"]" : ""); 077 i++; 078 String name = c.getName(); 079 if (name.endsWith("[x]")) { 080 name = name.substring(0, name.length()-3)+Utilities.capitalize(v.fhirType()); 081 } 082 Element n = new Element(name, p); 083 dst.getChildren().add(n); 084 if (v.isPrimitive()) { 085 if (v.fhirType().equals("xhtml")) { 086 n.setXhtml(v.getXhtml()); 087 try { 088 n.setValue(new XhtmlComposer(true).compose(n.getXhtml())); 089 } catch (Exception e) { 090 // won't happen here 091 } 092 } else { 093 n.setValue(v.primitiveValue()); 094 } 095// if (!n.getProperty().isChoice() && n.getType().equals("xhtml")) { 096// try { 097// n.setXhtml(new XhtmlParser().setValidatorMode(policy == ValidationPolicy.EVERYTHING).parse(n.getValue(), null).getDocumentElement()); 098// } catch (Exception e) { 099// logError(line(main), col(main), npath, IssueType.INVALID, context.formatMessage(I18nConstants.ERROR_PARSING_XHTML_, e.getMessage()), IssueSeverity.ERROR); 100// } 101// } 102// } 103 } 104 n.setPath(npath); 105 if (p.isResource()) { 106 StructureDefinition sd = context.fetchResource(StructureDefinition.class, ProfileUtilities.sdNs(v.fhirType(), null)); 107 if (sd == null) 108 throw new FHIRFormatError(context.formatMessage(I18nConstants.CONTAINED_RESOURCE_DOES_NOT_APPEAR_TO_BE_A_FHIR_RESOURCE_UNKNOWN_NAME_, v.fhirType())); 109 n.updateProperty(new Property(context, sd.getSnapshot().getElement().get(0), sd, getProfileUtilities(), getContextUtilities()), SpecialElement.fromProperty(n.getProperty()), p); 110 n.setType(v.fhirType()); 111 parseChildren(npath, v, n); 112 } else { 113 parseChildren(npath, v, n); 114 } 115 } 116 } 117 } 118 119 } 120 121 private Property getPropertyByName(List<Property> properties, String name) { 122 for (Property p : properties) { 123 if (p.getName().equals(name)) { 124 return p; 125 } 126 } 127 return null; 128 129 } 130} 131