Search code examples
xmlgroovyxml-parsingxmlslurper

How to get the value of XML attribute using groovy


I am trying to fetchthe value of attribute xmlns inside CanOfferProductResponse tag in Groovy

below is my XML-

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <SOAP-ENV:Body><CanOfferProductResponse xmlns="urn:iQQ:API:22:iQQMessages.xsd"/></SOAP-ENV:Body></SOAP-ENV:Envelope>

I tried below code but it's not working

def Envelope = new XmlSlurper().parseText(xml) 
println Envelope.Body.CanOfferProductResponse.@xmlns

// expected output = urn:iQQ:API:22:iQQMessages.xsd (which is inside Tag)

I am new to XML, please help me.


Solution

  • The use of XML namespaces is complicating matters perhaps. If you know that the XML snippet is using the exact namespace prefixes as shown, you can disable namespace awareness in the XmlSlurper and use the "prefix:elementName" as to reference the elements.

    def xml = '''<?xml version="1.0" encoding="UTF-8"?>
    <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
                       xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <SOAP-ENV:Body>
            <CanOfferProductResponse xmlns="urn:iQQ:API:22:iQQMessages.xsd"/>
        </SOAP-ENV:Body>
    </SOAP-ENV:Envelope>
    '''
    
    // the second constructor argument controls namespace awareness
    def env = new XmlSlurper(false, false).parseText(xml)
    def namespace = env.'SOAP-ENV:Body'.CanOfferProductResponse.@xmlns
    assert namespace == 'urn:iQQ:API:22:iQQMessages.xsd'
    

    But if the default namespace is not always defined on the CanOfferProductResponse element or if the namespace prefixes are not always consistent, e.g. the Envelope element has a xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" attribute instead of an xmlns:SOAP-ENV=..., then this approach would not work.

    A namespace-aware approach would involve calling the lookupNamespace method passing in an empty String argument (which means the default namespace for that element):

    // by default, XmlSlurper instances are namespace aware
    def env = new XmlSlurper().parseText(xml)
    def namespace = env.Body.CanOfferProductResponse.lookupNamespace('')
    assert namespace == 'urn:iQQ:API:22:iQQMessages.xsd'
    

    But since namespaces are inherited, this approach means that the lookupNamespace method would still return 'urn:iQQ:API:22:iQQMessages.xsd' even if there wasn't physically an xmlns attribute on the CanOfferProductResponse element, e.g.

    def xml = '''<?xml version="1.0" encoding="UTF-8"?>
    <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
                       xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                       xmlns="urn:iQQ:API:22:iQQMessages.xsd">
        <SOAP-ENV:Body>
            <CanOfferProductResponse />
        </SOAP-ENV:Body>
    </SOAP-ENV:Envelope>
    '''
    
    def env = new XmlSlurper().parseText(xml)
    def namespace = env.Body.CanOfferProductResponse.lookupNamespace('')
    assert namespace == 'urn:iQQ:API:22:iQQMessages.xsd'
    

    (This sample was executed with Groovy 2.5)