Sunday, September 6, 2009

Groovy & XML: Retrieve the Namespace of Nested Elements

Recently, I need to retrieve the default namespace from an incoming message such as:

<message xmlns="Message" a="1" b="2">
<request>
<text xmlns="Text" a="1">ok</text>
</request>
</message>

With a message like the above, I want to retrieve the namspace Text from the text element.

One method I was able to leverage was using Groovy's DOMBuilder and DOMCategory to read the message and retrieve the namespace:

import groovy.xml.DOMBuilder
import groovy.xml.dom.DOMCategory

def xml = """<message xmlns="Message" a="1" b="2">
<request>
<text xmlns="Text" a="1">ok</text>
</request>
</message>"""

def reader = new StringReader(xml)
def doc = DOMBuilder.parse(reader)
def root = doc.documentElement
def ns

use(DOMCategory) {
ns = root['request']['text'].'@xmlns'[0]
}
println "ns=$ns"

Output:

ns=Text

Omitting the lookup of the first element, we would get a list:

ns = root['request']['text'].'@xmlns'

Output:

ns=["Text"]

This could be used to get a list of all attribute value for an element.

Another method is to use XMLParser:

def doc = new XmlParser(false, false).parseText(xml)
def ns = doc.'request'.'text'.'@xmlns'
Or XMLSlurper:
def doc = new XmlSlurper(false, false).parseText(xml)
def ns = doc.'request'.'text'.'@xmlns'

Both methods requiring making the XML reader namespace unaware with the following constructors:

XmlSlurper(boolean validating, boolean namespaceAware)
XmlParser(boolean validating, boolean namespaceAware)

I'm sure there are plenty of other methods to do the same, if you have one please feel free to leave a comment.

2 comments:

  1. Why did you want the text of the namespace attribute? In XPath/XSLT if I wanted to base logic on the namespace, I'd use pattern matching against the namespace.

    I posted an example.

    The output is:

    Cool person says:
    This is totally cool.
    Yeah I'm no good at these games.

    Geeky person says:
    Oops, I'm not cool.
    Awesome, now I'm kind of cool.

    ReplyDelete
  2. Thanks for the example.

    In the case was working on, a Mule transformer, I did need to have logic based on the value of the namespace. Most of our transformers are in Groovy so I wanted to see if it could be done, easily or not.

    ReplyDelete