问题描述
我正在尝试从ANTLR解析树中提取数据,但没有完全掌握应如何正确完成操作
// language=sql
val sql3 = """
CREATE TABLE session(
id uuid not null
constraint account_pk
primary key,created timestamp default Now() not null
)
""".trimIndent()
// language=sql
val sql4 = """
CREATE TABLE IF NOT EXISTS blah(
id uuid not null
constraint account_pk
primary key,created timestamp default Now() not null
)
""".trimIndent()
现在我同时解析它们:
val visitor = Visitor()
listof(sql3,sql4).forEach { sql ->
val lexer = sqlLexer(CharStreams.fromString(sql))
val parser = sqlParser(CommonTokenStream(lexer))
visitor.visit(parser.sql())
println(visitor.tableName)
}
在我的访客中,如果我访问tableCreateStatement,我会得到解析树,但是显然抓取child1将对sql3
有效,但对sql4
无效,因为sql4
中的child1为{ {1}}
IF NOT EXISTS
有没有办法在解析树中找到特定的令牌?
我假设有效载荷与它有关,但是由于它的类型为class Visitor : sqlParserBaseVisitor<Unit>() {
var tableName = ""
override fun visitCreate_table_statement(ctx: sqlParser.Create_table_statementContext?) {
tableName = ctx?.getChild(1)?.text ?: ""
super.visitCreate_table_statement(ctx)
}
}
,所以我不确定要对它进行检查吗
Any
编辑 :. g4文件来自 https://github.com/pgcodekeeper/pgcodekeeper/tree/master/apgdiff/antlr-src
解决方法
这似乎可行
override fun visitCreate_table_statement(ctx: SQLParser.Create_table_statementContext?) {
ctx?.children?.forEach {
if (it.payload.javaClass == Schema_qualified_nameContext::class.java) {
tableName = it.text
}
}
super.visitCreate_table_statement(ctx)
}
对于分支树
fun walkLeaves(
childTree: ParseTree = internalTree,leave: (childTree: ParseTree) -> Unit) {
if (childTree.childCount == 0) {
if (!childTree.text?.trim().isNullOrBlank()) {
leave(childTree)
}
} else {
for (i in 0 until childTree.childCount) {
walkLeaves(childTree = childTree.getChild(i),leave = leave)
}
}
}
fun extractSQL(
childTree: ParseTree,tokens: MutableList<String> = mutableListOf()
): String {
walkLeaves(childTree = childTree) { leave ->
tokens.add(leave.text)
}
...
}