parseString static method

List<XmlDoctype>? parseString(
  1. String string, {
  2. bool parseCharacterEntities = true,
  3. bool parseComments = false,
  4. bool trimWhitespace = true,
  5. bool parseCdataAsText = true,
  6. int start = 0,
  7. int? stop,
})
override

Returns a list of every XML DocType declaration found in string. string must not be null.

If parseCharacterEntities is true, text values will be parsed and replace all encoded character entities with their corresponding character. parseCharacterEntities must not be null.

If parseComments is true, commments will be scrubbed from string before parsing.

If trimWhitespace is true, unnecessary whitespace between nodes will be removed and all remaining whitespace will be replaced with a single space. trimWhitespace must not be null.

If parseCdataAsText is true, all CDATA sections will be returned as XmlText nodes. parseCdataAsText must not be null.

Returns null if no Doctype Declarations are found.

Implementation

static List<XmlDoctype>? parseString(
  String string, {
  bool parseCharacterEntities = true,
  bool parseComments = false,
  bool trimWhitespace = true,
  bool parseCdataAsText = true,
  int start = 0,
  int? stop,
}) {
  if (!parseComments) string = string.removeComments();
  if (trimWhitespace) string = string.trimWhitespace();

  final doctypes = <XmlDoctype>[];

  final tags = _delimiter.allMatches(string);
  if (tags.isEmpty || start >= tags.length) return null;

  for (var tag in tags) {
    if (tag.namedGroup('isMarkup') != '!') continue;
    if (tag.namedGroup('doctype') != 'DOCTYPE') continue;

    final doctype =
        Delimiters.doctype.firstMatch(string.substring(tag.start, tag.end))!;

    final element = doctype.namedGroup('name');
    if (element == null) continue;

    // Capture and parse the external DTD values, if thye exist.
    final identifier = doctype.namedGroup('identifier');

    String? externalDtdName;
    var externalDtd = doctype.namedGroup('externalDtd');
    if (externalDtd != null) {
      final externalDtdParts =
          RegExp('".*?"|\'.?\'').allMatches(externalDtd).toList();
      if (externalDtdParts.length > 1) {
        final name = externalDtdParts.first;
        externalDtdName = externalDtd.substring(name.start + 1, name.end - 1);
        final path = externalDtdParts[1];
        externalDtd = externalDtd.substring(path.start + 1, path.start - 1);
      } else {
        externalDtd = externalDtd.stripDelimiters();
      }
    }

    // Caputre and parse the internal DTD value, if it exists.
    final internalDtdValue = doctype.namedGroup('internalDtd');

    List<XmlNode>? internalDtd;

    if (internalDtdValue != null) {
      internalDtd = XmlNode.parseString(
        internalDtdValue,
        parseCharacterEntities: parseCharacterEntities,
        parseComments: true,
        trimWhitespace: false,
        parseCdataAsText: true,
      );
    }

    doctypes.add(
      XmlDoctype(
        element: element,
        isPublic: identifier == 'PUBLIC',
        isSystem: identifier == 'SYSTEM',
        externalDtdName: externalDtdName,
        externalDtdUri: externalDtd,
        internalDtd: internalDtd,
      ),
    );
  }

  if (doctypes.isEmpty) return null;

  return doctypes;
}