getOrGeneratePrefix method

(String, bool) getOrGeneratePrefix(
  1. String namespace, {
  2. Map<String, String> customMappings = const {},
  3. Map<String, String>? invertedCustomMappings,
  4. Map<String, int>? prefixCounters,
})

Returns the Prefix for a given namespace URI, generating a new one if not found.

This method first tries to find an existing prefix for the given namespace URI by checking the provided custom mappings and then the standard mappings. If no existing prefix is found, it attempts to generate a meaningful prefix based on the structure of the namespace URI.

Note that this will not change the immutable RdfNamespaceMappings instance. Instead, it will return a new prefix that can be used for custom mappings.

The returned tuple contains:

  • The prefix: either an existing one or a newly generated one
  • A boolean indicating whether the prefix was generated (true) or found (false)

The namespace is the URI to look up or generate a prefix for, and customMappings are additional mappings to check before the standard ones. Returns the Prefix for a given namespace URI, generating a new one if not found.

invertedCustomMappings is an optional pre-built namespace→prefix inverse of customMappings, enabling O(1) candidate lookup instead of an O(P) linear scan. When provided it must cover the full contents of customMappings (and typically also _mappings), so neither of the O(P) _getKeyByValue fallbacks are needed.

prefixCounters is an optional mutable map from generated base-prefix to the next number to try. When provided, the numbered-prefix search starts where the previous call left off, reducing finding-the-free-slot from O(N) per call to O(1) amortized — avoiding the O(N²) that builds up across N getOrGeneratePrefix calls for the same base prefix.

Implementation

(String prefix, bool generated) getOrGeneratePrefix(
  String namespace, {
  Map<String, String> customMappings = const {},
  Map<String, String>? invertedCustomMappings,
  Map<String, int>? prefixCounters,
}) {
  // O(1) when invertedCustomMappings is provided (it covers both customMappings
  // and _mappings when built from the merged prefixCandidates map).
  // Falls back to O(P) linear scans when no inverted map is available.
  String? candidate;
  if (invertedCustomMappings != null) {
    candidate = invertedCustomMappings[namespace];
  } else {
    candidate = _getKeyByValue(customMappings, namespace) ??
        _getKeyByValue(_mappings, namespace);
  }
  if (candidate != null) {
    return (candidate, false);
  }

  // Generate a meaningful prefix from domain when possible
  String? prefix = _tryGeneratePrefixFromUrl(namespace);

  // Ensure prefix is not already used
  if (prefix != null &&
      !customMappings.containsKey(prefix) &&
      !_mappings.containsKey(prefix)) {
    return (prefix, true);
  }

  // Fall back to numbered prefixes.
  // [prefixCounters] lets the caller cache the last-used number per base prefix
  // so we start each search from where the previous call ended — O(1) amortized
  // instead of the O(N²) that arises when starting from 1 every time.
  final computedPrefix = prefix ?? 'ns';
  int prefixNum = prefixCounters?[computedPrefix] ?? 1;
  do {
    prefix = '$computedPrefix$prefixNum';
    prefixNum++;
  } while (
      customMappings.containsKey(prefix) && !_mappings.containsKey(prefix));
  prefixCounters?[computedPrefix] = prefixNum;
  return (prefix, true);
}