2010-02-17 8 views
16

estoy usando nokogiri para seleccionar el atributo 'palabras clave' como esto:¿Cómo puedo crear un selector Xpath insensible a las mayúsculas y minúsculas nokogiri?

puts page.parser.xpath("//meta[@name='keywords']").to_html 

Una de las páginas que estoy trabajando tiene la etiqueta de palabras clave con una "K" de capital que ha motivado que haga la consulta insensible a mayúsculas y minúsculas

<meta name="keywords"> AND <meta name="Keywords"> 

lo tanto, mi pregunta es: ¿Cuál es la mejor manera de hacer un caso de selección nokogiri insensible?

EDIT La sugerencia de Tomalak a continuación funciona muy bien para este problema específico. También me gustaría utilizar este ejemplo para ayudar a entender mejor a nokogiri y tener un par de cuestiones que me preguntan y que no he tenido éxito en la búsqueda. Por ejemplo, ¿son adecuadas las 'pseudo clases' de expresiones regulares Nokogiri Docs para un problema como este?

También tengo curiosidad sobre el método de los partidos?() En nokogiri. No he podido encontrar ninguna aclaración sobre el método. ¿Tiene algo que ver con el concepto de 'coincidencias' en XPath 2.0 (y, por lo tanto, podría usarse para resolver este problema)?

Muchas gracias.

+1

+1 - buena pregunta. Bienvenido a SO :) –

Respuesta

9

ajustado para la legibilidad:

puts page.parser.xpath(" 
    //meta[ 
    translate(
     @name, 
     'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
     'abcdefghijklmnopqrstuvwxyz' 
    ) = 'keywords' 
    ] 
").to_html 

no hay ninguna función "a minúsculas" en XPath 1.0, así que hay que utilizar translate() para este tipo de cosas. Agregue letras acentuadas según sea necesario.

+0

Muchas gracias Tomalak. Esta solución está funcionando bien para mí. – Rick

+0

FYI, VTD-XML's xpath 1.0 realmente implementa upperCase y lowerCase como una especie de paso intermedio a 2.0 –

19

Nokogiri permite funciones XPath personalizadas. Los documentos de nokogiri que vinculan muestran una definición de clase en línea para cuando solo la usa una vez. Si tiene muchas funciones personalizadas o si usa mucho las coincidencias insensibles a mayúsculas y minúsculas, puede definirlas en una clase.

class XpathFunctions 

    def case_insensitive_equals(node_set, str_to_match) 
    node_set.find_all {|node| node.to_s.downcase == str_to_match.to_s.downcase } 
    end 

end 

Luego llámalo como cualquier otra función XPath, pasando una instancia de tu clase como el segundo argumento.

page.parser.xpath("//meta[case_insensitive_equals(@name,'keywords')]", 
        XpathFunctions.new).to_html 

En el método de Ruby, node_set estará atado a un Nokogiri::XML::NodeSet. En el caso en el que esté pasando un valor de atributo como @name, será un NodeSet con un solo Nokogiri::XML::Attr. Entonces, llamar al to_s le da su valor. (Alternativamente, puede usar node.value.)

A diferencia del uso de XPath translate donde debe especificar cada caracter, esto funciona en todos los caracteres y codificaciones de caracteres en los que Ruby trabaja.

Además, si está interesado en hacer otras cosas además de la coincidencia de mayúsculas y minúsculas que XPath 1.0 no admite, es solo Ruby en este momento. Este es un buen punto de partida.

+0

¡Solución muy elegante! – Severin

Cuestiones relacionadas