Use of Namespaces in Groovy MarkupBuilder - groovy

I want have the following output:
<?xml version="1.0" encoding="UTF-8"?>
<structure:structuralDataRoot xmlns:register="http://www.test.ch/register/1" xmlns:structure="http://test.ch/structure/1" >
<structure:tester>ZH</structure:tester>
<structure:surveyYear>2001</structure:surveyYear>
<structure:surfaceData>
<structure:houseSurfaceData>
<structure:creationDate>2001-01-01</structure:creationDate>
<structure:localFarmId>
<register:houseIdCategory>token</register:houseIdCategory>
<register:houseId>token</register:houseId>
</structure:localFarmId>
</structure:houseSurfaceData>
</structure>
I can add namespace to an xml like this:
xml.records('xmlns:structure' :"http://test.ch/structure/1" ...
But how I can make a namespace prefix to an xml-element?
The only solution I found was this:
tester('xmlns:structure' :"http://test.ch/structure/1", 'ZH')
But this gives me the follwing output:
<tester xmlns:structure='http://test.ch/structure/1'>ZH</tester>
It's syntactical correct, but not nice to read when you have many nodes.

You can do this (not sure it's what you want though)
import groovy.xml.StreamingMarkupBuilder
import groovy.xml.XmlUtil
def xmlBuilder = new StreamingMarkupBuilder()
writer = xmlBuilder.bind {
mkp.declareNamespace( register: "http://www.test.ch/register/1" )
mkp.declareNamespace( structure: "http://test.ch/structure/1" )
'structure:structuralDataRoot' {
'structure:tester'( 'ZH' )
'structure:surveyYear'( 2001 )
'structure:surfaceData' {
'structure:houseSurfaceData' {
'structure:creationDate'( '2001-01-01' )
'structure:localFarmId' {
'register:houseIdCategory'( 'token' )
'register:houseId'( 'token' )
}
}
}
}
}
println XmlUtil.serialize( writer )
That code outputs:
<?xml version="1.0" encoding="UTF-8"?>
<structure:structuralDataRoot xmlns:register="http://www.test.ch/register/1" xmlns:structure="http://test.ch/structure/1">
<structure:tester>ZH</structure:tester>
<structure:surveyYear>2001</structure:surveyYear>
<structure:surfaceData>
<structure:houseSurfaceData>
<structure:creationDate>2001-01-01</structure:creationDate>
<structure:localFarmId>
<register:houseIdCategory>token</register:houseIdCategory>
<register:houseId>token</register:houseId>
</structure:localFarmId>
</structure:houseSurfaceData>
</structure:surfaceData>
</structure:structuralDataRoot>

Related

JSON to XML conversion in Node JS service (using xml2js)

I need some help/advice with JSON to XML conversion in Node js.
I have a service that gets a JSON object in request body that needs to convert to XML. I am able to achieve this using node-xml2js for json inputs with maximum one level of nested objects. But, it gets way more complicated with nested objects having attribute values. Attributes should be identified first, prefixed with $ sign and enclosed in curly braces before parsing through xml2js to get correct xml.
Is there a better way of doing this where this complicated layer of reformatting the json input can be simplified?
xml2js can converts this:
{
"Level1":{ "$":{ "attribute":"value" },
"Level2": {"$":{"attribute1":"05/29/2020",
"attribute2":"10","attribute3":"Pizza"}}
}
to this:(which is correct):
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Level1 attribute="value">
<Level2 attribute1="05/29/2020" attribute2="10" attribute3="Pizza"/>
</Level1>
But actual json input is this:
{
"Level1":{"attribute":"value",
"Level2": {"attribute1":"05/29/2020",
"attribute2":"10","attribute3":"Pizza"} }
}
Expected same result:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Level1 attribute="value">
<Level2 attribute1="05/29/2020" attribute2="10" attribute3="Pizza"/>
</Level1>
Please let me know if you have worked on similar requirements. Appreciate any help.
Thank you.
This would be a way to change the object back to the format expected in the library, although it assumes that all non object keys are supposed to be attributes (is that a valid assumption for your application?)
function groupChildren(obj) {
for(prop in obj) { // consider filtering for own properties (vs from prototype: for(prop of Object.keys(obj)) {
if (typeof obj[prop] === 'object') {
groupChildren(obj[prop]);
} else {
obj['$'] = obj['$'] || {};
obj['$'][prop] = obj[prop];
delete obj[prop];
}
}
return obj;
}
and then used like so:
var xml2js = require('xml2js');
var obj = {
Level1: {
attribute: 'value',
Level2: {
attribute1: '05/29/2020',
attribute2: '10',
attribute3: 'Pizza'
}
}
};
var builder = new xml2js.Builder();
var xml = builder.buildObject(groupChildren(obj));
which prints out:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Level1 attribute="value">
<Level2 attribute1="05/29/2020" attribute2="10" attribute3="Pizza"/>
</Level1>
you can use this library :nashwaan/xml-js
Like This:
let xmlJ=require('xml-js');
let parseToJson=(xml)=>{
return new Promise(resolve => {
let convert;
convert=xmlJ.xml2json(xml,{compact:true});
resolve(convert);
});
};

How to add namespaces to a tag using Groovy's MarkupTemplateEngine

Is there a way to have a tag with a namespace using MarkupTemplateEngine?
I would like to be able to do something like this:
sp.setNameSpaceDeclaration('http://example.org/myns')
xmlDeclaration()
cars(sp.ns) {
cars.each {
car(make: it.make, model: it.model)
sp.brand(attribute:'year', 'my text')
}
}
and get
<?xml version='1.0' encoding='UTF-8'?>
<cars xmlns:sp="http://example.org/myns">
<car make='Peugeot' model='508'/>\
<sp:brand attribute='year'>my text</sp:brand>
<car make='Toyota' model='Prius'/>
<sp:brand attribute='year'>my text</sp:brand>
</cars>
I found a way to tweak the template to get the result I wanted. There might be better solutions, but for now I am using:
xmlDeclaration()
cars('xmlns:sp':"http://example.org/myns") {
cars.each {
car(make: it.make, model: it.model)
'sp:brand'(attribute:'year', 'my text')
}
}
You're almost there. I have included the StreamingMarkupBuilder initialization for completeness
def builder = new StreamingMarkupBuilder()
builder.encoding = 'UTF-8'
def cars = builder.bind {
mkp.xmlDeclaration()
namespaces << [sp:'http://example.org/myns']
cars('xmlns:sp':"http://example.org/myns") {
cars.each {
car(make: it.make, model: it.model)
'sp:brand'(attribute:'year', 'my text')
}
}
}
I want to use a template file, so the way I am handling this for now is:
cars.tpl Template:
xmlDeclaration()
cars('xmlns:sp':"http://www.w3schools.com/furniture") {
comment commentTest
newLine()
cars.each {
car(make: it.make, model: it.model)
newLine()
'sp:brand'(attribute:'year', 'my text')
newLine()
}
}
Program
URL url = this.getClass().getResource("/cars.tpl");
File markupTemplate = new File(url.getFile());
TemplateConfiguration config = new TemplateConfiguration();
config.setAutoNewLine(true);
config.setAutoIndent(true);
config.setDeclarationEncoding('UTF-8');
MarkupTemplateEngine engine = new MarkupTemplateEngine(config);
Template template = engine.createTemplate(markupTemplate);
def model = [commentTest: 'alberto', cars: [new Car(make: 'Peugeot', model: '508'), new Car(make: 'Toyota', model: 'Prius')]]
def fout = new File("C:\\code\\cesa\\src\\test\\resources\\cars.xml")
fout.withWriter('UTF-8') {writer ->
template.make(model).writeTo(writer)
}

How to add dynamically node to XML in Groovy with the StreamingMarkupBuilder

I am trying to dynamically create an XML file with Groovy. I'm pleased with the simplicity everything works, but i am having a hard time understanding the whole mechanism behind closures and delegates. While it appears to be easy to add properties and child nodes with a fixed name, adding a node with a dynamic name appears to be a special case.
My use case is creating a _rep_policy file, which can be used in CQ5.
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:rep="internal"
jcr:primaryType="rep:ACL">
<allow
jcr:primaryType="rep:GrantACE"
rep:principalName="administrators"
rep:privileges="{Name}[jcr:all]"/>
<allow0
jcr:primaryType="rep:GrantACE"
rep:principalName="contributor"
rep:privileges="{Name}[jcr:read]"/>
</jcr:root>
Processing the collections works fine, but generating the name ...
import groovy.xml.StreamingMarkupBuilder
import groovy.xml.XmlUtil
def _rep_policy_files = [
'/content': [ // the path
'deny': [ // permission
'jcr:read': [ // action
'a1', 'b2']], // groups
'allow': [
'jcr:read, jcr:write': [
'c2']
]
]
]
def getNodeName(n, i) {
(i == 0) ? n : n + (i - 1)
}
_rep_policy_files.each {
path, permissions ->
def builder = new StreamingMarkupBuilder();
builder.encoding = "UTF-8";
def p = builder.bind {
mkp.xmlDeclaration()
namespaces << [
jcr: 'http://www.jcp.org/jcr/1.0',
rep: 'internal'
]
'jcr:root'('jcr:primaryType': 'rep:ACL') {
permissions.each {
permission, actions ->
actions.each {
action, groups ->
groups.eachWithIndex {
group, index ->
def nodeName = getNodeName(permission, index)
"$nodeName"(
'jcr:primaryType': 'rep:GrantACE',
'rep:principalName': "$group",
'rep:privileges': "{Name}[$action]")
}
}
}
}
}
print(XmlUtil.serialize(p))
}
Is this something (or similar) that you are looking for?
'jcr:root'('jcr:primaryType': 'rep:ACL') {
_rep_policy_files['/content'].each {k, v ->
if(k == 'allow')
"$k"('jcr:primaryType': 'rep:GrantACE',
'rep:principalName': 'administrators',
'rep:privileges': "$v" ){}
if(k == 'deny')
"$k"('jcr:primaryType': 'rep:GrantACE',
'rep:principalName': 'contributor',
'rep:privileges': "$v" ){}
}
}
The resultant xml shown in question cannot be apprehended properly with what you have in _rep_policy_files.

Read a Xml file in Groovy

I am reading a xml file in groovy something like below, but don't know what is going wrong.
Below is my function
def setEnvironment(Map env,Map params)
{
def records=new XmlSlurper().parse(env.get("ABC_HOME")+"/isp/config/nodemeta.xml")
def jdbcurl=records.'domainservice:DBConnectivity'[0].#dbConnectString
params.put("dn", records.'domainservice:GatewayNodeConfig'[0].#domainName)
params.put("dh", records.'domainservice:GatewayNodeConfig'[0].'address'[0].#host)
params.put("dp", records.'domainservice:GatewayNodeConfig'[0].'address'[0].#httpPort)
params.put("u", records.'domainservice:DBConnectivity'[0].#dbUsername)
if(jdbcurl==null||jdbcurl.size()==0)
{
params.put("tns", records.'domainservice:DBConnectivity'[0].#dbHost)
}
else
{
params.put("tns", jdbcurl.find("(?<=%2F%2F)[\\d\\w_]+"))
}
println params
}
My Output
[pd:admin, u:, tns:, dh:, dn:, dp:, un:admin, x:c1164035531]
My Xml
<?xml version="1.0" encoding="UTF-8"?>
<imx:IMX xmlns:imx="http://com.abc.imx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" serializationSpecVersion="4.0" crcEnabled="0" xmlns:domainservice="http://com.abc.isp.metadata.domainservice/2" versiondomainservice="2.4.1" xmlns:common="http://com.abc.isp.metadata.common/2" versioncommon="2.2.0" xsi:schemaLocation="http://com.abc.imx IMX.xsd http://com.abc.isp.metadata.domainservice/2 com.abc.isp.metadata.domainservice.xsd http://com.abc.isp.metadata.common/2 com.abc.isp.metadata.common.xsd">
<domainservice:GatewayNodeConfig imx:id="U:LtWHxY0ZEeGb2FwhP-xoGw" adminconsolePort="15533" adminconsoleShutdownPort="38207" domainName="D_1035531" nodeName="N_1035531" dbConnectivity="ID_1">
<address imx:id="ID_2" xsi:type="common:NodeAddress" host="absdie" httpPort="1531" port="1532"/>
<portals>
<NodeRef imx:id="ID_3" xsi:type="common:NodeRef" address="ID_2" nodeName="N_1035531"/>
</portals>
</domainservice:GatewayNodeConfig>
<domainservice:DBConnectivity imx:id="ID_1" dbEncryptedPassword="ZmTXZDoYq0TyrU7fSaS9BrAlIuZyS2rw%2FafW1TLWE4g%3D" dbHost="fortuner" dbName="ORCL" dbPort="1521" dbType="ORACLE" dbUsername="zx1649355388"/>
</imx:IMX>
Note: pd & x are already there in the map
XmlSlurper is handling the namespaces for you... Just get rid of the namespace part of the node names (note the more Groovy map management as well)
params.dn = records.GatewayNodeConfig[0].#domainName.text()
params.dh = records.GatewayNodeConfig[0].address[0].#host.text()
params.dp = records.GatewayNodeConfig[0].address[0].#httpPort.text()
params.u = records.DBConnectivity[0].#dbUsername.text()

how to create xml document with special node names with groovy markupbuilder

I am building an ant script with groovy markupbuilder. Unfortunately markupbuilder doesn't allow me to create nodes with name 'target' (no problem with targetee),
becauase it throws me
Caught: groovy.lang.MissingMethodException: No signature of method: java.lang.String.call() is applicable for argument types: (java.util.LinkedHashMap, BuildGen$_main_closure1_closure5) values: [[name:clean], BuildGen$_main_closure1_closure5#18efaea]
Possible solutions: wait(), any(), trim(), split(), dump(), next()
so inside my markupbuilder this snippet works:
targete(name: 'clean') {
delete(dir: rootProj.compilerOutput)
}
but I would like to achieve the same with a 'target' node..
I managed to create an empty 'target' node this way:
builder.invokeMethod('target', [name: 'clean'])
but how can I go on and put more nodes inside this 'target' node?
Example of working code:
def writer = new StringWriter()
def builder = new groovy.xml.MarkupBuilder(writer)
builder.project(name: projectName, basedir:'.') {
// works with 'target2' but not with 'target'
'target2'(name: 'build-subprojects') {
rootProj.getAllDependentProjects().each { p->
echo(message: "Compiling project: ${p.projectName}")
// some real stuff
}
}
If I guess right, your problem is you want to create nodes with names that are Groovy keywords?
If so, then you can simply put the name in quotes, like so:
def writer = new StringWriter()
def builder = new groovy.xml.MarkupBuilder( writer )
builder.project {
'for'(name: 'clean') {
delete(dir: '.')
}
}
println writer
That snippet will print out:
<project>
<for name='clean'>
<delete dir='.' />
</for>
</project>
For me, this works:
def projects = [ 'pro_one', 'pro_two' ]
def writer = new StringWriter()
def builder = new groovy.xml.MarkupBuilder(writer)
builder.project( name: 'test', basedir:'.' ) {
'target'( name: 'build-subprojects' ) {
projects.each { p ->
echo( message: "Compiling project: ${p}" )
}
}
}
println writer.toString()
Have you got target set to anything in your code before calling this?
You could try:
builder.target( name: 'build-subprojects' ) {
That might work better?
I've tried Groovy 1.7.5, and 1.8 beta 2 and can't get it to fail :-/

Resources