2010-11-11 14 views
2

Je ne veux pas une répétition de the Cthulhu answer, mais je veux faire correspondre des paires de balises HTML d'ouverture et de fermeture en utilisant Treetop. En utilisant this grammar, je peux faire correspondre les balises d'ouverture et de fermeture des balises, mais maintenant je veux une règle pour les attacher ensemble. J'ai essayé ce qui suit, mais en utilisant ce qui rend mon analyseur aller à l'infini (boucle infinie):paires de balises correspondant dans Treetop grammaire

rule html_tag_pair 
    html_open_tag (!html_close_tag (html_tag_pair/''/text/newline/
    whitespace))+ html_close_tag <HTMLTagPair> 
end 

je tentais de baser ce hors de l'exemple des parenthèses récursive et l'exemple négatif on the Treetop Github page préanalyse. Les autres règles que je l'ai pris en référence sont les suivantes:

rule newline 
    [\n\r] { 
    def content 
     :newline 
    end 
    } 
end 

rule tab 
    "\t" { 
    def content 
     :tab 
    end 
    } 
end 

rule whitespace 
    (newline/tab/[\s]) { 
    def content 
     :whitespace 
    end 
    } 
end 

rule text 
    [^<]+ { 
    def content 
     [:text, text_value] 
    end 
    } 
end 

rule html_open_tag 
    "<" html_tag_name attribute_list ">" <HTMLOpenTag> 
end 

rule html_empty_tag 
    "<" html_tag_name attribute_list whitespace* "/>" <HTMLEmptyTag> 
end 

rule html_close_tag 
    "</" html_tag_name ">" <HTMLCloseTag> 
end 

rule html_tag_name 
    [A-Za-z0-9]+ { 
    def content 
     text_value 
    end 
    } 
end 

rule attribute_list 
    attribute* { 
    def content 
     elements.inject({}){ |hash, e| hash.merge(e.content) } 
    end 
    } 
end 

rule attribute 
    whitespace+ html_tag_name "=" quoted_value { 
    def content 
     {elements[1].content => elements[3].content} 
    end 
    } 
end 

rule quoted_value 
    ('"' [^"]* '"'/"'" [^']* "'") { 
    def content 
     elements[1].text_value 
    end 
    } 
end 

Je sais que je vais devoir laisser pour faire correspondre les balises d'ouverture ou de fermeture simple, mais si une paire de balises HTML existent, j'aimerais les obtenir ensemble comme une paire. Il semblait plus propre de le faire en les associant à ma grammaire, mais peut-être y a-t-il un meilleur moyen?

+0

devrait y avoir un « + » entre '' et '(! Html_close_tag (etc'? De plus (et je reconnais que dans arboricole préanalyse brouille les Knuth de moi) il semble que négatif serait préanalyse Hm, il ne semble pas qu'il devrait y avoir de + puisque la règle entière est récursive, donc il peut déjà y avoir plusieurs balises ouvertes, car il y a d'autres balises ouvertes (comme
et – philosodad

+0

). paires de balises en elle. –

Répondre

1

Vous pouvez uniquement utiliser une règle distincte pour chaque paire de balises HTML ou utiliser un prédicat sémantique. C'est-à-dire en sauvegardant la balise d'ouverture (dans un sempred), puis en acceptant (dans un autre sempred) une balise de fermeture seulement si c'est la même balise. C'est beaucoup plus difficile à faire dans Treetop qu'il ne devrait l'être, car il n'y a pas d'endroit pratique pour sauvegarder le contexte et vous ne pouvez pas jeter un coup d'œil sur la pile de l'analyseur, mais c'est possible. BTW, le même problème se produit dans l'analyse des limites MIME (et dans Markdown). Je n'ai pas vérifié l'implémentation de Mikel dans ActionMailer (probablement il utilise un analyseur MIME imbriqué pour cela), mais c'est possible dans Treetop.

Dans http://github.com/cjheath/activefacts/blob/master/lib/activefacts/cql/parser.rb J'enregistre le contexte dans un faux flux d'entrée - vous pouvez voir quelles méthodes il doit prendre en charge - car "entrée" est disponible sur tous les SyntaxNodes. J'ai une raison différente d'utiliser des sempreds, mais certaines techniques sont applicables.

5

Voici une grammaire très simple qui utilise un prédicat sémantique pour faire correspondre l'étiquette de fermeture à l'étiquette de début.

grammar SimpleXML 
    rule document 
    (text/tag)* 
    end 

    rule text 
    [^<]+ 
    end 

    rule tag 
    "<" [^>]+ ">" (text/tag)* "</" [^>]+ &{|seq| seq[1].text_value == seq[5].text_value } ">" 
    end 
end