All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hl7.fhir.validation.instance.utils.FHIRPathExpressionFixer Maven / Gradle / Ivy

The newest version!
package org.hl7.fhir.validation.instance.utils;

import org.hl7.fhir.utilities.VersionUtilities;

public class FHIRPathExpressionFixer {


  public static String fixExpr(String expr, String key, String version) {
    // this is a hack work around for past publication of wrong FHIRPath expressions

    boolean r5 = VersionUtilities.isR5Ver(version);
    boolean r4 = VersionUtilities.isR4Ver(version) || VersionUtilities.isR4BVer(version);

    // see https://chat.fhir.org/#narrow/stream/196008-ig-publishing-requirements/topic/Operation.20Definition.20Parameters.20table
    if (r5 && "opd-3".equals(key)) {
      return "targetProfile.exists() implies (type = 'Reference' or type = 'canonical' or type.memberOf('http://hl7.org/fhir/ValueSet/all-resource-types'))";
    }    
    if (r4 && "opd-3".equals(key)) {
      return "targetProfile.exists() implies (type = 'Reference' or type = 'canonical' or type.memberOf('http://hl7.org/fhir/ValueSet/resource-types'))";
    }
    
    if ("probability is decimal implies (probability as decimal) <= 100".equals(expr)) {
      return "(probability.exists() and (probability is decimal)) implies ((probability as decimal) <= 100)";
    }
    if ("enableWhen.count() > 2 implies enableBehavior.exists()".equals(expr)) {
      return "enableWhen.count() >= 2 implies enableBehavior.exists()";
    }
    if ("txt-2".equals(key)) {
      return "htmlChecks2()";
    }
    if ("dom-6".equals(key)) {
      return "(%rootResource != $this) or text.`div`.exists()";
    }
    if ("generated='generated' implies source.empty()".equals(expr)) {
      return "generation='generated' implies source.empty()";
    }
    if (expr.equals("binding.empty() or type.code.empty() or type.code.contains(\":\") or type.select((code = 'code') or (code = 'Coding') or (code='CodeableConcept') or (code = 'Quantity') or (code = 'string') or (code = 'uri') or (code = 'Duration')).exists()")) {
      return "binding.empty() or type.code.empty() or type.code.contains(':') or type.select((code = 'code') or (code = 'Coding') or (code='CodeableConcept') or (code = 'Quantity') or (code = 'string') or (code = 'uri') or (code = 'Duration')).exists()";
    }
    // fixes to string functions in FHIRPath
    // ref-1
    if (expr.equals("reference.startsWith('#').not() or (reference.substring(1).trace('url') in %rootResource.contained.id.trace('ids')) or (reference='#' and %rootResource!=%resource)")) { // R5
      return "reference.exists() implies ("+expr+")";
    }
    if (expr.equals("reference.startsWith('#').not() or (reference.substring(1).trace('url') in %rootResource.contained.id.trace('ids'))")) { // R4/R4B
      return "reference.exists() implies (reference = '#' or ("+expr+"))";
    }
    if (expr.equals("reference.startsWith('#').not() or (reference.substring(1).trace('url') in %resource.contained.id.trace('ids'))")) { // STU3
      return "reference.exists() implies (reference = '#' or (reference.startsWith('#').not() or (reference.substring(1).trace('url') in %rootResource.contained.id.trace('ids'))))";
    }
    // bld-8
    if (expr.equals("fullUrl.contains('/_history/').not()")) { // R4
      return "fullUrl.exists() implies fullUrl.contains('/_history/').not()";      
    }
    if (expr.equals("name.matches('[A-Z]([A-Za-z0-9_]){0,254}')")) {
      return "name.exists() implies name.matches('^[A-Z]([A-Za-z0-9_]){0,254}$')";
    }
    // canonical
    if (expr.equals("name.matches('[A-Z]([A-Za-z0-9_]){0,254}')")) {
      return ("name.exists() implies name.matches('[A-Z]([A-Za-z0-9_]){0,254}')");
    }
    // con-3 in R4
    if (expr.equals("clinicalStatus.exists() or verificationStatus.coding.where(system='http://terminology.hl7.org/CodeSystem/condition-ver-status' and code = 'entered-in-error').exists() or category.select($this='problem-list-item').empty()")) {
      return "(verificationStatus.coding.where(system='http://terminology.hl7.org/CodeSystem/condition-ver-status' and code = 'entered-in-error').exists() and category.coding.exists(system='http://terminology.hl7.org/CodeSystem/condition-category' and code ='problem-list-item').empty()) implies (clinicalStatus.exists())";
    }
    
    // R5 ballot
    if (expr.equals("url.matches('([^|#])*')")) {
      return ("$this.matches('([^|#])*')");
    }
    if (expr.equals("((kind in 'resource' | 'complex-type') and (specialization = 'derivation')) implies differential.element.where((min != 0 and min != 1) or (max != '1' and max != '*')).empty()")) {
      return "((kind in 'resource' | 'complex-type') and (derivation = 'specialization')) implies differential.element.where((min.exists() and min != 0 and min != 1) or (max.exists() and max != '1' and max != '*')).empty()";
    }  
    
    // clarification in FHIRPath spec
    if (!r5 && "eld-19".equals(key)) {
      return "path.matches('^[^\\\\s\\\\.,:;\\\\\\'\"\\\\/|?!@#$%&*()\\\\[\\\\]{}]{1,64}(\\\\.[^\\\\s\\\\.,:;\\\\\\'\"\\\\/|?!@#$%&*()\\\\[\\\\]{}]{1,64}(\\\\[x\\\\])?(\\\\:[^\\\\s\\\\.]+)?)*$')";
    }
    if (!r5 && "eld-20".equals(key)) {
      return "path.matches('^[A-Za-z][A-Za-z0-9]*(\\\\.[a-z][A-Za-z0-9]*(\\\\[x])?)*$')";
    }
  
    // handled in 4.0.1
    if ("(component.empty() and hasMember.empty()) implies (dataAbsentReason or value)".equals(expr)) {
      return "(component.empty() and hasMember.empty()) implies (dataAbsentReason.exists() or value.exists())";
    }
    if ("isModifier implies isModifierReason.exists()".equals(expr)) {
      return "(isModifier.exists() and isModifier) implies isModifierReason.exists()";
    }
    if ("(%resource.kind = 'logical' or element.first().path.startsWith(%resource.type)) and (element.tail().not() or  element.tail().all(path.startsWith(%resource.differential.element.first().path.replaceMatches('\\\\..*','')&'.')))".equals(expr)) {
      return "(%resource.kind = 'logical' or element.first().path.startsWith(%resource.type)) and (element.tail().empty() or  element.tail().all(path.startsWith(%resource.differential.element.first().path.replaceMatches('\\\\..*','')&'.')))";
    }
    if ("differential.element.all(id) and differential.element.id.trace('ids').isDistinct()".equals(expr)) {
      return "differential.element.all(id.exists()) and differential.element.id.trace('ids').isDistinct()";
    }
    if ("snapshot.element.all(id) and snapshot.element.id.trace('ids').isDistinct()".equals(expr)) {
      return "snapshot.element.all(id.exists()) and snapshot.element.id.trace('ids').isDistinct()";
    }

    // R3
    if ("(code or value.empty()) and (system.empty() or system = 'urn:iso:std:iso:4217')".equals(expr)) {
      return "(code.exists() or value.empty()) and (system.empty() or system = 'urn:iso:std:iso:4217')";
    }
    if ("value.empty() or code!=component.code".equals(expr)) {
      return "value.empty() or (code in component.code).not()";
    }
    if ("(code or value.empty()) and (system.empty() or system = %ucum) and (value.empty() or value > 0)".equals(expr)) {
      return "(code.exists() or value.empty()) and (system.empty() or system = %ucum) and (value.empty() or value > 0)";
    }
    if ("element.all(definition and min and max)".equals(expr)) {
      return "element.all(definition.exists() and min.exists() and max.exists())";
    }
    if ("telecom or endpoint".equals(expr)) {
      return "telecom.exists() or endpoint.exists()";
    }
    if ("(code or value.empty()) and (system.empty() or system = %ucum) and (value.empty() or value > 0)".equals(expr)) {
      return "(code.exists() or value.empty()) and (system.empty() or system = %ucum) and (value.empty() or value > 0)";
    }
    if ("searchType implies type = 'string'".equals(expr)) {
      return "searchType.exists() implies type = 'string'";
    }
    if ("abatement.empty() or (abatement as boolean).not()  or clinicalStatus='resolved' or clinicalStatus='remission' or clinicalStatus='inactive'".equals(expr)) {
      return "abatement.empty() or (abatement is boolean).not() or (abatement as boolean).not() or (clinicalStatus = 'resolved') or (clinicalStatus = 'remission') or (clinicalStatus = 'inactive')";
    }
    if ("(component.empty() and related.empty()) implies (dataAbsentReason or value)".equals(expr)) {
      return "(component.empty() and related.empty()) implies (dataAbsentReason.exists() or value.exists())";
    }
    if ("reference.startsWith('#').not() or (reference.substring(1).trace('url') in %rootResource.contained.id.trace('ids'))".equals(expr)) {
      return "(reference = '#') or reference.startsWith('#').not() or (reference.substring(1).trace('url') in %rootResource.contained.id.trace('ids'))";
    }
    if ("reference.startsWith('#').not() or (reference.substring(1).trace('url') in %resource.contained.id.trace('ids'))".equals(expr)) {
      return "(reference = '#') or reference.startsWith('#').not() or (reference.substring(1).trace('url') in %rootResource.contained.id.trace('ids'))";
    }
    if ("probability is decimal implies probability.as(decimal) <= 100".equals(expr)) {
      if (key.equals("ras-2")) {
        return "probability.empty() or (probability is decimal implies probability.as(decimal) <= 100)";
      }
    }
    if ("".equals(expr)) {
      return "";
    }
    return expr;
  }

  public static String fixRegex(String regex) {
    if (regex == null) {
      return null;
    }
    if (regex.equals("-?(0|[1-9][0-9]{0,17})(\\.[0-9]{1,17})?([eE][+-]?[0-9]{1,9}})?")) {
      return "-?(0|[1-9][0-9]{0,17})(\\.[0-9]{1,17})?([eE](0|[+\\-]?[1-9][0-9]{0,9}))?";
    }
    if (regex.equals("[ \\r\\n\\t\\S]+")) {
      return "^[\\s\\S]+$";
    }
    return regex;
  }
  
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy