function _expandIri(
    $active_ctx, $value, $relative_to=array(), $local_ctx=null, $defined=null) {
    // already expanded
    if($value === null || self::_isKeyword($value)) {
      return $value;
    }

    // define term dependency if not defined
    if($local_ctx !== null && property_exists($local_ctx, $value) &&
      !self::_hasKeyValue($defined, $value, true)) {
      $this->_createTermDefinition($active_ctx, $local_ctx, $value, $defined);
    }

    if(isset($relative_to['vocab']) && $relative_to['vocab']) {
      if(property_exists($active_ctx->mappings, $value)) {
        $mapping = $active_ctx->mappings->{$value};

        // value is explicitly ignored with a null mapping
        if($mapping === null) {
          return null;
        }

        // value is a term
        return $mapping->{'@id'};
      }
    }

    // split value into prefix:suffix
    $colon = strpos($value, ':');
    if($colon !== false) {
      $prefix = substr($value, 0, $colon);
      $suffix = substr($value, $colon + 1);

      // do not expand blank nodes (prefix of '_') or already-absolute
      // IRIs (suffix of '//')
      if($prefix === '_' || strpos($suffix, '//') === 0) {
        return $value;
      }

      // prefix dependency not defined, define it
      if($local_ctx !== null && property_exists($local_ctx, $prefix)) {
        $this->_createTermDefinition(
          $active_ctx, $local_ctx, $prefix, $defined);
      }

      // use mapping if prefix is defined
      if(property_exists($active_ctx->mappings, $prefix)) {
        $mapping = $active_ctx->mappings->{$prefix};
        if($mapping) {
          return $mapping->{'@id'} . $suffix;
        }
      }

      // already absolute IRI
      return $value;
    }

    // prepend vocab
    if(isset($relative_to['vocab']) && $relative_to['vocab'] &&
      property_exists($active_ctx, '@vocab')) {
      return $active_ctx->{'@vocab'} . $value;
    }

    // prepend base
    $rval = $value;
    if(isset($relative_to['base']) && $relative_to['base']) {
      $rval = jsonld_prepend_base($active_ctx->{'@base'}, $rval);
    }

    return $rval;
  }