diff --git a/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/model/ExpressionNode.java b/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/model/ExpressionNode.java index 3a6780906..cc3fb058a 100644 --- a/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/model/ExpressionNode.java +++ b/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/model/ExpressionNode.java @@ -56,7 +56,7 @@ public class ExpressionNode { Encode, Decode, Escape, Unescape, Trim, Split, Join, LowBoundary, HighBoundary, Precision, // Local extensions to FHIRPath - HtmlChecks1, HtmlChecks2, AliasAs, Alias, Comparable; + HtmlChecks1, HtmlChecks2, AliasAs, Alias; public static Function fromCode(String name) { if (name.equals("empty")) return Function.Empty; @@ -118,7 +118,6 @@ public class ExpressionNode { if (name.equals("htmlChecks")) return Function.HtmlChecks1; if (name.equals("htmlchecks")) return Function.HtmlChecks1; // support change of care from R3 if (name.equals("htmlChecks2")) return Function.HtmlChecks2; - if (name.equals("comparable")) return Function.Comparable; if (name.equals("encode")) return Function.Encode; if (name.equals("decode")) return Function.Decode; if (name.equals("escape")) return Function.Escape; @@ -153,7 +152,7 @@ public class ExpressionNode { if (name.equals("ln")) return Function.Ln; if (name.equals("log")) return Function.Log; if (name.equals("power")) return Function.Power; - if (name.equals("truncate")) return Function.Truncate; + if (name.equals("truncate")) return Function.Truncate; if (name.equals("lowBoundary")) return Function.LowBoundary; if (name.equals("highBoundary")) return Function.HighBoundary; if (name.equals("precision")) return Function.Precision; @@ -227,7 +226,6 @@ public class ExpressionNode { case Join : return "join"; case HtmlChecks1 : return "htmlChecks"; case HtmlChecks2 : return "htmlChecks2"; - case Comparable : return "comparable"; case OfType : return "ofType"; case Type : return "type"; case ToInteger : return "toInteger"; diff --git a/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/model/TypeDetails.java b/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/model/TypeDetails.java index 7c5980b32..07f7b067f 100644 --- a/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/model/TypeDetails.java +++ b/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/model/TypeDetails.java @@ -49,15 +49,15 @@ import org.hl7.fhir.utilities.Utilities; public class TypeDetails { public static final String FHIR_NS = "http://hl7.org/fhir/StructureDefinition/"; public static final String FP_NS = "http://hl7.org/fhirpath/"; - public static final String FP_String = "http://hl7.org/fhirpath/System.String"; - public static final String FP_Boolean = "http://hl7.org/fhirpath/System.Boolean"; - public static final String FP_Integer = "http://hl7.org/fhirpath/System.Integer"; - public static final String FP_Decimal = "http://hl7.org/fhirpath/System.Decimal"; - public static final String FP_Quantity = "http://hl7.org/fhirpath/System.Quantity"; - public static final String FP_DateTime = "http://hl7.org/fhirpath/System.DateTime"; - public static final String FP_Time = "http://hl7.org/fhirpath/System.Time"; - public static final String FP_SimpleTypeInfo = "http://hl7.org/fhirpath/System.SimpleTypeInfo"; - public static final String FP_ClassInfo = "http://hl7.org/fhirpath/System.ClassInfo"; + public static final String FP_String = "http://hl7.org/fhirpath/String"; + public static final String FP_Boolean = "http://hl7.org/fhirpath/Boolean"; + public static final String FP_Integer = "http://hl7.org/fhirpath/Integer"; + public static final String FP_Decimal = "http://hl7.org/fhirpath/Decimal"; + public static final String FP_Quantity = "http://hl7.org/fhirpath/Quantity"; + public static final String FP_DateTime = "http://hl7.org/fhirpath/DateTime"; + public static final String FP_Time = "http://hl7.org/fhirpath/Time"; + public static final String FP_SimpleTypeInfo = "http://hl7.org/fhirpath/SimpleTypeInfo"; + public static final String FP_ClassInfo = "http://hl7.org/fhirpath/ClassInfo"; public static final Set FP_NUMBERS = new HashSet(Arrays.asList(FP_Integer, FP_Decimal)); public static class ProfiledType { @@ -187,7 +187,7 @@ public class TypeDetails { if (typesContains(t)) return true; if (Utilities.existsInList(n, "boolean", "string", "integer", "decimal", "Quantity", "dateTime", "time", "ClassInfo", "SimpleTypeInfo")) { - t = FP_NS+"System."+Utilities.capitalize(n); + t = FP_NS+Utilities.capitalize(n); if (typesContains(t)) return true; } @@ -224,7 +224,7 @@ public class TypeDetails { if (url.startsWith("http://hl7.org/fhir/StructureDefinition/")) { String code = url.substring(40); if (Utilities.existsInList(code, "string", "boolean", "integer", "decimal", "dateTime", "time", "Quantity")) - return FP_NS+"System."+Utilities.capitalize(code); + return FP_NS+Utilities.capitalize(code); } return null; } @@ -299,7 +299,7 @@ public class TypeDetails { if (typesContains(t)) return true; if (Utilities.existsInList(n, "boolean", "string", "integer", "decimal", "Quantity", "date", "dateTime", "time", "ClassInfo", "SimpleTypeInfo")) { - t = FP_NS+"System."+Utilities.capitalize(n); + t = FP_NS+Utilities.capitalize(n); if (typesContains(t)) return true; } @@ -312,7 +312,7 @@ public class TypeDetails { if (typesContains(t)) return true; if (Utilities.existsInList(n, "boolean", "string", "integer", "decimal", "Quantity", "dateTime", "time", "ClassInfo", "SimpleTypeInfo")) { - t = FP_NS+"System."+Utilities.capitalize(n); + t = FP_NS+Utilities.capitalize(n); if (typesContains(t)) return true; } @@ -360,8 +360,4 @@ public class TypeDetails { } - public boolean matches(TypeDetails other) { - return collectionStatus == other.collectionStatus && types.equals(other.types); - } - } \ No newline at end of file diff --git a/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/utils/FHIRPathEngine.java b/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/utils/FHIRPathEngine.java index 1d10f66eb..15d82473c 100644 --- a/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/utils/FHIRPathEngine.java +++ b/org.hl7.fhir.r4b/src/main/java/org/hl7/fhir/r4b/utils/FHIRPathEngine.java @@ -59,7 +59,6 @@ import org.hl7.fhir.r4b.model.ValueSet; import org.hl7.fhir.r4b.utils.FHIRLexer.FHIRLexerException; import org.hl7.fhir.r4b.utils.FHIRPathEngine.IEvaluationContext.FunctionDetails; import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; -import org.hl7.fhir.utilities.MarkDownProcessor; import org.hl7.fhir.utilities.MergedList; import org.hl7.fhir.utilities.MergedList.MergeNode; import org.hl7.fhir.utilities.SourceLocation; @@ -596,7 +595,7 @@ public class FHIRPathEngine { } } - return executeType(new ExecutionTypeContext(appContext, resourceType, types, types), types, expr, true, false); + return executeType(new ExecutionTypeContext(appContext, resourceType, types, types), types, expr, true); } private FHIRException makeExceptionPlural(Integer num, ExpressionNode holder, String constName, Object... args) { @@ -645,13 +644,13 @@ public class FHIRPathEngine { } } - return executeType(new ExecutionTypeContext(appContext, sd.getUrl(), types, types), types, expr, true, false); + return executeType(new ExecutionTypeContext(appContext, sd.getUrl(), types, types), types, expr, true); } public TypeDetails check(Object appContext, StructureDefinition sd, ExpressionNode expr) throws FHIRLexerException, PathEngineException, DefinitionException { // if context is a path that refers to a type, do that conversion now TypeDetails types = null; // this is a special case; the first path reference will have to resolve to something in the context - return executeType(new ExecutionTypeContext(appContext, sd == null ? null : sd.getUrl(), null, types), types, expr, true, false); + return executeType(new ExecutionTypeContext(appContext, sd == null ? null : sd.getUrl(), null, types), types, expr, true); } public TypeDetails check(Object appContext, String resourceType, String context, String expr) throws FHIRLexerException, PathEngineException, DefinitionException { @@ -1401,7 +1400,6 @@ public class FHIRPathEngine { case Join: return checkParamCount(lexer, location, exp, 1); case HtmlChecks1: return checkParamCount(lexer, location, exp, 0); case HtmlChecks2: return checkParamCount(lexer, location, exp, 0); - case Comparable: return checkParamCount(lexer, location, exp, 1); case ToInteger: return checkParamCount(lexer, location, exp, 0); case ToDecimal: return checkParamCount(lexer, location, exp, 0); case ToString: return checkParamCount(lexer, location, exp, 0); @@ -1545,7 +1543,7 @@ public class FHIRPathEngine { return new TypeDetails(CollectionStatus.SINGLETON, exp.getName()); } - private TypeDetails executeType(ExecutionTypeContext context, TypeDetails focus, ExpressionNode exp, boolean atEntry, boolean canBeNone) throws PathEngineException, DefinitionException { + private TypeDetails executeType(ExecutionTypeContext context, TypeDetails focus, ExpressionNode exp, boolean atEntry) throws PathEngineException, DefinitionException { TypeDetails result = new TypeDetails(null); switch (exp.getKind()) { case Name: @@ -1561,17 +1559,13 @@ public class FHIRPathEngine { for (String s : focus.getTypes()) { result.update(executeType(s, exp, atEntry)); } - if (result.hasNoTypes()) { - if (!canBeNone) { - throw makeException(exp, I18nConstants.FHIRPATH_UNKNOWN_NAME, exp.getName(), focus.describe()); - } else { - // return result; - } + if (result.hasNoTypes()) { + throw makeException(exp, I18nConstants.FHIRPATH_UNKNOWN_NAME, exp.getName(), focus.describe()); } } break; case Function: - result.update(evaluateFunctionType(context, focus, exp, canBeNone)); + result.update(evaluateFunctionType(context, focus, exp)); break; case Unary: result.addType(TypeDetails.FP_Integer); @@ -1582,12 +1576,12 @@ public class FHIRPathEngine { result.update(resolveConstantType(context, exp.getConstant(), exp)); break; case Group: - result.update(executeType(context, focus, exp.getGroup(), atEntry, canBeNone)); + result.update(executeType(context, focus, exp.getGroup(), atEntry)); } exp.setTypes(result); if (exp.getInner() != null) { - result = executeType(context, result, exp.getInner(), false, false); + result = executeType(context, result, exp.getInner(), false); } if (exp.isProximal() && exp.getOperation() != null) { @@ -1598,7 +1592,7 @@ public class FHIRPathEngine { if (last.getOperation() == Operation.Is || last.getOperation() == Operation.As) { work = executeTypeName(context, focus, next, atEntry); } else { - work = executeType(context, focus, next, atEntry, canBeNone); + work = executeType(context, focus, next, atEntry); } result = operateTypes(result, last.getOperation(), work, last); last = next; @@ -3109,36 +3103,21 @@ public class FHIRPathEngine { } - private void evaluateParameters(ExecutionTypeContext context, TypeDetails focus, ExpressionNode exp, List paramTypes, boolean canBeNone) { - int i = 0; - for (ExpressionNode expr : exp.getParameters()) { - if (isExpressionParameter(exp, i)) { - paramTypes.add(executeType(changeThis(context, focus), focus, expr, true, canBeNone)); - } else { - paramTypes.add(executeType(context, context.thisItem, expr, true, canBeNone)); - } - i++; - } - } - @SuppressWarnings("unchecked") - private TypeDetails evaluateFunctionType(ExecutionTypeContext context, TypeDetails focus, ExpressionNode exp, boolean canBeNone) throws PathEngineException, DefinitionException { + private TypeDetails evaluateFunctionType(ExecutionTypeContext context, TypeDetails focus, ExpressionNode exp) throws PathEngineException, DefinitionException { List paramTypes = new ArrayList(); if (exp.getFunction() == Function.Is || exp.getFunction() == Function.As || exp.getFunction() == Function.OfType) { paramTypes.add(new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); - } else if (exp.getFunction() == Function.Repeat && exp.getParameters().size() == 1) { - TypeDetails base = focus; - boolean changed = false; - do { - evaluateParameters(context, base, exp, paramTypes, true); - changed = !paramTypes.get(0).matches(base); - if (changed) { - base = paramTypes.get(0); - paramTypes.clear(); - } - } while (changed); } else { - evaluateParameters(context, focus, exp, paramTypes, false); + int i = 0; + for (ExpressionNode expr : exp.getParameters()) { + if (isExpressionParameter(exp, i)) { + paramTypes.add(executeType(changeThis(context, focus), focus, expr, true)); + } else { + paramTypes.add(executeType(context, context.thisItem, expr, true)); + } + i++; + } } switch (exp.getFunction()) { case Empty : @@ -3166,11 +3145,11 @@ public class FHIRPathEngine { case Where : return focus; case Select : - return paramTypes.get(0); + return anything(focus.getCollectionStatus()); case All : return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); case Repeat : - return paramTypes.get(0); + return anything(focus.getCollectionStatus()); case Aggregate : return anything(focus.getCollectionStatus()); case Item : { @@ -3333,7 +3312,7 @@ public class FHIRPathEngine { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_DateTime); case Resolve : { checkContextReference(focus, "resolve", exp); - return new TypeDetails(CollectionStatus.ORDERED, "DomainResource"); + return new TypeDetails(CollectionStatus.SINGLETON, "DomainResource"); } case Extension : { checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); @@ -3353,8 +3332,6 @@ public class FHIRPathEngine { return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); case HtmlChecks2 : return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); - case Comparable : - return new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_Boolean); case Alias : checkParamTypes(exp, exp.getFunction().toCode(), paramTypes, new TypeDetails(CollectionStatus.SINGLETON, TypeDetails.FP_String)); return anything(CollectionStatus.SINGLETON); @@ -3661,7 +3638,6 @@ public class FHIRPathEngine { case Alias : return funcAlias(context, focus, exp); case HtmlChecks1 : return funcHtmlChecks1(context, focus, exp); case HtmlChecks2 : return funcHtmlChecks2(context, focus, exp); - case Comparable : return funcComparable(context, focus, exp); case ToInteger : return funcToInteger(context, focus, exp); case ToDecimal : return funcToDecimal(context, focus, exp); case ToString : return funcToString(context, focus, exp); @@ -3901,10 +3877,7 @@ public class FHIRPathEngine { } private List funcLowBoundary(ExecutionContext context, List focus, ExpressionNode expr) { - if (focus.size() == 0) { - return makeNull(); - } - if (focus.size() > 1) { + if (focus.size() != 1) { throw makeExceptionPlural(focus.size(), expr, I18nConstants.FHIRPATH_FOCUS, "lowBoundary", focus.size()); } int precision = 0; @@ -3927,11 +3900,6 @@ public class FHIRPathEngine { result.add(new DateTimeType(Utilities.lowBoundaryForDate(base.primitiveValue(), precision == 0 ? 17 : precision))); } else if (base.hasType("time")) { result.add(new TimeType(Utilities.lowBoundaryForTime(base.primitiveValue(), precision == 0 ? 9 : precision))); - } else if (base.hasType("Quantity")) { - String value = getNamedValue(base, "value"); - Base v = base; // .copy() - big issue - v.setProperty("value", new DecimalType(Utilities.lowBoundaryForDecimal(value, precision == 0 ? 8 : precision))); - result.add(v); } else { makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "sqrt", "(focus)", base.fhirType(), "decimal or date"); } @@ -3939,10 +3907,7 @@ public class FHIRPathEngine { } private List funcHighBoundary(ExecutionContext context, List focus, ExpressionNode expr) { - if (focus.size() == 0) { - return makeNull(); - } - if (focus.size() > 1) { + if (focus.size() != 1) { throw makeExceptionPlural(focus.size(), expr, I18nConstants.FHIRPATH_FOCUS, "highBoundary", focus.size()); } int precision = 0; @@ -3965,11 +3930,6 @@ public class FHIRPathEngine { result.add(new DateTimeType(Utilities.highBoundaryForDate(base.primitiveValue(), precision == 0 ? 17 : precision))); } else if (base.hasType("time")) { result.add(new TimeType(Utilities.highBoundaryForTime(base.primitiveValue(), precision == 0 ? 9 : precision))); - } else if (base.hasType("Quantity")) { - String value = getNamedValue(base, "value"); - Base v = base; // .copy() - big issue - v.setProperty("value", new DecimalType(Utilities.highBoundaryForDecimal(value, precision == 0 ? 8 : precision))); - result.add(v); } else { makeException(expr, I18nConstants.FHIRPATH_WRONG_PARAM_TYPE, "sqrt", "(focus)", base.fhirType(), "decimal or date"); } @@ -4091,10 +4051,6 @@ public class FHIRPathEngine { result.add(new StringType(Utilities.escapeXml(cnt))); } else if ("json".equals(param)) { result.add(new StringType(Utilities.escapeJson(cnt))); - } else if ("url".equals(param)) { - result.add(new StringType(Utilities.URLEncode(cnt))); - } else if ("md".equals(param)) { - result.add(new StringType(MarkDownProcessor.makeStringSafeAsMarkdown(cnt))); } } @@ -4112,10 +4068,6 @@ public class FHIRPathEngine { result.add(new StringType(Utilities.unescapeXml(cnt))); } else if ("json".equals(param)) { result.add(new StringType(Utilities.unescapeJson(cnt))); - } else if ("url".equals(param)) { - result.add(new StringType(Utilities.URLDecode(cnt))); - } else if ("md".equals(param)) { - result.add(new StringType(MarkDownProcessor.makeMarkdownForString(cnt))); } } @@ -4138,8 +4090,7 @@ public class FHIRPathEngine { List result = new ArrayList(); if (focus.size() == 1) { String cnt = focus.get(0).primitiveValue(); - String[] sl = Pattern.compile(param, Pattern.LITERAL).split(cnt); - for (String s : sl) { + for (String s : cnt.split(param)) { result.add(new StringType(s)); } } @@ -4149,14 +4100,9 @@ public class FHIRPathEngine { private List funcJoin(ExecutionContext context, List focus, ExpressionNode exp) { List nl = execute(context, focus, exp.getParameters().get(0), true); String param = nl.get(0).primitiveValue(); - String param2 = param; - if (exp.getParameters().size() == 2) { - nl = execute(context, focus, exp.getParameters().get(1), true); - param2 = nl.get(0).primitiveValue(); - } - + List result = new ArrayList(); - CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(param, param2); + CommaSeparatedStringBuilder b = new CommaSeparatedStringBuilder(param); for (Base i : focus) { b.append(i.primitiveValue()); } @@ -4218,47 +4164,6 @@ public class FHIRPathEngine { return false; } - private List funcComparable(ExecutionContext context, List focus, ExpressionNode exp) throws FHIRException { - if (focus.size() != 1 || !(focus.get(0).fhirType().equals("Quantity"))) { - return makeBoolean(false); - } - List nl = execute(context, focus, exp.getParameters().get(0), true); - if (nl.size() != 1 || !(nl.get(0).fhirType().equals("Quantity"))) { - return makeBoolean(false); - } - String s1 = getNamedValue(focus.get(0), "system"); - String u1 = getNamedValue(focus.get(0), "code"); - String s2 = getNamedValue(nl.get(0), "system"); - String u2 = getNamedValue(nl.get(0), "code"); - - if (s1 == null || s2 == null || !s1.equals(s2)) { - return makeBoolean(false); - } - if (u1 == null || u2 == null) { - return makeBoolean(false); - } - if (u1.equals(u2)) { - return makeBoolean(true); - } - if (s1.equals("http://unitsofmeasure.org") && worker.getUcumService() != null) { - try { - return makeBoolean(worker.getUcumService().isComparable(u1, u2)); - } catch (UcumException e) { - return makeBoolean(false); - } - } else { - return makeBoolean(false); - } - } - - - private String getNamedValue(Base base, String name) { - Property p = base.getChildByName(name); - if (p.hasValues() && p.getValues().size() == 1) { - return p.getValues().get(0).primitiveValue(); - } - return null; - } private boolean checkHtmlNames(XhtmlNode node) { if (node.getNodeType() == NodeType.Comment) { @@ -4959,11 +4864,10 @@ public class FHIRPathEngine { if (s != null) { Base res = null; if (s.startsWith("#")) { - String t = s.substring(1); Property p = context.rootResource.getChildByName("contained"); if (p != null) { for (Base c : p.getValues()) { - if (t.equals(c.getIdBase())) { + if (chompHash(s).equals(chompHash(c.getIdBase()))) { res = c; break; } @@ -4985,6 +4889,17 @@ public class FHIRPathEngine { return result; } + /** + * Strips a leading hashmark (#) if present at the start of a string + */ + private String chompHash(String theId) { + String retVal = theId; + while (retVal.startsWith("#")) { + retVal = retVal.substring(1); + } + return retVal; + } + private List funcExtension(ExecutionContext context, List focus, ExpressionNode exp) throws FHIRException { List result = new ArrayList(); List nl = execute(context, focus, exp.getParameters().get(0), true); @@ -5710,17 +5625,16 @@ public class FHIRPathEngine { } if (type.equals("http://hl7.org/fhir/StructureDefinition/xhtml")) { return; - } + } + if (type.startsWith(Constants.NS_SYSTEM_TYPE)) { + return; + } if (type.equals(TypeDetails.FP_SimpleTypeInfo)) { getSimpleTypeChildTypesByName(name, result); } else if (type.equals(TypeDetails.FP_ClassInfo)) { getClassInfoChildTypesByName(name, result); } else { - if (type.startsWith(Constants.NS_SYSTEM_TYPE)) { - return; - } - String url = null; if (type.contains("#")) { url = type.substring(0, type.indexOf("#")); @@ -5730,11 +5644,7 @@ public class FHIRPathEngine { String tail = ""; StructureDefinition sd = worker.fetchResource(StructureDefinition.class, url); if (sd == null) { - if (url.startsWith(TypeDetails.FP_NS)) { - return; - } else { - throw makeException(expr, I18nConstants.FHIRPATH_UNKNOWN_TYPE, url, "getChildTypesByName"); - } + throw makeException(expr, I18nConstants.FHIRPATH_NO_TYPE, url, "getChildTypesByName"); } List sdl = new ArrayList(); ElementDefinitionMatch m = null; @@ -5817,7 +5727,7 @@ public class FHIRPathEngine { for (TypeRefComponent t : ed.getDefinition().getType()) { if (Utilities.noString(t.getCode())) { if (Utilities.existsInList(ed.getDefinition().getId(), "Element.id", "Extension.url") || Utilities.existsInList(ed.getDefinition().getBase().getPath(), "Resource.id", "Element.id", "Extension.url")) { - result.addType(TypeDetails.FP_NS, "System.String"); + result.addType(TypeDetails.FP_NS, "string"); } break; // throw new PathEngineException("Illegal reference to primitive value attribute @ "+path); } @@ -5916,12 +5826,7 @@ public class FHIRPathEngine { } private boolean isAbstractType(List list) { - if (list.size() != 1) { - return false; - } else { - StructureDefinition sd = worker.fetchTypeDefinition(list.get(0).getCode()); - return sd != null && sd.getAbstract(); - } + return list.size() != 1 ? true : Utilities.existsInList(list.get(0).getCode(), "Element", "BackboneElement", "Resource", "DomainResource"); } private boolean hasType(ElementDefinition ed, String s) {