html5lib dart. Query by class-selector throw exception

494 views Asked by At

I'm trying to get element with class nav by selector .nav. As result lib throw exception:

only type selectors are implemented.

Code example:

import 'package:html5lib/parser.dart';

void main() {
  String html = '''
    <html>
    <head><title>Some title</title></head>
    <body>
    <div class="nav">Some nav content</div>
    </body>
    </html>
  ''';
  var doc = parse(html);

  print(doc.query('.nav'));
}

Console output:

Breaking on exception: UnimplementedError: only type selectors are implemented
Unhandled exception:
UnimplementedError: only type selectors are implemented
#0      Node._typeSelector (package:html5lib/dom.dart:269:7)
#1      Node.query (package:html5lib/dom.dart:249:62)
#2      main (/home/hello/dart/test/bin/simple_exp.dart:14:18)
#3      _startIsolate.isolateStartHandler (dart:isolate-patch/isolate_patch.dart:190)
#4      _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:93)

What is wrong?

2

There are 2 answers

2
Greg Lowe On BEST ANSWER

Full CSS selector matching has not been implemented yet.

Depending on your use case, you may be able to match on the type (tag name), and then filter the results using the Element's class attribute.

Here is an example of how to do that:

  var el = doc.queryAll('div').where((el) => 
      el.attributes.keys.contains('class') &&
        el.attributes['class'].split(' ').contains('nav')).first;

Hopefully someone will implement the query selector matching support soon - because this work around is very inefficient for documents with a lot of div tags.

Another solution is to do your own traversal - something like this:

queryClass(Node element, String className) {
  for (var node in element.nodes) {
    if (node is! Element) continue;
    if (node.attributes.keys.contains('class') 
        && node.attributes['class'].split(' ').contains(className)) {
      return node;
    }
    var result = queryClass(node, className);
    if (result != null) return result;
  }
  return null;
}

main() {
   var doc = parse(...);
   var el = queryClass(doc, 'nav');
   print(el);
}
0
Mircea On

Looking through the code of the html5lib parser, you can see that the query function is working only for type selector (such as: div, head, etc). There is a comment in the source code stating that and, also, the exception thrown is quite explicit.

Probably a solution for your case would be to use queryAll method to return all divs and iterate through them until you find the one (or the ones) that have the respective class. I know it's by far not the ideal solution, but it might work.

Hope it helps!