Nokogiri: сортировка массива идентификаторов в соответствии с порядком в HTML-документе - PullRequest
0 голосов
/ 06 мая 2009

У меня есть несортированный массив, содержащий следующие идентификаторы:

@un_array = ['bar', 'para-3', 'para-2', 'para-7']

Существует ли разумный способ использования Nokogiri (или обычного Javascript) для сортировки массива в соответствии с порядком идентификаторов в примере HTML-документа ниже?

require 'rubygems'
require 'nokogiri'

value = Nokogiri::HTML.parse(<<-HTML_END)
  "<html>
    <head>
    </head>
    <body>
        <p id='para-1'>A</p>
        <div id='foo'>
            <p id='para-2'>B</p>
        <p id='para-3'>C</p>
            <div id='bar'>
                <p id='para-4'>D</p>
                <p id='para-5'>E</p>
                <p id='para-6'>F</p>
        </div>
         <p id='para-7'>G</p>
        </div>
        <p id='para-8'>H</p>
    </body>
    </html>"
HTML_END

В этом случае результирующий отсортированный массив должен быть:

['para-2', 'para-3', 'bar', 'para-7']

Ответы [ 3 ]

1 голос
/ 06 мая 2009

Я не знаю, что такое Nokogiri, но если у вас есть HTML-код в виде строки, можно было бы получить заказ с соответствием регулярному выражению, например:

var str = '<html>...</html>'; // the HTML code to check
var ids = ['bar', 'para-3', 'para-2', 'para-7']; // the array with all IDs to check
var reg = new RegExp('(?:id=[\'"])('+ids.join('|')+')(?:[\'"])','g') // the regexp
var result = [], tmp; // array holding the result and a temporary variable
while((tmp = reg.exec(str))!==null)result.push(tmp[1]); // matching the IDs
console.log(result); // ['para-2', 'para-3', 'bar', 'para-7']

используя этот код, вы должны быть осторожны с идентификаторами, содержащими метасимволы регулярных выражений. Сначала им нужно сбежать.

0 голосов
/ 07 мая 2009

Это решение, которое мы с коллегой придумали:

parent = value.css('body').first
indexes = []
parent.children.each do |child|
  indexes << child['id']
end

puts @un_array.sort! { |x,y| indexes.index(x) <=> indexes.index(y) }

Сначала я выбираю все идентификаторы HTML-документа в массив, а затем сортирую @un_array в соответствии с массивом идентификаторов, который я создал ранее.

0 голосов
/ 06 мая 2009

Вот один из способов сделать это в Нокогири - могут быть и другие, более эффективные, так как в конечном итоге вы обходите весь DOM.

require 'set'

#Using a set here to make lookup O(1), because we don't care about the initial order
id_set = ['bar', 'para-3', 'para-2', 'para-7'].to_set
sorted = []

value.root.traverse do |node|
  node_id = node['id']
  sorted << node_id if node_id && id_set.delete?(node_id)
end
# sorted is now ['para-2', 'para-3', 'bar', 'para-7']

РЕДАКТИРОВАТЬ: Вот одна строка, которая дает те же результаты, но я не сделал сравнительный анализ, чтобы увидеть, что быстрее.

ids = ['bar', 'para-3', 'para-2', 'para-7']
value.xpath("//*[@id]").collect {|node| node['id']} & ids
...