fefit / visdom

A library use jQuery like API for html parsing & node selecting & node mutation, suitable for web scraping and html confusion.
MIT License
110 stars 6 forks source link

Navigating sideway with `find` method #13

Closed Random-G closed 2 years ago

Random-G commented 2 years ago

Hello, is there a way to navigate sideway with find method?

use std::ops::Index;
use visdom::{Vis, html};
use visdom::types::{BoxDynError, Elements};

fn main() -> Result<(), BoxDynError> {
    let html = r##"
        <div class='main'>
            <p>abc</p>
            <p>def</p>
        </div>
        <div class='main'>
            <p>ghi</p>
            <p>jkl</p>
        </div>
    "##;
    let doc = Vis::load(html)?;
    let div = doc.find("div.main");
    let div_length = div.length();
    div.each(|index, ele| {
        if index < div_length {
        let p = ele.find("p");
        return true;
        } false
    });
    Ok(())
}

# error[E0599]: the method `find` exists for mutable reference `&mut Box<dyn visdom::mesdoc::interface::element::IElementTrait>`, but its trait bounds were not satisfied

for div.each, ele.find("p") is not working. Also, why does .each need index?

fefit commented 2 years ago

@Random-G the each method also follow the each API in jQuery, it will iterate over each element in the Elements by mutable reference, and break the loop if the traversal function return false. the traversal function's second parameter ele is a dyn IElementTrait, you can use the method Vis::dom(ele) to translate it into an Elements just like jQuery use $(ele) to get a jQuery object from the original DOM element, then you can use the methods such as 'find()' over the Elements.

use std::ops::Index;
use visdom::{Vis, html};
use visdom::types::{BoxDynError, Elements};

fn main() -> Result<(), BoxDynError> {
    let html = r##"
        <div class='main'>
            <p>abc</p>
            <p>def</p>
        </div>
        <div class='main'>
            <p>ghi</p>
            <p>jkl</p>
        </div>
    "##;
    let doc = Vis::load(html)?;
    // here the `div` should be mutable
    let mut div = doc.find("div.main");
    // use '_' ignore the first parameter if you don't care about the index 
    div.each(|_, ele| {
        // use Vis::dom(ele) wrap the element into an `Elements`
        // and can also use the APIs defined in `IElementTrait`
        // e.g. `ele.children()` to get an `Elements` from the `ele`'s childs 
        let p = Vis::dom(ele).find("p"); //  let p = ele.children().filter("p");
        true
    });
    Ok(())
}
Random-G commented 2 years ago

@fefit Thank you very much.