Как получить только TEXT_NODE с кучики

У меня есть этот пример HTML, который я хочу проанализировать с помощью кучики:

<a href = "https://example.com"><em>@</em>Bananowy</a>

Хочу только Bananowy без @.

Аналогичный вопрос для JavaScript: Как получить текстовый узел элемента?

Что такое кучики? Не могли бы вы немного расширить свой вопрос? Например. какой-то пример кода?

hellow 27.05.2019 19:27
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
1
1
359
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Во-первых, давайте начнем с того, как парсер будет анализировать:

    <a href = "https://example.com"><em>@</em>Bananowy</a>

В дерево. См. изображение ниже:

Теперь, если вы попытаетесь сделать очевидную вещь и вызвать anchor.text_contents(), вы получите все текстовое содержимое всех текстовых узлов, потомков тега привязки (<a>). Вот как ведут себя text_contents в соответствии с определением CSS.

Тем не менее, вы хотите просто получить "Bananowy", у вас есть несколько способов сделать это:

extern crate kuchiki;

use kuchiki::traits::*;

fn main() {
    let html = r"<a href='https://example.com'><em>@</em>Bananowy</a>";

    let document = kuchiki::parse_html().one(html);

    let selector = "a";
    let anchor = document.select_first(selector).unwrap();
    // Quick and dirty hack
    let last_child = anchor.as_node().last_child().unwrap();
    println!("{:?}", last_child.into_text_ref().unwrap());

    // Iterating solution
    for children in anchor.as_node().children() {
        if let Some(a) = children.as_text() {
            println!("{:?}", a);
        }
    }

    // Iterating solution - Using `text_nodes()` iterators
    anchor.as_node().children().text_nodes().for_each(|e| {
        println!("{:?}", e);
    });

    // text1 and text2 are examples how to get `String`
    let text1 = match anchor.as_node().children().text_nodes().last() {
        Some(x) => x.as_node().text_contents(),
        None => String::from(""),
    };

    let text2 = match anchor.as_node().children().text_nodes().last() {
        Some(x) => x.borrow().clone(),
        None => String::from(""),
    };
}

Первый способ — хрупкий, хакерский. Все, что вам нужно понять, это то, что "Bananowy" — это последний ребенок вашего тега привязки, и получить его соответствующим образом anchor.as_node().last_child().unwrap().into_text_ref().unwrap().

Второе решение состоит в том, чтобы перебрать дочерние элементы тега привязки (например, [Tag(em), TextNode("Bananowy")]) и выбрать только текстовые узлы, используя (метод as_text()). Мы делаем это с помощью метода as_text(), который возвращает None для всех Nodes, которые не являются TextNode. Это намного менее хрупко, чем первое решение, которое не будет работать, если, например. у тебя было <a><em>@</em>Banan<i>!</i>owy</a>.

Обновлено:

ПРЕДПОЧТИТЕЛЬНОЕ решение

Немного осмотревшись, я нашел гораздо лучшее решение вашей проблемы. Он называется Итератор TextNodes.

Имея это в виду, просто напишите anchor.as_node().children().text_nodes().<<ITERATOR CODE GOES HERE>>;, а затем сопоставьте или манипулируйте записями по своему усмотрению.

Почему это решение лучше? Он более лаконичен, в нем используется старый добрый Iterator, поэтому он очень похож на ответ в JS, который вы дали выше.

Я нашел этот комментарий, как перемещаться по документации: reddit.com/r/rust/comments/af4ns6/how_to_work_with_refcell

rofrol 06.01.2020 08:01

Другие вопросы по теме