У меня есть этот пример HTML, который я хочу проанализировать с помощью кучики:
<a href = "https://example.com"><em>@</em>Bananowy</a>
Хочу только Bananowy
без @
.
Аналогичный вопрос для JavaScript: Как получить текстовый узел элемента?
Во-первых, давайте начнем с того, как парсер будет анализировать:
<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
Что такое кучики? Не могли бы вы немного расширить свой вопрос? Например. какой-то пример кода?