utkarshkukreti / select.rs

A Rust library to extract useful data from HTML documents, suitable for web scraping.
MIT License
971 stars 69 forks source link

Add macros for predicate #29

Open hawnzug opened 7 years ago

hawnzug commented 7 years ago

Maybe we could consider adding some macros to make the grammar more appealing. I've written some simple examples as follows.

use select::predicate::{And, Not, Attr, Name};

macro_rules! attrs {
    ([!$($kv:tt)+]) => (Not(attrs!([$($kv)+])));
    (["class", $v:expr]) => (Class($v));
    ([$k:expr, $v:expr]) => (Attr($k, $v));
    ([$k:expr]) => (Attr($k, ()));
    ($head:tt$($rest:tt)+) => (And(attrs!($head), attrs!($($rest)+)));
}

macro_rules! tag_attrs {
    ($tag:ident) => (Name(stringify!($tag)));
    (ANY$($attrs:tt)+) => (attrs!($($attrs)+));
    ($tag:ident$($attrs:tt)+) => (And(tag_attrs!($tag), attrs!($($attrs)+)));
}

macro_rules! find {
    ($doc:ident$(.$tag:ident$([$($kv:tt)+])*)+) => ($doc$(.find(tag_attrs!($tag$([$($kv)+])*)))+)
}

Using find! macro, we can write selecting codes like this.

find!(document.body.div["id", "info"].a["href"][!"target"]["rel", "nofollow"]);
find!(document.ANY["class", "card"].div.li.span.a);

It may serve as boilerplate for selecting elements with simple logic.

utkarshkukreti commented 7 years ago

@hawnzug Sorry for the late reply and thanks for the idea! Using . for descendents would probably be confusing for beginners since . is used for CSS classes in CSS selectors, but that can be changed easily. What is your opinion on #26?