Pregunta

Tengo una matriz sin clasificar que contiene los siguientes ID:

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

¿Existe una manera inteligente de usar Nokogiri (o Javascript simple) para ordenar la matriz de acuerdo con el orden de las ID en el documento HTML de ejemplo a continuación?

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

En este caso, la matriz ordenada resultante debería ser:

['para-2', 'para-3', 'bar', 'para-7']
¿Fue útil?

Solución 3

Esta es la solución que un compañero de trabajo y yo se nos ocurrió:

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) }

Primero busco todas las ID del documento HTML en una matriz, luego clasifico @un_array de acuerdo con la matriz de IDs que creé antes.

Otros consejos

No sé qué es Nokogiri, pero si tiene el código HTML como una Cadena, entonces sería posible obtener el pedido con coincidencia de expresiones regulares, por ejemplo:

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']

con este código, debe tener cuidado con los ID que contienen metacaracteres regexp. Deben escapar primero.

Aquí hay una forma de hacerlo en Nokogiri: puede haber otros que sean más eficientes, ya que esto termina caminando por todo el 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']

EDITAR: Aquí hay una línea que obtiene los mismos resultados, pero no he hecho una evaluación comparativa para ver cuál es más rápido.

ids = ['bar', 'para-3', 'para-2', 'para-7']
value.xpath("//*[@id]").collect {|node| node['id']} & ids
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top