2016-08-05 2 views
3

Я хочу получить все узлы из документа HTML с помощью Nokogiri. Пример HTML входной строки:Nokogiri получить все узлы HTML

<html> 
    <body> 
    <h1>Test</h1> 
    <p>test <strong> Jojo </strong></p> 
    </body> 
</html> 

Ожидаемый результат:

['<html>','<body>','<h1>','</h1>','<p>','<strong>','</strong>','</p>','</body>','</html>'] 

закрывающие теги и правильный порядок важен!

Я попробовал этот код уже:

require 'nokogiri' 
string_page = "<html><body><h1>Header1</h1></body></html>" 
doc = Nokogiri::HTML(string_page) 
doc.search('*').map(&:name) 
# => ["html", "body", "h1"] 

Но он не возвращает закрывающий теги.

ответ

4

Вы можете разделить OuterXml на InnerXml на все открывающиеся элементы, которые не закрываются сами собой, хранить соответствующие закрывающие элементы, если они есть, и анализировать документ с помощью считывателя Nokogiri для создания списка в соответствии с порядком в документе ,

Для этого требуется, чтобы ваш документ являлся допустимым фрагментом XML, поскольку он использует синтаксический анализатор XML, а не HTML.

require 'nokogiri' 
[ "<html><body><h1>Header1</h1></body></html>", 
"<html><body><div><h1>Title</h1><hr /></div><div><p>Lorem Ipsum<br />sit <span class=\"style\">d</span>olor</p></div></body></html>", <<END 
<html> 
    <body> 
     <h1>Test</h1> 
     <p>test <strong> Jojo </strong></p> 
    </body> 
</html> 
END 
].each { |string_page| 
    elem_all = Array.new 
    elem_ends = Hash.new 
    reader = Nokogiri::XML::Reader(string_page) 
    reader.each { |node| 
    if node.node_type.eql?(1) 
     if node.self_closing? 
     elem_all << node.outer_xml 
     else 
     elem_tags = node.outer_xml.split(node.inner_xml) 
     elem_all << elem_tags.first 
     elem_ends[node.local_name] = elem_tags[1] unless elem_tags.one? 
     end 
    end 
    elem_all << elem_ends[node.local_name] if node.node_type.eql?(15) and elem_ends.has_key?(node.local_name) 
    } 

    puts string_page 
    puts elem_all.to_s 
    puts 
} 

Выходы:

<html><body><h1>Header1</h1></body></html> 
["<html>", "<body>", "<h1>", "</h1>", "</body>", "</html>"] 

<html><body><div><h1>Title</h1><hr /></div><div><p>Lorem Ipsum<br />sit <span class="style">d</span>olor</p></div></body></html> 
["<html>", "<body>", "<div>", "<h1>", "</h1>", "<hr/>", "</div>", "<div>", "<p>", "<br/>", "<span class=\"style\">", "</span>", "</p>", "</div>", "</body>", "</html>"] 

<html> 
    <body> 
     <h1>Test</h1> 
     <p>test <strong> Jojo </strong></p> 
    </body> 
</html> 
["<html>", "<body>", "<h1>", "</h1>", "<p>", "<strong>", "</strong>", "</p>", "</body>", "</html>"] 
0

Вы можете установить закрывающий тег ваш собственный, как показано ниже:

doc = Nokogiri::HTML(<<EOT) 
<html> 
    <body> 
    <h1>Test</h1> 
    <p>test <strong> Jojo </strong></p> 
    </body> 
</html> 
EOT 

doc.search('*').map{|m| [m.name, "/#{m.name}"]} 

выход: => [[ "HTML", "/ html"], ["body", "/ body"], ["h1", "/ h1"], ["p", "/ p"], ["strong", "/ strong"]]

+0

"правильный порядок важен! " –

Смежные вопросы