001package org.hl7.fhir.r4.elementmodel; 002 003import java.io.IOException; 004import java.io.InputStream; 005import java.io.OutputStream; 006import java.util.HashMap; 007import java.util.List; 008import java.util.Map; 009 010import org.hl7.fhir.r4.context.IWorkerContext; 011import org.hl7.fhir.r4.formats.FormatUtilities; 012import org.hl7.fhir.r4.formats.IParser.OutputStyle; 013import org.hl7.fhir.r4.model.StructureDefinition; 014import org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionKind; 015import org.hl7.fhir.r4.model.StructureDefinition.TypeDerivationRule; 016import org.hl7.fhir.r4.utils.ToolingExtensions; 017import org.hl7.fhir.exceptions.DefinitionException; 018import org.hl7.fhir.exceptions.FHIRException; 019import org.hl7.fhir.exceptions.FHIRFormatError; 020import org.hl7.fhir.utilities.Utilities; 021import org.hl7.fhir.utilities.validation.ValidationMessage; 022import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity; 023import org.hl7.fhir.utilities.validation.ValidationMessage.IssueType; 024import org.hl7.fhir.utilities.validation.ValidationMessage.Source; 025 026public abstract class ParserBase { 027 028 public interface ILinkResolver { 029 String resolveType(String type); 030 String resolveProperty(Property property); 031 String resolvePage(String string); 032 } 033 034 public enum ValidationPolicy { NONE, QUICK, EVERYTHING } 035 036 public boolean isPrimitive(String code) { 037 return Utilities.existsInList(code, "boolean", "integer", "string", "decimal", "uri", "base64Binary", "instant", "date", "dateTime", "time", "code", "oid", "id", "markdown", "unsignedInt", "positiveInt", "xhtml", "url", "canonical"); 038 039// StructureDefinition sd = context.fetchTypeDefinition(code); 040// return sd != null && sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE; 041 } 042 043 protected IWorkerContext context; 044 protected ValidationPolicy policy; 045 protected List<ValidationMessage> errors; 046 protected ILinkResolver linkResolver; 047 protected boolean showDecorations; 048 049 public ParserBase(IWorkerContext context) { 050 super(); 051 this.context = context; 052 policy = ValidationPolicy.NONE; 053 } 054 055 public void setupValidation(ValidationPolicy policy, List<ValidationMessage> errors) { 056 this.policy = policy; 057 this.errors = errors; 058 } 059 060 public abstract Element parse(InputStream stream) throws IOException, FHIRFormatError, DefinitionException, FHIRException; 061 062 public abstract void compose(Element e, OutputStream destination, OutputStyle style, String base) throws FHIRException, IOException; 063 064 065 public void logError(int line, int col, String path, IssueType type, String message, IssueSeverity level) throws FHIRFormatError { 066 if (policy == ValidationPolicy.EVERYTHING) { 067 ValidationMessage msg = new ValidationMessage(Source.InstanceValidator, type, line, col, path, message, level); 068 errors.add(msg); 069 } else if (level == IssueSeverity.FATAL || (level == IssueSeverity.ERROR && policy == ValidationPolicy.QUICK)) 070 throw new FHIRFormatError(message+String.format(" at line %d col %d", line, col)); 071 } 072 073 074 protected StructureDefinition getDefinition(int line, int col, String ns, String name) throws FHIRFormatError { 075 if (ns == null) { 076 logError(line, col, name, IssueType.STRUCTURE, "This cannot be parsed as a FHIR object (no namespace)", IssueSeverity.FATAL); 077 return null; 078 } 079 if (name == null) { 080 logError(line, col, name, IssueType.STRUCTURE, "This cannot be parsed as a FHIR object (no name)", IssueSeverity.FATAL); 081 return null; 082 } 083 for (StructureDefinition sd : context.allStructures()) { 084 if (name.equals(sd.getType()) && sd.getDerivation() == TypeDerivationRule.SPECIALIZATION && !sd.getUrl().startsWith("http://hl7.org/fhir/StructureDefinition/de-")) { 085 if((ns == null || ns.equals(FormatUtilities.FHIR_NS)) && !ToolingExtensions.hasExtension(sd, "http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace")) 086 return sd; 087 String sns = ToolingExtensions.readStringExtension(sd, "http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace"); 088 if (ns != null && ns.equals(sns)) 089 return sd; 090 } 091 } 092 logError(line, col, name, IssueType.STRUCTURE, "This does not appear to be a FHIR resource (unknown namespace/name '"+ns+"::"+name+"')", IssueSeverity.FATAL); 093 return null; 094 } 095 096 protected StructureDefinition getDefinition(int line, int col, String name) throws FHIRFormatError { 097 if (name == null) { 098 logError(line, col, name, IssueType.STRUCTURE, "This cannot be parsed as a FHIR object (no name)", IssueSeverity.FATAL); 099 return null; 100 } 101 // first pass: only look at base definitions 102 for (StructureDefinition sd : context.allStructures()) { 103 if (sd.getUrl().equals("http://hl7.org/fhir/StructureDefinition/"+name)) { 104 return sd; 105 } 106 } 107 for (StructureDefinition sd : context.allStructures()) { 108 if (name.equals(sd.getType()) && sd.getDerivation() == TypeDerivationRule.SPECIALIZATION) { 109 return sd; 110 } 111 } 112 logError(line, col, name, IssueType.STRUCTURE, "This does not appear to be a FHIR resource (unknown name '"+name+"')", IssueSeverity.FATAL); 113 return null; 114 } 115 116 public ILinkResolver getLinkResolver() { 117 return linkResolver; 118 } 119 120 public ParserBase setLinkResolver(ILinkResolver linkResolver) { 121 this.linkResolver = linkResolver; 122 return this; 123 } 124 125 public boolean isShowDecorations() { 126 return showDecorations; 127 } 128 129 public void setShowDecorations(boolean showDecorations) { 130 this.showDecorations = showDecorations; 131 } 132 133 134}