Groovy MarkupBuilder名称冲突 [英] Groovy MarkupBuilder name conflict
问题描述
String buildCatalog(Catalog catalog){
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
xml.catalog(xmlns:'http://www.sybrium.com/XMLSchema/NodeCatalog'){
'identity'(){
groupId(catalog.groupId)
artifactId(catalog.artifactId)
version(catalog.version)
}
}
return writer。的toString();
}
产生这个xml:
< catalog xmlns ='http://www.sybrium.com/XMLSchema/NodeCatalog'>
< groupId> sample.group< / groupId>
sample-artifact< / artifactId>
< version> 1.0.0< / version>
< / catalog>
请注意,身份标记丢失了......我试过了世界上所有的东西让该节点出现。我把我的头发撕了出来!
预先感谢您。
可能有更好的方法,但一个诀窍是直接调用 invokeMethod
:
String buildCatalog(Catalog catalog){
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
xml.catalog(xmlns:'http:// '){
delegate.invokeMethod('identity',[{
groupId(catalog.groupId)
artifactId(catalog.artifactId)
版本(catalog.version)
}])
}
返回writer.toString();
}
这就是Groovy在幕后做的事情。我无法得到 delegate.identity
或 owner.identity
来工作,这是常用的技巧。
编辑:我弄清楚发生了什么事情。
Groovy 为每个对象添加一个方法,其签名为 identity(Closure c)
。
这意味着,当您试图动态调用XML构建器上的标识
元素时,传递一个闭包参数时,它调用 identity()
方法,就像在外部闭包中调用委托({...})
一样。
使用 invokeMethod
特技强制Groovy绕过元对象协议并将该方法视为动态方法,即使 identity
方法已经存在于MetaObject中。
知道这一点,我们可以制定一个更好,更清晰的解决方案。
字符串buildCatalog(目录编目){$ b $所有我们要做的就是更改方法的签名,如下所示: b def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
xml.catalog(xmlns:'http://www.sybrium.com/XMLSchema/NodeCatalog'){
//注意:在这里保留空映射以防止调用标识方法!
identity([:]){
groupId(catalog.groupId)
artifactId(catalog.artifactId)
version(catalog.version)
}
}
return writer.toString();
}
这可读性更强,意图更清晰,评论应该希望)防止任何人删除不必要的空白地图。
I have this code:
String buildCatalog(Catalog catalog) {
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
xml.catalog(xmlns:'http://www.sybrium.com/XMLSchema/NodeCatalog') {
'identity'() {
groupId(catalog.groupId)
artifactId(catalog.artifactId)
version(catalog.version)
}
}
return writer.toString();
}
It produces this xml:
<catalog xmlns='http://www.sybrium.com/XMLSchema/NodeCatalog'>
<groupId>sample.group</groupId>
<artifactId>sample-artifact</artifactId>
<version>1.0.0</version>
</catalog>
Notice that the "identity" tag is missing... I've tried everything in the world to get that node to appear. I'm ripping my hair out!
Thanks in advance.
There might be a better way, but one trick is to call invokeMethod
directly:
String buildCatalog(Catalog catalog) {
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
xml.catalog(xmlns:'http://www.sybrium.com/XMLSchema/NodeCatalog') {
delegate.invokeMethod('identity', [{
groupId(catalog.groupId)
artifactId(catalog.artifactId)
version(catalog.version)
}])
}
return writer.toString();
}
This is effectively what Groovy is doing behind the scenes. I couldn't get delegate.identity
or owner.identity
to work, which are the usual tricks.
Edit: I figured out what's going on.
Groovy adds a method with a signature of identity(Closure c)
to every object.
This means that when you tried to dynamically invoke the identity
element on the XML builder, while passing in a single closure argument, it was calling the identity()
method, which is like calling delegate({...})
on the outer closure.
Using the invokeMethod
trick forces Groovy to bypass the Meta Object Protocol and treat the method as a dynamic method, even though the identity
method already exists on the MetaObject.
Knowing this, we can put together a better, more legible solution. All we have to do is change the signature of the method, like so:
String buildCatalog(Catalog catalog) {
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
xml.catalog(xmlns:'http://www.sybrium.com/XMLSchema/NodeCatalog') {
// NOTE: LEAVE the empty map here to prevent calling the identity method!
identity([:]) {
groupId(catalog.groupId)
artifactId(catalog.artifactId)
version(catalog.version)
}
}
return writer.toString();
}
This is much more readable, it's clearer the intent, and the comment should (hopefully) prevent anyone from removing the "unnecessary" empty map.
这篇关于Groovy MarkupBuilder名称冲突的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!