使用 antlr4 解析 XML 标签和属性时出现问题
Problem using antlr4 to parse XML tag & attributes
我正在写一个简化的 antlr4 XML 语法来解析这个例子:
<root>
<field a="1">
random text
</field>
</root>
语法是:
grammar TestKo;
root : '<root>' WS* field* WS* '</root>' ;
field : '<field' attr* '>' chardata* '</field>' ; // fails
attr : TEXT '=' '"' TEXT '"';
chardata : TEXT | WS ;
WS : (' '|'\t'|'\r'? '\n')+ -> skip;
TEXT : ~[<&]+ ;
运行 与 antlr4:
$ antlr4 TestKo.g4 && javac -cp /usr/share/java/antlr4-runtime.jar TestKo*java
$ cat ./test.xml | grun TestKo root -tree
line 4:2 mismatched input '</field>' expecting '='
(root <root> (field <field (attr a="1">\n\trandom text\n </field>)) </root>)
正确解析 field
和 '>'
之间的属性缺少什么?
感谢您的任何建议。
在解析器考虑任何解析器规则之前,词法分析器运行完成。推论:解析器规则评估不能 affect/influence 词法分析器规则评估。所以,规则
TEXT : ~[<&]+ ;
将使用 [>="/]
,防止解析器看到相应的隐式标记。 (这是语法的主要错误。)
解释:在解析器中为字符串生成隐式标记。这是对“解析器不影响词法分析器”这一老生常谈的警告。它们在内部被定义为位于词法分析器规则列表的顶部,即通过魔法,因此具有最高的单个字符匹配优先级。
TEXT
规则可以匹配多个字符串,并且对于这些字符串,具有更高的绝对匹配优先级:当多个词法分析器规则可以匹配给定输入时,匹配长度最长的规则获胜;如果长度相同,则第一个列出的规则获胜。
出于各种实际原因——清晰度和可维护性——最好不要依赖隐式标记。
建议:解析 XML 不 简单。区分 random text
和标签,作为目前的语法尝试,将是有问题的。鉴于标签提供了明确的保护字符——<
和 >
——使用 Antlr mode
功能将结构化的标签内词汇与 random text
的词汇完全隔离开来语法更容易设计和维护。
顺便说一句,-> skip
确实如其所说:不会产生任何令牌。所以,解析器规则
chardata : TEXT | WS ;
永远不会看到 WS
令牌。
如果您是 Antlr 的新手,TDAR 非常值得一读。
当我检查问题并准备答案时,您已经有了答案...
负标记很难管理,它们会消耗文件的其余部分。随着你的语法重命名为问题和你的数据:
$ grun Question root -tokens data.txt
[@0,0:5='<root>',<'<root>'>,1:0]
[@1,9:14='<field',<'<field'>,2:2]
[@2,15:40=' a="1">\n random text\n ',<TEXT>,2:8]
[@3,41:48='</field>',<'</field>'>,4:2]
[@4,50:56='</root>',<'</root>'>,5:0]
[@5,58:57='<EOF>',<EOF>,6:0]
line 4:2 mismatched input '</field>' expecting '='
它没有找到 =,因为它已被 attr
的第一个 TEXT
规则消耗在令牌 @2 中。试试这个:
grammar Question;
root : '<root>' WS* field* WS* '</root>' ;
field : '<field' attr* '>' chardata* '</field>' ;
attr : TEXT '=' STRING ;
chardata : TEXT | WS ;
STRING : '"' .*? '"' ;
WS : (' '|'\t'|'\r'? '\n')+ -> skip;
TEXT : ~[=<>&]+ ;
执行:
$ export CLASSPATH=".:/usr/local/lib/antlr-4.6-complete.jar"
$ alias a4='java -jar /usr/local/lib/antlr-4.6-complete.jar'
$ alias grun='java org.antlr.v4.gui.TestRig'
$ a4 Question.g4
$ javac Question*.java
$ grun Question root -tokens data.txt
[@0,0:5='<root>',<'<root>'>,1:0]
[@1,9:14='<field',<'<field'>,2:2]
[@2,15:16=' a',<TEXT>,2:8]
[@3,17:17='=',<'='>,2:10]
[@4,18:20='"1"',<STRING>,2:11]
[@5,21:21='>',<'>'>,2:14]
[@6,22:40='\n random text\n ',<TEXT>,2:15]
[@7,41:48='</field>',<'</field>'>,4:2]
[@8,50:56='</root>',<'</root>'>,5:0]
[@9,58:57='<EOF>',<EOF>,6:0]
我正在写一个简化的 antlr4 XML 语法来解析这个例子:
<root>
<field a="1">
random text
</field>
</root>
语法是:
grammar TestKo;
root : '<root>' WS* field* WS* '</root>' ;
field : '<field' attr* '>' chardata* '</field>' ; // fails
attr : TEXT '=' '"' TEXT '"';
chardata : TEXT | WS ;
WS : (' '|'\t'|'\r'? '\n')+ -> skip;
TEXT : ~[<&]+ ;
运行 与 antlr4:
$ antlr4 TestKo.g4 && javac -cp /usr/share/java/antlr4-runtime.jar TestKo*java
$ cat ./test.xml | grun TestKo root -tree
line 4:2 mismatched input '</field>' expecting '='
(root <root> (field <field (attr a="1">\n\trandom text\n </field>)) </root>)
正确解析 field
和 '>'
之间的属性缺少什么?
感谢您的任何建议。
在解析器考虑任何解析器规则之前,词法分析器运行完成。推论:解析器规则评估不能 affect/influence 词法分析器规则评估。所以,规则
TEXT : ~[<&]+ ;
将使用 [>="/]
,防止解析器看到相应的隐式标记。 (这是语法的主要错误。)
解释:在解析器中为字符串生成隐式标记。这是对“解析器不影响词法分析器”这一老生常谈的警告。它们在内部被定义为位于词法分析器规则列表的顶部,即通过魔法,因此具有最高的单个字符匹配优先级。
TEXT
规则可以匹配多个字符串,并且对于这些字符串,具有更高的绝对匹配优先级:当多个词法分析器规则可以匹配给定输入时,匹配长度最长的规则获胜;如果长度相同,则第一个列出的规则获胜。
出于各种实际原因——清晰度和可维护性——最好不要依赖隐式标记。
建议:解析 XML 不 简单。区分 random text
和标签,作为目前的语法尝试,将是有问题的。鉴于标签提供了明确的保护字符——<
和 >
——使用 Antlr mode
功能将结构化的标签内词汇与 random text
的词汇完全隔离开来语法更容易设计和维护。
顺便说一句,-> skip
确实如其所说:不会产生任何令牌。所以,解析器规则
chardata : TEXT | WS ;
永远不会看到 WS
令牌。
如果您是 Antlr 的新手,TDAR 非常值得一读。
当我检查问题并准备答案时,您已经有了答案...
负标记很难管理,它们会消耗文件的其余部分。随着你的语法重命名为问题和你的数据:
$ grun Question root -tokens data.txt
[@0,0:5='<root>',<'<root>'>,1:0]
[@1,9:14='<field',<'<field'>,2:2]
[@2,15:40=' a="1">\n random text\n ',<TEXT>,2:8]
[@3,41:48='</field>',<'</field>'>,4:2]
[@4,50:56='</root>',<'</root>'>,5:0]
[@5,58:57='<EOF>',<EOF>,6:0]
line 4:2 mismatched input '</field>' expecting '='
它没有找到 =,因为它已被 attr
的第一个 TEXT
规则消耗在令牌 @2 中。试试这个:
grammar Question;
root : '<root>' WS* field* WS* '</root>' ;
field : '<field' attr* '>' chardata* '</field>' ;
attr : TEXT '=' STRING ;
chardata : TEXT | WS ;
STRING : '"' .*? '"' ;
WS : (' '|'\t'|'\r'? '\n')+ -> skip;
TEXT : ~[=<>&]+ ;
执行:
$ export CLASSPATH=".:/usr/local/lib/antlr-4.6-complete.jar"
$ alias a4='java -jar /usr/local/lib/antlr-4.6-complete.jar'
$ alias grun='java org.antlr.v4.gui.TestRig'
$ a4 Question.g4
$ javac Question*.java
$ grun Question root -tokens data.txt
[@0,0:5='<root>',<'<root>'>,1:0]
[@1,9:14='<field',<'<field'>,2:2]
[@2,15:16=' a',<TEXT>,2:8]
[@3,17:17='=',<'='>,2:10]
[@4,18:20='"1"',<STRING>,2:11]
[@5,21:21='>',<'>'>,2:14]
[@6,22:40='\n random text\n ',<TEXT>,2:15]
[@7,41:48='</field>',<'</field>'>,4:2]
[@8,50:56='</root>',<'</root>'>,5:0]
[@9,58:57='<EOF>',<EOF>,6:0]