2010-11-11 3 views
2

Я не хочу повторять the Cthulhu answer, но я хочу совместить пары открывающих и закрывающих HTML-тегов с помощью Treetop. Используя this grammar, я могу сопоставить открывающие теги и закрывающие теги, но теперь я хочу, чтобы правило связывало их обоих. Я попытался следующие, но используя это делает мой парсер продолжаться вечно (бесконечный цикл):Соответствующие пар тегов в грамматике Treetop

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

Я пытался основать это от рекурсивного примера скобки и отрицательного опережения например on the Treetop Github page. Другие правила я упоминаться следующие:

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 

Я знаю, что нужно, чтобы обеспечить соответствие одного открытия или закрытия тегов, но если пара HTML-теги существуют, я хотел бы получить их вместе как пара. Казалось, что это самое чистое, сопоставляя их с моей грамматикой, но, возможно, есть лучший способ?

+0

должен там быть «+» между ' и '(! Html_close_tag (etc'? Кроме того (и я признаю, что предпросмотр в Treetop путает Кнут из меня), кажется, как бы отрицательного предпросмотра (например,
и положительный lookahead для совпадающих тегов – philosodad

+0

Хм, похоже, не должно быть +, поскольку все правило является рекурсивным, поэтому в нем уже может быть несколько открытых тегов, потому что есть другие теги. –

ответ

1

Вы можете сделать это только с помощью отдельного правила для каждой пары тегов HTML или с использованием семантического предиката. То есть, сохраняя открывающий тег (в sempred), затем принимающий (в другом sempred) закрывающий тег только в том случае, если он является тем же самым тегом. Это гораздо сложнее сделать в Treetop, чем должно быть, потому что нет удобного места для сохранения контекста, и вы не можете заглянуть в стек парсера, но это возможно.

BTW, та же проблема возникает при разборе границ MIME (и в Markdown). Я не проверял реализацию Mikel в ActionMailer (возможно, он использует для этого синтаксический анализатор Mime), но это возможно в Treetop.

В http://github.com/cjheath/activefacts/blob/master/lib/activefacts/cql/parser.rb Я сохраняю контекст в поддельном потоке ввода - вы можете видеть, какие методы он должен поддерживать, потому что «ввод» доступен на всех SyntaxNodes. У меня есть другая причина использования sempreds там, но некоторые из этих методов применимы.

5

Вот действительно простая грамматика, которая использует семантический предикат для соответствия закрывающего тега стартовому тегу.

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 

 Смежные вопросы

  • Нет связанных вопросов^_^