I am using MarkupBuilder to generate xml, need to know how can I add NodeChild to a MarkupBuilder Object
my code
def fxml=new File("E:\\Projects\\dom.xml")
def xmltext=new XmlSlurper(false,false).parseText(fxml.text)
or
def xml=new XmlSlurper(false,false).parse("E:\\Projects\\dom.xml")
def abc = new groovy.xml.MarkupBuilder()
abc.product(name:"Dota"){
language("Java")
language("Groovy")
language("JavaScript")
domainsinfa{delegate.current.appendNode( xmltext)}
}
You can use StreamingMarkupBuilder to insert arbitrary nodes to the xml:
import groovy.xml.*
def xmltext = '''<node><name short="yes">tim</name><fun>maybe</fun></node>'''
def xml = new XmlSlurper( false, false ).parseText( xmltext )
def newxml = new StreamingMarkupBuilder().bind {
product(name:"Dota") {
language("Java")
language("Groovy")
language("JavaScript")
mkp.yield xml
}
}
println XmlUtil.serialize( newxml )
Related
I am using Groovy MarkupBuilder to create an XML file. I can do it fine when I have static tags, like this
def userCreationNumber = "12530";
def userCreationDate = "02/02/2020";
def userCreationAuthor = "admin";
Creation{
Revision(userCreationNumber)
Date(userCreationDate )
Author(userCreationAuthor)
}
this creates XML like this
<Creation>
<Revision>12530</Revision>
<Date>02/02/2020</Date>
<Author>admin</Author>
</Creation>
but how can I create XML with dynamic tags?
I want something like this
def actionArray = new ArrayList();
actionArray.add("Added");
actionArray.add("Removed");
actionArray.add("Disabled");
actionArray.each{ action ->
action(**this is a variable**){
Revision(userCreationNumber)
Date(userCreationDate )
Author(userCreationAuthor)
}
}
which is same as:
Added{
Revision(userCreationNumber)
Date(userCreationDate )
Author(userCreationAuthor)
}
Removed{
Revision(userCreationNumber)
Date(userCreationDate )
Author(userCreationAuthor)
}
Disabled{
Revision(userCreationNumber)
Date(userCreationDate )
Author(userCreationAuthor)
}
this creates XML like this
<Added>
<Revision>12530</Revision>
<Date>02/02/2020</Date>
<Author>admin</Author>
</Added>
<Removed>
<Revision>12530</Revision>
<Date>02/02/2020</Date>
<Author>admin</Author>
</Removed>
<Disabled>
<Revision>12530</Revision>
<Date>02/02/2020</Date>
<Author>admin</Author>
</Disabled>
You can use GString interpolation:
import groovy.xml.*
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
def userCreationNumber = "12530"
def userCreationDate = "02/02/2020"
def userCreationAuthor = "admin"
def actionArray = [ "Added", "Removed", "Disabled" ]
xml.records() {
actionArray.each{ action ->
"$action"{
Revision( userCreationNumber )
Date( userCreationDate )
Author( userCreationAuthor )
}
}
}
writer
outputs
<records>
<Added>
<Revision>12530</Revision>
<Date>02/02/2020</Date>
<Author>admin</Author>
</Added>
<Removed>
<Revision>12530</Revision>
<Date>02/02/2020</Date>
<Author>admin</Author>
</Removed>
<Disabled>
<Revision>12530</Revision>
<Date>02/02/2020</Date>
<Author>admin</Author>
</Disabled>
</records>
Note also, that you need a root element.
I am using the Groovy MarkupBuilder to create some XML.
In my scenario I get an xml string which is essentially the body of the xml document and then I want to surround it with some other stuff.
Something like this....
def xmltext = '''<node><name short="yes">tim</name><fun>maybe</fun></node>'''
def body = new XmlSlurper(false,false).parseText( xmltext )
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
xml.mkp.xmlDeclaration version: '1.0', encoding: 'UTF-8'
xml.'cre:InputParamters'('xmlns:cre': 'http://xmlns.oracle.com/apps/ar/soaprovider/plsql/ar_invoice_api_pub/create_single_invoice/') {
xml.'cre:P_P_TRX_HEADER_TBL' {
xml.'cre:P_TRX_HEADER_TBL_ITEM' {
map 'cre:TRX_HEADER_ID', '',xml
map 'cre:TRX_DATE', requestPayload?.invoiceDate, xml
map 'cre:TRX_CURRENCY', requestPayload?.currencyCode, xml
map 'cre:TRX_CLASS', 'INV', xml
map 'cre:CUST_TRX_TYPE_ID', '1034', xml
map 'cre:BILL_TO_CUSTOMER_ID', '147055', xml
}
}
<<APPEND ELEMENTS FROM XML STRING HERE>>
}
private map (Object field, Object value, MarkupBuilder xml) {
if (value) {
xml."$field"(value)
}
}
return writer.toString()
Could someone help me with the bit 'APPEND ELEMENTS FROM XML STRING HERE' and how to get that the work for me?
thanks
Here is the changed script:
Note that you have used some variable to get the values. To demonstrate I have used fixed values below which you may be able to replace it.
import groovy.xml.*
def xmltext = '''<node><name short="yes">tim</name><fun>maybe</fun></node>'''
def builder = new StreamingMarkupBuilder()
builder.encoding = 'UTF-8'
def xml = builder.bind {
mkp.xmlDeclaration()
namespaces << [cre:'http://xmlns.oracle.com/apps/ar/soaprovider/plsql/ar_invoice_api_pub/create_single_invoice/']
cre.InputParamters{
cre.P_P_TRX_HEADER_TBL {
cre.P_TRX_HEADER_TBL_ITEM {
cre.TRX_HEADER_ID ('')
cre.TRX_DATE ('2017-02-17')
cre.TRX_CURRENCY( 'USD')
cre.TRX_CLASS('INV')
cre.CUST_TRX_TYPE_ID( '1034')
cre.BILL_TO_CUSTOMER_ID( '147055')
}
}
mkp.yieldUnescaped xmltext
}
}
println XmlUtil.serialize(xml)
You may try it quickly online Demo
Output
//Unable to add replaced nodes back to xml using xml slurper. Throws stackoverflow exception. Now idea how to do it
def xml = """<container>
<listofthings>
<thing id="100" name="foo"/>
</listofthings>
</container>"""
def root = new XmlSlurper().parseText(xml)
def fun = new ArrayList(root.listofthings.collect{it})
root.listofthings.thing.each {
it.replaceNode {}
}
root.listofthings.appendNode ( { thing(id:102, name:'baz') })
fun.each {
root.listofthings.appendNode it
}
def outputBuilder = new groovy.xml.StreamingMarkupBuilder()
String result = outputBuilder.bind { mkp.yield root }
print result
You call:
def fun = new ArrayList(root.listofthings.collect{it})
Which sets fun to be the node <listofthings> (and btw could be shortened to: def fun = root.listofthings)
Then on the line:
fun.each {
root.listofthings.appendNode it
}
You append this node to the node <listofthings>. This means your tree will be never ending (as you are attaching a node to itself), and hence the StackOverflowException
To get the code to run, you can change it to:
import groovy.xml.StreamingMarkupBuilder
def xml = """<container>
| <listofthings>
| <thing id="100" name="foo"/>
| </listofthings>
|</container>""".stripMargin()
def root = new XmlSlurper().parseText(xml)
root.listofthings.thing*.replaceNode {}
root.listofthings.appendNode {
thing( id:102, name:'baz' )
}
def outputBuilder = new StreamingMarkupBuilder()
String result = outputBuilder.bind { mkp.yield root }
print result
ie: get rid of the recursive node addition.
However, I'm not sure what you were trying to do with the recursive addition, so this probably doesn't do what you wanted to do... Can you explain more what result you wanted to see?
Edit
I managed to get XmlParser to do what I think you were trying to do?
def xml = """<container>
| <listofthings>
| <thing id="100" name="foo"/>
| </listofthings>
|</container>""".stripMargin()
def root = new XmlParser().parseText(xml)
def listofthings = root.find { it.name() == 'listofthings' }
def nodes = listofthings.findAll { it.name() == 'thing' }
listofthings.remove nodes
listofthings.appendNode( 'thing', [ id:102, name:'baz' ] )
nodes.each {
listofthings.appendNode( it.name(), it.attributes(), it.value() )
}
def writer = new StringWriter()
new XmlNodePrinter(new PrintWriter(writer)).print(root)
def result = writer.toString()
print result
That prints:
<container>
<listofthings>
<thing id="102" name="baz"/>
<thing id="100" name="foo"/>
</listofthings>
</container>
I need to add # attribute to the root element of XML fragment in Groovy. I want to use XmlSlurper. How to do it? Adding elements is easy.
Run this in the Groovy console to verify that it works
import groovy.xml.StreamingMarkupBuilder
// the original XML
def input = "<foo><bar></bar></foo>"
// add attributeName="attributeValue" to the root
def root = new XmlSlurper().parseText(input)
root.#attributeName = 'attributeValue'
// get the modified XML and check that it worked
def outputBuilder = new StreamingMarkupBuilder()
String updatedXml = outputBuilder.bind{ mkp.yield root }
assert "<foo attributeName='attributeValue'><bar></bar></foo>" == updatedXml
adding an attribute is the same as reading it:
import groovy.xml.StreamingMarkupBuilder
def input = '''
<thing>
<more>
</more>
</thing>'''
def root = new XmlSlurper().parseText(input)
root.#stuff = 'new'
def outputBuilder = new StreamingMarkupBuilder()
String result = outputBuilder.bind{ mkp.yield root }
println result
will give you:
<thing stuff='new'><more></more></thing>
I've been trying to do some xml modifications with groovy's XML Slurper.
Basically, i'm going through the xml and looking for tags or attributes that have ? as the value and then replacing it with some value.
I've got it working for xml that doesn't have namespaces but once I include them things get wonky. For example, this:
String foo = "<xs:test xmlns:xs="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:foo="http://myschema/xmlschema" name='?'>
<foo:tag1>?</foo:tag1>
<foo:tag2>?</foo:tag2>
</xs:test>";
produces:
<Envelope/>
Here's the groovy code I'm using. This does appear to work when I am not using a namespace:
public def populateRequest(xmlString, params) {
def slurper = new XmlSlurper().parseText(xmlString)
//replace all tags with ?
def tagsToReplace = slurper.depthFirst().findAll{ foundTag ->
foundTag.text() == "?"
}.each { foundTag ->
foundTag.text = {webServiceOperation.parameters[foundTag.name()]}
foundTag.replaceNode{
"${foundTag.name()}"(webServiceOperation.parameters[foundTag.name()])
}
}
//replace all attributes with ?
def attributesToReplace = slurper.list().each{
it.attributes().each{ attributes ->
if(attributes.value == '?')
{
attributes.value = webServiceOperation.parameters[attributes.key]
}
}
}
new StreamingMarkupBuilder().bind { mkp.yield slurper }.toString()
}
from groovy documentation
def wsdl = '''
<definitions name="AgencyManagementService"
xmlns:ns1="http://www.example.org/NS1"
xmlns:ns2="http://www.example.org/NS2">
<ns1:message name="SomeRequest">
<ns1:part name="parameters" element="SomeReq" />
</ns1:message>
<ns2:message name="SomeRequest">
<ns2:part name="parameters" element="SomeReq" />
</ns2:message>
</definitions>
'''
def xml = new XmlSlurper().parseText(wsdl).declareNamespace(ns1: 'http://www.example.org/NS1', ns2: 'http://www.example.org/NS2')
println xml.'ns1:message'.'ns1:part'.size()
println xml.'ns2:message'.'ns2:part'.size()