2010-02-17 1 views
16

Sto usando nokogiri per selezionare l'attributo 'parole chiave' in questo modo:Come posso creare un selettore Xpath senza distinzione tra maiuscole e minuscole?

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

Una delle pagine che sto lavorando con ha l'etichetta di parole chiave con la "K", che ha motivato me per fare il query case insensitive.

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

Quindi, la mia domanda è: Qual è il modo migliore per fare un caso di selezione nokogiri insensibile?

MODIFICA Il seguente suggerimento Tomalak funziona alla grande per questo problema specifico. Mi piacerebbe anche usare questo esempio per aiutare a capire meglio nokogiri e avere un paio di problemi di cui mi sto interrogando e che non ho cercato con successo. Ad esempio, le regex 'pseudo classi' Nokogiri Docs sono appropriate per un problema come questo?

Sono anche curioso del metodo delle partite?() In nokogiri. Non sono stato in grado di trovare alcun chiarimento sul metodo. Ha qualcosa a che fare con il concetto di "partite" in XPath 2.0 (e quindi potrebbe essere usato per risolvere questo problema)?

Grazie mille.

+1

+1 - bella domanda. Benvenuti in SO :) –

risposta

9

wrapping per migliorare la leggibilità:

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

Non esiste una funzione "in minuscolo" in XPath 1.0, quindi bisogna usare translate() per questo genere di cose. Aggiungi le lettere accentate se necessario.

+0

Grazie mille Tomalak. Questa soluzione sta funzionando bene per me. – Rick

+0

FYI, xpath 1.0 di VTD-XML implementa effettivamente upperCase e lowerCase come una sorta di passaggio intermedio a 2.0 –

19

Nokogiri consente le funzioni XPath personalizzate. I documenti nokogiri che si collegano per mostrare una definizione di classe in linea per quando la si utilizza solo una volta. Se si dispone di molte funzioni personalizzate o se si utilizza molto la distinzione tra maiuscole e minuscole, è possibile definirlo in una classe.

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 

Quindi chiamarlo come qualsiasi altra funzione XPath, passando un'istanza della classe come secondo argomento.

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

nel metodo Ruby, node_set sarà legato ad un Nokogiri::XML::NodeSet. Nel caso in cui stai passando un valore di attributo come @name, sarà un NodeSet con un singolo Nokogiri::XML::Attr. Quindi chiamare to_s su di esso ti dà il suo valore. (In alternativa, è possibile utilizzare node.value.)

A differenza dell'utilizzo di XPath translate in cui è necessario specificare ogni carattere, questo funziona su tutti i caratteri e le codifiche di carattere su cui lavora Ruby.

Inoltre, se sei interessato a fare altre cose oltre alla corrispondenza senza distinzione tra maiuscole e minuscole che XPath 1.0 non supporta, è solo Ruby a questo punto. Quindi questo è un buon punto di partenza.

+0

Soluzione molto elegante! – Severin