protected function _selectTerm(
    $active_ctx, $iri, $value, $containers,
    $type_or_language, $type_or_language_value) {
    if($type_or_language_value === null) {
      $type_or_language_value = '@null';
    }

    // options for the value of @type or @language
    $prefs = array();

    // determine prefs for @id based on whether or not value compacts to a term
    if(($type_or_language_value === '@id' ||
      $type_or_language_value === '@reverse') &&
      self::_isSubjectReference($value)) {
      // prefer @reverse first
      if($type_or_language_value === '@reverse') {
        $prefs[] = '@reverse';
      }
      // try to compact value to a term
      $term = $this->_compactIri(
        $active_ctx, $value->{'@id'}, null, array('vocab' => true));
      if(property_exists($active_ctx->mappings, $term) &&
        $active_ctx->mappings->{$term} &&
        $active_ctx->mappings->{$term}->{'@id'} === $value->{'@id'}) {
        // prefer @vocab
        array_push($prefs, '@vocab', '@id');
      } else {
        // prefer @id
        array_push($prefs, '@id', '@vocab');
      }
    } else {
      $prefs[] = $type_or_language_value;
    }
    $prefs[] = '@none';

    $container_map = $active_ctx->inverse->{$iri};
    foreach($containers as $container) {
      // if container not available in the map, continue
      if(!property_exists($container_map, $container)) {
        continue;
      }

      $type_or_language_value_map =
        $container_map->{$container}->{$type_or_language};
      foreach($prefs as $pref) {
        // if type/language option not available in the map, continue
        if(!property_exists($type_or_language_value_map, $pref)) {
          continue;
        }

        // select term
        return $type_or_language_value_map->{$pref};
      }
    }
    return null;
  }