我正在尝试创建一种严格定义的xml语言,但是在元素标签之间的元素值上遇到了麻烦。我希望将它们像字符串一样对待,除非它们没有用引号引起来。这是我创建的一个基本语法,用于说明这个想法:
grammar org.xtext.example.myxml.MyXml hidden(WS)
generate myXml "http://www.xtext.org/example/myxml/MyXml"
import "http://www.eclipse.org/emf/2002/Ecore" as ecore
Element:
{Element}
'<Element' attributes+=ElementAttribute* ('/>' | '>'
subElement+=SubElement*
'</Element' '>')
;
SubElement:
{SubElement}
'<SubElement' attributes+=SubElementAttribute* ('/>' | '>'
value=ElementValue
'</SubElement' '>')
;
ElementAttribute:
NameAttribute | TypeAttribute
;
SubElementAttribute:
NameAttribute
;
TypeAttribute:
'type' '=' type=STRING
;
NameAttribute:
'name' '=' name=STRING
;
ElementValue hidden():
value=ID
;
terminal STRING:
'"' ( '\\' . /* 'b'|'t'|'n'|'f'|'r'|'u'|'"'|"'"|'\\' */ | !('\\'|'"') )* '"' |
"'" ( '\\' . /* 'b'|'t'|'n'|'f'|'r'|'u'|'"'|"'"|'\\' */ | !('\\'|"'") )* "'"
;
terminal WS: (' '|'\t'|'\r'|'\n')+;
terminal ID: '^'?('a'..'z'|'A'..'Z'|'_'|'0'..'9'|':'|'-'|'('|')')*;
这是一个演示其用法的测试:
@Test
def void parseXML() {
val result = parseHelper.parse('''
<Element type="myType" name="myName">
<SubElement>some string:like-stuff here </SubElement>
</Element>
''')
Assert.assertNotNull(result)
val errors = result.eResource.errors
for (error : errors) {
println(error.message)
}
}
我从这个确切的代码中得到的错误是mismatched input 'string:like-stuff' expecting '</SubElement'
显然,这是行不通的,因为ID
不允许有空格,向ID
添加空格可以解决上述错误,但会引起其他解析问题。因此,我的问题是如何将元素值解析为类似字符串的表示形式,而又不会引起其他区域解析器的歧义。我能够使它以我的全部语言以任何形式工作的唯一方法是将ElementValue
变成由空白隔开的ID's
列表。 (但是,我无法在这个最小的示例上使用它,不确定有什么不同)
答案 0 :(得分:0)
我不会真的推荐它,因为Xtext通常不是最适合XML解析的方法,但是可以通过将ElementValue转换为datatype rule来实现,它允许所有不会造成歧义的事物。
类似的东西:
ElementValue returns ecore::EString hidden(): (ID|WS|STRING|UNMATCHED)+ ;
以及语法结尾:
terminal UNMATCHED: .;
您可能希望将SubElement.value设为可选,以允许使用空元素。
value=ElementValue?