parseString static method

List<XmlElement>? parseString(
  1. String string, {
  2. bool parseCharacterEntities = true,
  3. bool parseComments = false,
  4. bool trimWhitespace = true,
  5. bool parseCdataAsText = true,
  6. bool global = false,
  7. List<String>? returnElementsNamed,
  8. List<String>? returnElementsWithId,
  9. List<String>? returnElementsWithAttributesNamed,
  10. List<XmlAttribute>? returnElementsWithAttributes,
  11. bool matchAllAttributes = true,
  12. int start = 0,
  13. int? stop,
})
override

Returns a list of every element 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.

If global is true, all elements will be returned regardless of whether they're nested within other elements. If false, only the root level elements will be returned.

If returnElementsNamed is not null, only elements with a name contained in returnElementsNamed will be returned.

If returnElementsWithId is not null, only elements with an ID contained in returnElementsWithId will be returned.

If returnElementsWithAttributesNamed is not null, only elements posessing an attribute with a name contained in returnElementsWithAttributesNamed will be returned. If matchAllAttributes is true, an element must possess every attribute contained in returnElementsWithAttributesNamed to be returned, if false, the element only needs to posess a single attribute contained in returnElementsWithAttributesNamed.

If returnElementsWithAttributes is not null, only elements possessing attributes with an identical name and value as those contained in returnElemtnsWithAttribute will be returned. If matchAllAttributes is true, an element must possess every attribute contained in returnElementsWithAttributes, if false, the element only needs to possess a single attribute contained in returnElementsWithAttributes.

start and stop refer to the indexes of the identified elements. Only matches found between start and stop will be returned. start must not be null and must be >= 0. stop may be null, but must be >= start if provided.

Returns null if no elements were found.

Implementation

static List<XmlElement>? parseString(
  String string, {
  bool parseCharacterEntities = true,
  bool parseComments = false,
  bool trimWhitespace = true,
  bool parseCdataAsText = true,
  bool global = false,
  List<String>? returnElementsNamed,
  List<String>? returnElementsWithId,
  List<String>? returnElementsWithAttributesNamed,
  List<XmlAttribute>? returnElementsWithAttributes,
  bool matchAllAttributes = true,
  int start = 0,
  int? stop,
}) {
  assert(start >= 0);
  assert(stop == null || stop >= start);

  if (!parseComments) string = string.removeComments();
  if (trimWhitespace) string = string.trimWhitespace();

  final elements = <XmlElement>[];
  var elementCount = 0;

  while (string.contains(Delimiters.elementTag)) {
    var tag = Delimiters.elementTag.firstMatch(string);

    final name = tag!.namedGroup('tagName');

    if (!name!.startsWith('/')) {
      if (returnElementsNamed == null || returnElementsNamed.contains(name)) {
        List<XmlNode>? children;

        final attributeData = tag.namedGroup('attributes')!.trim();

        if (tag.namedGroup('isEmpty') != '/') {
          tag = Delimiters.element(name, global: global).firstMatch(string);

          children = XmlNode.parseString(
            tag!.namedGroup('children')!,
            parseCharacterEntities: parseCharacterEntities,
            parseComments: true,
            trimWhitespace: false,
            parseCdataAsText: parseCdataAsText,
          );
        }

        List<XmlAttribute>? attributes;
        var attriubtesAreValid = true;

        if (attributeData.isNotEmpty) {
          attributes = XmlAttribute.parseString(
            attributeData,
            parseCharacterEntities: parseCharacterEntities,
            trimWhitespace: false,
          )!;

          if (returnElementsWithAttributesNamed != null ||
              returnElementsWithAttributes != null) {
            var attributeNamesToValidate =
                (returnElementsWithAttributesNamed != null)
                    ? (matchAllAttributes)
                        ? returnElementsWithAttributesNamed.length
                        : 1
                    : 0;

            var attributesToValidate = (returnElementsWithAttributes != null)
                ? (matchAllAttributes)
                    ? returnElementsWithAttributes.length
                    : 1
                : 0;

            for (var attribute in attributes) {
              if (attributeNamesToValidate > 0 &&
                  returnElementsWithAttributesNamed!
                      .contains(attribute.name)) {
                attributeNamesToValidate--;
              }

              if (attributesToValidate > 0 &&
                  returnElementsWithAttributes!.contains(attribute)) {
                attributesToValidate--;
              }

              if (attributeNamesToValidate <= 0 &&
                  attributesToValidate <= 0) {
                break;
              }
            }

            if (attributeNamesToValidate > 0 || attributesToValidate > 0) {
              attriubtesAreValid = false;
            }
          }
        } else if (returnElementsWithAttributes != null &&
            returnElementsWithAttributes.isNotEmpty) {
          attriubtesAreValid = false;
        }

        if (attriubtesAreValid) {
          final id = attributes
              ?.cast<XmlAttribute?>()
              .firstWhere((attribute) => attribute!.name == 'id',
                  orElse: () => null)
              ?.value;

          if (elementCount >= start &&
              (returnElementsWithId == null ||
                  returnElementsWithId.contains(id))) {
            elements.add(
              XmlElement(
                name: name,
                attributes: attributes,
                children: children,
              ),
            );

            if (stop != null && elementCount > stop) break;
          }

          elementCount++;
        }
      }
    }

    string = string.substring(tag.end);
  }

  if (elements.isEmpty) return null;

  return elements;
}