Domanda

Non voglio una ripetizione di la risposta Cthulhu , ma voglio abbinare coppie di apertura e chiusura tag HTML usando Cima di albero. Utilizzando questa grammatica , posso abbinare i tag di apertura e tag di chiusura , ma ora voglio una regola per legarli entrambi insieme. Ho provato quanto segue, ma usando questo rende la mia parser andare avanti per sempre (loop infinito):

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

I stava cercando di fondare questo fuori della parentesi esempio ricorsivo e l'esempio lookahead negativo sulla pagina Treetop Github . Le altre regole che ho a cui fa riferimento sono i seguenti:

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

Lo so che avrò bisogno per consentire la corrispondenza singola apertura o la chiusura di tag, ma se un paio di tag HTML esiste, mi piacerebbe metterli insieme come una coppia. Sembrava più pulito di fare questo da loro corrispondenza con la mia grammatica, ma forse c'è un modo migliore?

È stato utile?

Soluzione

È possibile farlo solo utilizzando una regola separata per ogni coppia di tag HTML, o utilizzando un predicato semantico. Cioè, salvando il tag di apertura (in un sempred), quindi accettare (in un'altra sempred) un tag di chiusura solo se è lo stesso tag. Questo è molto più difficile da fare in Cima di quanto dovrebbe essere, perché non c'è posto comodo per salvare il contesto e non si può sbirciare lo stack parser, ma è possibile.

A proposito, lo stesso problema si verifica nel parsing confini MIME (e in Markdown). Non ho controllato l'implementazione di Mikel in ActionMailer (probabilmente usa un parser nidificato Mime per questo), ma è possibile in Cima di albero.

http://github.com/cjheath /activefacts/blob/master/lib/activefacts/cql/parser.rb risparmio contesto in un flusso di input falso - è possibile vedere quali metodi si deve sostenere - perché "input" è disponibile su tutte SyntaxNodes. Ho un diverso tipo di ragione per usare sempreds lì, ma alcune delle tecniche sono applicabili.

Altri suggerimenti

Ecco una molto semplice grammatica che utilizza un predicato semantica per abbinare il tag di chiusura al tag di partenza.

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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top