如何实现Xtext的doGenerate方法?求核心方法实现示例
实现Xtext的doGenerate方法来打印编辑器语句的示例
我明白你现在的困惑——看着自动生成的Xtend代码不知道怎么下手,其实核心就是遍历你的模型元素,把各个部分的文本拼接起来输出。下面给你3个逐步进阶的doGenerate实现示例,帮你搞清楚怎么操作。
首先先回顾下你的Xtext语法:每个UseStory包含Title、Role、Target、Use四个部分,我们要做的就是把这些部分的文本提取出来,组合成完整的语句。
示例1:基础版——直接拼接所有UseStory语句
这个版本最直白,直接遍历所有UseStory,把每个部分的内容拼接成完整的句子,输出到文件里:
class HellodslGenerator extends AbstractGenerator { String code = "" override void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) { // 重置拼接字符串 code = "" // 获取模型根元素Model val model = resource.allContents.filter(Model).head // 遍历每个UseStory并处理 model.usestory.forEach[funktion] // 生成输出文件 fsa.generateFile("test.txt", code) } // 拼接字符串的工具方法 def conc(String str) { code += str } // 处理单个UseStory,拼接成完整语句 def funktion(UseStory story) { // 把Title、Role、Target、Use的内容按语法顺序拼接 conc(story.title.titlen + " " + story.title.titlev.value + ": ") conc("Als " + story.role.role + " ") conc("möchte ich " + story.target.targetn + " " + story.target.targetv.value + ", ") conc("um " + story.use.usen + " zu " + story.use.usev.value + ".\n\n") } }
解释:
resource.allContents.filter(Model).head:从资源中获取你的根模型对象Modelmodel.usestory.forEach[funktion]:遍历每个UseStory,调用funktion方法处理- 每个
funktion(UseStory)方法里,我们直接取出每个属性的文本(比如story.title.titlen是标题里的名词,story.title.titlev.value是标题里的动词),按照你的Xtext语法的格式拼接成完整句子,最后加换行让每个用例分开。
示例2:结构化版——拆分各部分处理
如果后续需要扩展(比如给不同部分加格式),可以把每个组件的处理拆成单独方法,代码更易维护:
class HellodslGenerator extends AbstractGenerator { String code = "" override void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) { code = "" val model = resource.allContents.filter(Model).head model.usestory.forEach[ conc(processTitle(it)) conc(processRole(it)) conc(processTarget(it)) conc(processUse(it)) conc("\n\n") ] fsa.generateFile("test.txt", code) } def conc(String str) { code += str } // 单独处理Title部分 def processTitle(UseStory story) { return story.title.titlen + " " + story.title.titlev.value + ": " } // 单独处理Role部分 def processRole(UseStory story) { return "Als " + story.role.role + " " } // 单独处理Target部分 def processTarget(UseStory story) { return "möchte ich " + story.target.targetn + " " + story.target.targetv.value + ", " } // 单独处理Use部分 def processUse(UseStory story) { return "um " + story.use.usen + " zu " + story.use.usev.value + "." } }
解释:
- 把每个部分的文本生成逻辑拆成单独方法,比如
processTitle、processRole,这样如果以后要给标题加特殊格式、或者给角色加前缀,直接修改对应方法就行,不用动主逻辑。 - 主方法里只需要按顺序调用这些方法,代码结构更清晰,可读性更强。
示例3:增强版——带编号和格式化输出
如果想让输出更易读,比如给每个用例加编号,或者调整格式区分不同部分,可以这样写:
class HellodslGenerator extends AbstractGenerator { String code = "" override void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) { code = "=== 所有用户用例 ===\n\n" val model = resource.allContents.filter(Model).head // 遍历的时候带索引,生成编号 model.usestory.forEachIndexed[story, index | conc("用例" + (index + 1) + ": ") conc(story.title.titlen + " " + story.title.titlev.value + "\n") conc(" 角色: Als " + story.role.role + "\n") conc(" 目标: möchte ich " + story.target.targetn + " " + story.target.targetv.value + "\n") conc(" 用途: um " + story.use.usen + " zu " + story.use.usev.value + "\n\n") ] fsa.generateFile("test.txt", code) } def conc(String str) { code += str } }
解释:
- 使用
forEachIndexed遍历,获取每个用例的索引,生成直观的编号(比如“用例1:”、“用例2:”) - 给每个部分加缩进和标签(比如“角色:”、“目标:”),让输出的文本结构层次分明,方便阅读。
这三个示例从基础到进阶,你可以根据自己的需求选择。核心思路就是从模型中提取各个元素的属性值,然后按照你想要的格式拼接成字符串,最后输出到文件。
内容的提问来源于stack exchange,提问作者Detlef7able
相关产品推荐
相关产品推荐

