Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Groovy XML and the "xml:" namespace

I'm writing a couple of scripts the modify xml files. The files in question use the xml:lang element. Groovy (XmlSlurper) seems to be inserting a tag0 namespace, which I wouldn't mind too much, except it seems to break later processing with XmlUtil.

An example:

import groovy.xml.StreamingMarkupBuilder
import groovy.xml.XmlUtil

String source = """<?xml version='1.0' encoding='UTF-8'?>
<root>
    <one xml:lang="en">First</one>
    <one xml:lang="de">Second</one>
</root>
"""

def root = new XmlSlurper().parseText(source).declareNamespace(xml: "http://www.w3.org/XML/1998/namespace")
println root
String xml = new StreamingMarkupBuilder().bind{ 
    mkp.xmlDeclaration() 
    out << root 
}
println xml
println XmlUtil.serialize(xml)

results in

[Fatal Error] :2:44: The value of the attribute "prefix="xmlns",localpart="tag0",rawname="xmlns:tag0"" is invalid. Prefixed namespace bindings may not be empty.

The xml: namespace is supposed to exist by default, and I've tried adding it with .declareNamespace() but it doesn't seem to help. I feel like I'm missing something obvious, but Google hasn't been able to tell me what it is.

like image 673
Erik Ackerman Avatar asked Mar 06 '12 11:03

Erik Ackerman


2 Answers

Found this thread from a few years ago, which says:

The problem is that the original document uses the default namespace.

SMB does not normally use the default namespace so it invents a tag and uses it to explicitly mark each element in the namespace. As far as an XML parser is concerned it doesn't matter how the namespace is indicated. However there are cosmetic reasons why it is sometimes desirable to use default namespaces.

If you put mkp.declareNamespace("": "http://java.sun.com/xml/ns/j2ee") as the first line in your builder closure you should get the output you want.

However, this doesn't seem to work

The only solution I have found is to make the Slurper ignore namespaces and validation;

def root = new XmlSlurper(false,false).parseText(source)
like image 129
tim_yates Avatar answered Oct 02 '22 23:10

tim_yates


Setting default namespace to empty tag works for me (no "tag0"added). I use default XmlSlurper constructor to have working namespacing and validation, eg:

def root = new XmlSlurper().parseText(source).declareNamespace(xml: "http://www.w3.org/XML/1998/namespace")

When binding, declare empty namespace:

def writer = new StreamingMarkupBuilder().bind {
    mkp.declareNamespace("": "") //get rid of "tag0"
    mkp.declareNamespace(xml: "http://www.w3.org/XML/1998/namespace") 
    mkp.yield root
}
like image 26
minsk Avatar answered Oct 02 '22 21:10

minsk