2010-02-17 2 views
16

J'utilise nokogiri pour sélectionner l'attribut « Mots clés » comme celui-ci:Comment créer un sélecteur Xpath insensible à la casse nokogiri?

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

L'une des pages avec lesquelles je travaille a l'étiquette de mots-clés avec un « K » qui m'a motivé à faire la question insensible à la casse.

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

Alors, ma question est: Quelle est la meilleure façon de faire un cas de sélection nokogiri insensible?

EDIT La suggestion de Tomalak ci-dessous fonctionne très bien pour ce problème spécifique. J'aimerais aussi utiliser cet exemple pour mieux comprendre le nokogiri et avoir quelques problèmes que je me pose et que je n'ai pas réussi à trouver. Par exemple, les 'pseudo-classes' regex Nokogiri Docs sont-elles appropriées pour un problème comme celui-ci?

Je suis également curieux de connaître la méthode correspondante() dans nokogiri. Je n'ai pas été en mesure de trouver des éclaircissements sur la méthode. Cela a-t-il quelque chose à voir avec le concept 'matches' dans XPath 2.0 (et pourrait donc être utilisé pour résoudre ce problème)?

Merci beaucoup.

+1

+1 - bonne question. Bienvenue à SO :) –

Répondre

9

raccourcies pour des raisons de lisibilité:

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

Il n'y a pas de fonction « minuscules » dans XPath 1.0, vous devez utiliser translate() pour ce genre de chose. Ajoutez des lettres accentuées si nécessaire.

+0

Merci beaucoup Tomalak. Cette solution fonctionne bien pour moi. – Rick

+0

FYI, xpath 1.0 de VTD-XML implémente réellement upperCase et lowerCase comme une sorte d'étape intermédiaire à 2.0 –

19

Nokogiri permet des fonctions XPath personnalisées. Les documents nokogiri que vous liez pour afficher une définition de classe en ligne lorsque vous ne l'utilisez qu'une seule fois. Si vous avez beaucoup de fonctions personnalisées ou si vous utilisez beaucoup le caractère insensible à la casse, vous pouvez le définir dans une classe. Ensuite, appelez-le comme n'importe quelle autre fonction XPath, en passant une instance de votre classe comme second argument.

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

Dans votre méthode Ruby, node_set sera lié à un Nokogiri::XML::NodeSet. Dans le cas où vous passez une valeur d'attribut comme @name, ce sera un NodeSet avec un seul Nokogiri::XML::Attr. Donc, en appelant to_s sur elle vous donne sa valeur. (Vous pouvez également utiliser node.value.)

Contrairement à l'utilisation de XPath translate où vous devez spécifier chaque caractère, cela fonctionne sur tous les caractères et codages de caractères sur lesquels Ruby travaille. En outre, si vous êtes intéressé par d'autres choses que la correspondance insensible à la casse que XPath 1.0 ne prend pas en charge, c'est simplement Ruby à ce stade. Donc c'est un bon point de départ.

+0

Solution très élégante! – Severin