打破Grails 2.2.0的变革->;Grails2.3.5,使用XmlSlurper/GPathResult并选择具有未知名称空间的attirbutes

打破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

给定以下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.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.5
xml.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。