打破Grails 2.2.0的变革->;Grails2.3.5,使用XmlSlurper/GPathResult并选择具有未知名称空间的attirbutes
给定以下XML:打破Grails 2.2.0的变革->;Grails2.3.5,使用XmlSlurper/GPathResult并选择具有未知名称空间的attirbutes,grails,groovy,Grails,Groovy,给定以下XML: <Response xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> <Exception> <Code>01</Code> <Message i:nil="true" /> </Exception> <Details /> </Response> 在grails 2.2
<Response xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Exception>
<Code>01</Code>
<Message i:nil="true" />
</Exception>
<Details />
</Response>
在grails 2.2.0中,我有如下代码,允许我查询/Response/Exception/Message/@I:nil属性的值,而不知道该属性的名称空间“I”:
def xml = new XmlSlurper().parse(<xml text>)
assert xml.Exception.Message.@nil.text() == 'true'
defxml=newxmlslurper().parse()
断言xml.Exception.Message。@nil.text()=“true”
但是在升级到grails 2.3.5xml.Exception.Message之后,@nil.text()
现在返回一个空字符串
我会注意到,在属性选择器中使用名称空间(如@I:nil
)确实有效,但是我的基本问题是,我所处理的API无法预测它使用的名称空间前缀,或者它是否使用了名称空间前缀
我尝试构造XmlSlurper
,使其像newxmlslurper(false,false)
一样不知道名称空间,但这样做我无法以任何方式选择属性(无论@nil
还是@I:nil
都不起作用)
有人知道我如何解决这一突破性的变化吗?这样,它将使用
XmlSlurper
或XmlParser
工作
def xmlSlurp = new XmlSlurper( false, false ).parse( xml )
assert xmlSlurp.'**'.find {it.name() == 'Message'}?.attributes()?.findResult{k,v ->
k.endsWith( 'nil' ) ? v : null
} == 'true'
您还可以对XmlSlurper
使用无参数构造函数
def xmlSlurp = new XmlSlurper( false, false ).parse( xml )
assert xmlSlurp.'**'.find {it.name() == 'Message'}?.attributes()?.findResult{k,v ->
k.endsWith( 'nil' ) ? v : null
} == 'true'
更新:一个更干净的方法是
xmlSlurp.Exception.Message[0].attributes().find { it.key.endsWith( 'nil' ) }?.value
如果我们知道,
消息将始终存在感谢@dmahapatro和@cfrick对这个答案的帮助。我只能得出结论,Grails2.3.5附带的Groovy版本中确实存在一种回归。我的最终解决方案是一个不那么痛苦的解决方案,它提供了与Grails2.2.0附带的Groovy早期版本类似的行为
下面是我用来增加GPathResult
实例的mixin方法:
/**
* Workaround GPathResult regression that doesn't play nice with attribute namespace prefixes
* @param self the parent node
* @param key the attribute name, WITHOUT namespace-prefix (multiple attribute names with different namespace prefixes not supported).
* @return a GPathResult Attribute implementation corresponding to the key argument
*/
static GPathResult attr(GPathResult self, String key) {
if(self instanceof NodeChildren)
self = self[0]
if(self instanceof NodeChild) {
def kvp = self.attributes().find {
it.key ==~ /.*[:\}]?${key}$/
}
new Attribute(kvp?.key ?: '', kvp?.value ?: '', self, '', [:])
} else {
new Attribute('', '', self, '', [:])
}
}
该实现支持带有或不带有名称空间前缀的XML属性,以及带有或不带有名称空间感知的XmlSlurper
s构造。它接受任何GPathResult
,并返回一个非空的属性
GPathResult
子类。这允许我们使用如下语法(参见问题中的示例):
我也遇到过类似的问题,我不知道如何实现上述解决方案。所以我一直在玩代码,直到我让它工作。。。。这就是我所做的
def validating = true,
namespaceAware = true,
allowDocTypeDeclaration = true
return new XmlSlurper(validating, namespaceAware, allowDocTypeDeclaration).parse(url)
使用非验证性XmlParser可能会更幸运。如果您愿意,我可以发布一个如何创建的示例。@Joshuamore感谢您的建议,但这将是最后的选择,因为正在升级的项目广泛使用XmlSlurper
/GPathResult
(也就是说,迁移到使用XmlParser
,需要做大量的工作,我在这里提出的问题在整个项目中反复出现)。我知道它不起作用(至少在groovy 2.3.9中是这样),但我希望'@*:nil'是语法,应该在这里起作用。很难接受,但谢谢。xml.Exception.Message[0].attributes()。查找{键,值->键.EnssOffice('nIL')} .Value类似地工作。如果有多个属性以相同的片段结尾,我宁愿用“代码>查找{{键==~/(.*:)/nIL/} < /代码>)。请考虑在这里发布一个新问题:StasOfFuff.com /Quass/Ask。