Groovy: Accessing Closure Object's elements - groovy

I am new to Groovy, and was wondering:
If I define a object like this:
def buildParentXML(){
def parentXMLElement = {
ParentElement {
CreationDate(new Date())
out << buildChildXML()
ChildElementFK(buildChildXML().childElement.ChildPK) //Something like this
}
}
}
def buildChildXML() {
def childElement {
ChildPK("12345679")
Operator("Don't Know")
}
}
How would I access the value of Element1 or Element2?
I tried
println obj.RootElement.Element1
println obj[RootElement].[Element1]
println obj['RootElement'].['Element1']
Simple Example
<SavePolicy>
<Segment>
<IssueState>AK</IssueState>
<OptionCode>ADD</OptionCode>
<SegmentStatus>Aive</SegmentStatus>
<ApplicationReceivedDate>09/17/2013</ApplicationReceivedDate>
<ApplicationSignedDate>09/17/2013</ApplicationSignedDate>
<CreationDate>09/17/2013</CreationDate>
<EffeiveDate>09/17/2013</EffeiveDate>
<IssueDate>09/17/2013</IssueDate>
<TerminationDate>09/17/2013</TerminationDate>
<RateSeriesDate>09/17/2013</RateSeriesDate>
</Segment>
<Life>
<FaceAmount>250.00</FaceAmount>
</Life>
Will Be converted into
<?xml version="1.0" encoding="UTF-8"?>
<SEGRequestVO>
<Service>Policy</Service>
<Operation>submit</Operation>
<Operator>N/A</Operator>
<IgnoreEditWarningsNF/>
<RequestParameters>
<SubmissionType>SaveIt</SubmissionType>
<ContraNumber/>
<SegmentVO>
<IssueState>AK</IssueState>
<OptionCode>DD</OptionCode>
<SegmentStatus>Aive</SegmentStatus>
<ApplicationReceivedDate>09/17/2013</ApplicationReceivedDate>
<ApplicationSignedDate>09/17/2013</ApplicationSignedDate>
<CreationDate>09/17/2013</CreationDate>
<EffeiveDate>09/17/2013</EffeiveDate>
<IssueDate>09/17/2013</IssueDate>
<TerminationDate>09/17/2013</TerminationDate>
<RateSeriesDate>09/17/2013</RateSeriesDate>
<ContraNumber/>
<ProduStruureFK>01</ProduStruureFK>
<LifeVO>
<FaceAmount>250.00</FaceAmount>
<LifePK>-123464646</LifePK>
<SegmentFK/>
</LifeVO></SegmentVO>
</RequestParameters>
</SEGRequestVO>

Right, I took a wild guess...is this what you mean?
import groovy.xml.*
def buildChildXML = {
ChildPK("12345679")
Operator("Don't Know")
return "12345679"
}
def buildParentXML = {
ParentElement {
CreationDate(new Date())
def pk = buildChildXML()
ChildElementFK( pk )
}
}
println XmlUtil.serialize( new StreamingMarkupBuilder().bind { it ->
buildParentXML.delegate = it
buildChildXML.delegate = it
buildParentXML()
} )
That prints:
<?xml version="1.0" encoding="UTF-8"?><ParentElement>
<CreationDate>Mon Sep 16 17:02:42 BST 2013</CreationDate>
<ChildPK>12345679</ChildPK>
<Operator>Don't Know</Operator>
<ChildElementFK>12345679</ChildElementFK>
</ParentElement>

Related

passing in args to a Closure for a StreamingMarkupBuilder

Groovy 2.4, Spring 5.3.13
Not having much luck using StreamingMarkupBuilder to create some XML, serialize it and print it
public void createMsgToStreamOut( String strCreatedAt, String strEntity, String strIdNum, String strEvent) {
def streamBuilder = new StreamingMarkupBuilder();
streamBuilder.encoding = "UTF-8"
def xml = streamBuilder.bind{ strCreatedAt, strEntity, strIdNum, strEvent ->
>> some magic goes here
}
def xmlStr = XmlUtil.serialize( xml)
println xmlStr;
}
createMsgToStreamOut( "2022-09-10T12:13:14.567", "Matter", "907856", "create");
should give
<?xml version="1.0" encoding="UTF-8"?>
<message>
<timestamp>2022-09-10T12:13:14.567</timestamp>
<entity>Matter</entity>
<number>907856</number>
<event>create</event>
</message>
next step is to stream the output to a Kafka producer.
The magic you're looking for looks like that, I suppose:
def xml = streamBuilder.bind {
message {
timestamp(strCreatedAt)
entity(strEntity)
number(strIdNum)
event(strEvent)
}
}
Here is the fully working script:
import groovy.xml.*
createMsgToStreamOut( "2022-09-10T12:13:14.567", "Matter", "907856", "create");
void createMsgToStreamOut(String strCreatedAt, String strEntity, String strIdNum, String strEvent) {
def streamBuilder = new StreamingMarkupBuilder();
streamBuilder.encoding = "UTF-8"
def xml = streamBuilder.bind {
message {
timestamp(strCreatedAt)
entity(strEntity)
number(strIdNum)
event(strEvent)
}
}
def xmlStr = XmlUtil.serialize( xml)
println xmlStr;
}
Let me know if it helps.

how to create Gsp tag by Markupbuilder?

I want to create a gsp file like this:
but I fail to find how to write the code by markupbuilder.
my code like this:
MarkupBuilder mb = new groovy.xml.MarkupBuilder(strXml);
def builderA = new StreamingMarkupBuilder()
def gsp = builderA.bind{
html{
g.uploadForm(action:"saveDataItem"){
table{
f.with{
tr{
td{
"Test"
}
}
}
}
}
}
}
println XmlUtil.serialize(gsp)
It dos not work.
import groovy.xml.*
def mb = new StreamingMarkupBuilder()
def gsp = mb.bind {
html{
"g:uploadForm"(action:"saveDataItem"){
table{
tr{
td("Test")
}
}
}
}
}
println gsp.toString()

XML combine documents

I am working on Boomi interface and I need to combine individual xml documents in to single output documents . The standard combine document step is not working properly.
All xml documents are of same structure .
First Document
<?xml version='1.0' encoding='UTF-8'?>
<EMPLEADOS>
<EMPLEADO TIPO="A" NUMERO="123">
<PROCESO PERIODO="201603" TT="MN" PAC="9999" />
<SECCION ID="ETACIV">
<CAMPO ID="ETA_ETCNOM" SEC=" " FECHA=" ">abc</CAMPO>
</SECCION>
</EMPLEADO>
</EMPLEADOS>
Second document
<?xml version='1.0' encoding='UTF-8'?>
<EMPLEADOS>
<EMPLEADO TIPO="A" NUMERO="123">
<PROCESO PERIODO="201603" TT="MN" PAC="9999" />
<SECCION ID="SADMIN ">
<CAMPO ID="SAD_SADESO" SEC=" " FECHA="01/03/2015">01/03/2015</CAMPO>
</SECCION>
</EMPLEADO>
</EMPLEADOS>
Third document
<?xml version='1.0' encoding='UTF-8'?>
<EMPLEADOS>
<EMPLEADO TIPO="A" NUMERO="123">
<PROCESO PERIODO="201603" TT="MN" PAC="9999" />
<SECCION ID="SADMIN ">
<CAMPO ID="SAD_SADESO" SEC=" " FECHA="01/06/2015">01/06/2015</CAMPO>
</SECCION>
</EMPLEADO>
</EMPLEADOS>
Expected output
<?xml version='1.0' encoding='UTF-8'?>
<EMPLEADOS>
<EMPLEADO TIPO="A" NUMERO="123">
<PROCESO PERIODO="201603" TT="MN" PAC="9999" />
<SECCION ID="ETACIV">
<CAMPO ID="ETA_ETCNOM" SEC=" " FECHA=" ">abc</CAMPO>
</SECCION>
<SECCION ID="SADMIN ">
<CAMPO ID="SAD_SADESO" SEC=" " FECHA="01/03/2015">01/03/2015</CAMPO>
<CAMPO ID="SAD_SADESO" SEC=" " FECHA="01/06/2015">01/06/2015</CAMPO>
</SECCION>
</EMPLEADO>
</EMPLEADOS>
The merging on elements are the same as attributes ? Technically , I need all the documents to be merged on ID attribute of CAMPO .
Any help greatly appreciated .
Thanks
Nag
I tried the below code ; getting Premature end of file. error.
import java.util.Properties;
import java.io.InputStream;
import org.jdom.input.SAXBuilder;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.xpath.XPath;
import org.jdom.output.XMLOutputter;
import groovy.util.slurpersupport.GPathResult;
import groovy.xml.StreamingMarkupBuilder;
for( int i = 0; i < dataContext.getDataCount(); i++ ) {
InputStream is = dataContext.getStream(i);
Properties props = dataContext.getProperties(i);
def xs = new XmlSlurper()
def employee = xs.parse(is);
String Encod = "UTF-8" ;
HashMap<String, GPathResult> CampoMap = new HashMap<String, GPathResult>()
employee.EMPLEADOS.EMPLEADO.PROCESO.SECCION.CAMPO.each {
CampoMap["${it.#ID}"] = it
}
new StreamingMarkupBuilder().bind {
mkp.xmlDeclaration(["version":"1.0", "encoding":"UTF-8"]);
EMPLEADOS {
EMPLEADO.PROCESO.SECCION.each {
if (CampoMap["${it.#ID}"] != null) {
it.appendNode(CampoMap["${it.#id}"].sites)
}
out << it
}
}
} .writeTo(is.newWriter(Encod))
}
dataContext.storeStream(is, props);
The new code is
import groovy.util.XmlParser
import groovy.xml.MarkupBuilder
def parser = new XmlParser()
def writer = new StringWriter()
def builder = new MarkupBuilder(writer)
for( int i = 0; i < dataContext.getDataCount(); i++ ) {
InputStream is = dataContext.getStream(i);
Properties props = dataContext.getProperties(i);
def mergedDocument = (0..<dataContext.dataCount)
.collect { XmlParser.parse(dataContext.getStream(it)) }
.inject { nodeA, nodeB -> merge(nodeA, nodeB) }
builder.mkp.xmlDeclaration(version:'1.0', encoding:'UTF-8')
builder.EMPLEADOS {
doc1.EMPLEADO.each { empleado ->
EMPLEADO(empleado.attributes()) {
empleado.PROCESO.each { proceso ->
PROCESO(proceso.attributes())
}
empleado.SECCION.each { seccion ->
SECCION(seccion.attributes()) {
seccion.CAMPO.each { campo ->
CAMPO(campo.attributes(), campo.value().head())
}
}
}
}
}
}
is = mergedDocument ;
}
/*
* Category to simplify XML node comparisons.
* Basically, two Nodes are equal if their attributes are the same.
*/
// class NodeCategory {
// static boolean equals(Node me, Node other) {
// me.attributes() == other.attributes()
// }
// static boolean isCase(List<Node> nodes, Node other) {
// nodes.find { it == other } != null
// }
//}
/*
* Merges document b into document a.
* WARNING: This method is destructive; it modifies document a
* #Returns a, for convenience
*/
def merge(a, b) {
// use(NodeCategory) {
b.EMPLEADO.each { empleado ->
def existingEmpleado = a.EMPLEADO.find {
it == empleado
}
if(existingEmpleado) {
// Empleado already exists, must merge differences.
// Add any missing PROCESO nodes.
empleado.PROCESO
.findAll { !(it in existingEmpleado.PROCESO) }
.with {
delegate.each { existingEmpleado.append(it) }
}
// Add any missing SECCION nodes.
empleado.SECCION
.findAll { !(it in existingEmpleado.SECCION) }
.with {
delegate.each { existingEmpleado.append(it) }
}
// Add any missing CAMPO nodes.
empleado.SECCION.each { seccion ->
existingEmpleado.SECCION
.find { it == seccion }
.with {
seccion.CAMPO
.findAll { !(it in delegate.CAMPO) }
.each { delegate.append(it) }
}
}
} else {
// Empleado does not exist, go ahead and add it as-is.
a.append(empleado)
}
}
// }
return a
}
First, I should mention that a generic method for combining XML documents is impossible because the merging process is contextual. How XML nodes are merged is dependent on what the nodes mean. A computer is incapable of figuring out the meaning on your data, so you as the programmer have to provide the instructions. Having said that, here's how to merge YOUR XML documents.
import groovy.util.XmlParser
import groovy.xml.MarkupBuilder
def parser = new XmlParser()
def writer = new StringWriter()
def builder = new MarkupBuilder(writer)
def doc1 = parser.parseText('''<?xml version='1.0' encoding='UTF-8'?>
<EMPLEADOS>
<EMPLEADO TIPO="A" NUMERO="123">
<PROCESO PERIODO="201603" TT="MN" PAC="9999" />
<SECCION ID="ETACIV">
<CAMPO ID="ETA_ETCNOM" SEC=" " FECHA=" ">abc</CAMPO>
</SECCION>
</EMPLEADO>
</EMPLEADOS>''')
def doc2 = parser.parseText('''<?xml version='1.0' encoding='UTF-8'?>
<EMPLEADOS>
<EMPLEADO TIPO="A" NUMERO="123">
<PROCESO PERIODO="201603" TT="MN" PAC="9999" />
<SECCION ID="SADMIN ">
<CAMPO ID="SAD_SADESO" SEC=" " FECHA="01/03/2015">01/03/2015</CAMPO>
</SECCION>
</EMPLEADO>
</EMPLEADOS>''')
def doc3 = parser.parseText('''<?xml version='1.0' encoding='UTF-8'?>
<EMPLEADOS>
<EMPLEADO TIPO="A" NUMERO="123">
<PROCESO PERIODO="201603" TT="MN" PAC="9999" />
<SECCION ID="SADMIN ">
<CAMPO ID="SAD_SADESO" SEC=" " FECHA="01/06/2015">01/06/2015</CAMPO>
</SECCION>
</EMPLEADO>
</EMPLEADOS>''')
merge(doc1, doc2)
merge(doc1, doc3)
builder.mkp.xmlDeclaration(version:'1.0', encoding:'UTF-8')
builder.EMPLEADOS {
doc1.EMPLEADO.each { empleado ->
EMPLEADO(empleado.attributes()) {
empleado.PROCESO.each { proceso ->
PROCESO(proceso.attributes())
}
empleado.SECCION.each { seccion ->
SECCION(seccion.attributes()) {
seccion.CAMPO.each { campo ->
CAMPO(campo.attributes(), campo.value().head())
}
}
}
}
}
}
println writer
/*
* Category to simplify XML node comparisons.
* Basically, two Nodes are equal if their attributes are the same.
*/
class NodeCategory {
static boolean equals(Node me, Node other) {
me.attributes() == other.attributes()
}
static boolean isCase(List<Node> nodes, Node other) {
nodes.find { it == other } != null
}
}
/*
* Merges document b into document a.
* WARNING: This method is destructive; it modifies document a
* #Returns a, for convenience
*/
def merge(a, b) {
use(NodeCategory) {
b.EMPLEADO.each { empleado ->
def existingEmpleado = a.EMPLEADO.find {
it == empleado
}
if(existingEmpleado) {
// Empleado already exists, must merge differences.
// Add any missing PROCESO nodes.
empleado.PROCESO
.findAll { !(it in existingEmpleado.PROCESO) }
.with {
delegate.each { existingEmpleado.append(it) }
}
// Add any missing SECCION nodes.
empleado.SECCION
.findAll { !(it in existingEmpleado.SECCION) }
.with {
delegate.each { existingEmpleado.append(it) }
}
// Add any missing CAMPO nodes.
empleado.SECCION.each { seccion ->
existingEmpleado.SECCION
.find { it == seccion }
.with {
seccion.CAMPO
.findAll { !(it in delegate.CAMPO) }
.each { delegate.append(it) }
}
}
} else {
// Empleado does not exist, go ahead and add it as-is.
a.append(empleado)
}
}
}
return a
}
The process goes like this:
The merge(Node a, Node b) method traverses through the nodes, handling each case so that a ends up being the combination of both documents (node trees). It's based on figuring out whether a node in b is already in a. If not, the node is added as-is. Otherwise, merge the changes a accordingly. Yes, this method is butt ugly and was a real PITA to write. Please, for the sake of sound programming, refactor the beast.
Finally, a MarkupDocumentBuilder is used to process the final node tree and produce a serialized XML document.
You may notice there's a Groovy category involved. It's used to simplify the Node comparisons.
Addendum - Using input streams
You can invoke the same process using InputStreams as the source of XML documents. It would go something like this:
def parser = new XmlParser()
def mergedDocument = (0..<dataContext.dataCount)
.collect { parser.parse(dataContext.getStream(it) }
.inject { nodeA, nodeB -> merge(nodeA, nodeB) }
Then, you can process mergedDocument with the MarkupBuilder.

replace XmlSlurper tag with arbitrary XML

I am trying to replace specific XmlSlurper tags with arbitrary XML strings. The best way I have managed to come up with to do this is:
#!/usr/bin/env groovy
import groovy.xml.StreamingMarkupBuilder
def page=new XmlSlurper(new org.cyberneko.html.parsers.SAXParser()).parseText("""
<html>
<head></head>
<body>
<one attr1='val1'>asdf</one>
<two />
<replacemewithxml />
</body>
</html>
""".trim())
import groovy.xml.XmlUtil
def closure
closure={ bind,node->
if (node.name()=="REPLACEMEWITHXML") {
bind.mkp.yieldUnescaped "<replacementxml>sometext</replacementxml>"
} else {
bind."${node.name()}"(node.attributes()) {
mkp.yield node.text()
node.children().each { child->
closure(bind,child)
}
}
}
}
println XmlUtil.serialize(
new StreamingMarkupBuilder().bind { bind->
closure(bind,page)
}
)
However, the only problem is the text() element seems to capture all child text nodes, and thus I get:
<?xml version="1.0" encoding="UTF-8"?>
<HTML>asdf<HEAD/>
<BODY>asdf<ONE attr1="val1">asdf</ONE>
<TWO/>
<replacementxml>sometext</replacementxml>
</BODY>
</HTML>
Any ideas/help much appreciated.
Thank you!
Misha
p.s. Also, out of curiosity, if I change the above to the "Groovier" notation as follows, the groovy compiler thinks I am trying to access the ${node.name()} member of my test class. Is there a way to specify this is not the case while still not passing the actual builder object? Thank you! :)
def closure
closure={ node->
if (node.name()=="REPLACEMEWITHXML") {
mkp.yieldUnescaped "<replacementxml>sometext</replacementxml>"
} else {
"${node.name()}"(node.attributes()) {
mkp.yield node.text()
node.children().each { child->
closure(child)
}
}
}
}
println XmlUtil.serialize(
new StreamingMarkupBuilder().bind {
closure(page)
}
)
Ok here is what I came up with:
#!/usr/bin/env groovy
import groovy.xml.StreamingMarkupBuilder
import groovy.xml.XmlUtil
def printSlurper={page->
println XmlUtil.serialize(
new StreamingMarkupBuilder().bind { bind->
mkp.yield page
}
)
}
def saxParser=new org.cyberneko.html.parsers.SAXParser()
saxParser.setFeature('http://xml.org/sax/features/namespaces',false)
saxParser.setFeature("http://cyberneko.org/html/features/balance-tags/document-fragment",true)
def string="TEST"
def middleClosureHelper={ builder->
builder."${string}" {
mkp.yieldUnescaped "<inner>XML</inner>"
}
}
def middleClosure={
MiddleClosure {
middleClosureHelper(delegate)
}
}
def original=new XmlSlurper(saxParser).parseText("""
<original>
<middle>
</middle>
</original>
""")
original.depthFirst().find { it.name()=='MIDDLE' }.replaceNode { node->
mkp.yield middleClosure
}
printSlurper(original)
assert original.depthFirst().find { it.name()=='INNER' } == null
def modified=new XmlSlurper(saxParser).parseText(new StreamingMarkupBuilder().bind {mkp.yield original}.toString())
assert modified.depthFirst().find { it.name()=='INNER' } != null
You have to reload the slurper, but it works!
Misha

groovy multithreading

I'm newbie to groovy/grails.
How to implement thread for this code . Had 2500 urls and this was taking hours of time for checking each url.
so i decided to implement multi-thread for this :
Here is my sample code :
def urls = [
"http://www.wordpress.com",
"http://67.192.103.225/QRA.Public/" ,
"http://www.subaru.com",
"http://baldwinfilter.com/products/start.html"
]
def up = urls.collect { ur ->
try {
def url = new URL(ur)
def connection = url.openConnection()
if (connection.responseCode == 200) {
return true
} else {
return false
}
} catch (Exception e) {
return false
}
}
For this code i need to implement multi-threading .
Could any one please suggest me the code.
thanks in advance,
sri.
I would take a look at the Groovy Parallel Systems library. In particular I think that the Parallel collections section would be useful.
Looking at the docs, I believe that collectParallel is a direct drop-in replacement for collect (bearing in mind the obvious caveats about side-effects). The following works fine for me:
def urls = [
"http://www.wordpress.com",
"http://www.subaru.com",
"http://baldwinfilter.com/products/start.html"
]
Parallelizer.doParallel {
def up = urls.collectParallel { ur ->
try {
def url = new URL(ur)
def connection = url.openConnection()
if (connection.responseCode == 200) {
return true
} else {
return false
}
} catch (Exception e) {
return false
}
}
println up
}
See the Groovy docs for an example how to use an ExecutorService to do what you want.
You can use this to check the URL in a separate thread.
class URLReader implements Runnable
{
def valid
def url
URLReader( url ) {
this.url = url
}
void run() {
try {
def connection = url.toURL().openConnection()
valid = ( connection.responseCode == 200 ) as Boolean
} catch ( Exception e ) {
println e.message
valid = Boolean.FALSE
}
}
}
def reader = new URLReader( "http://www.google.com" )
new Thread( reader ).start()
while ( reader.valid == null )
{
Thread.sleep( 500 )
}
println "valid: ${reader.valid}"
Notes: The valid attribute will be either null, Boolean.TRUE or Boolean.FALSE. You'll need to wait for a while to give all the threads a chance to open the connection. Depending on the number of URLs you're checking you will eventually hit a limit of the number of threads / connections you can realistically handle, so should check URLs in batches of the appropriate size.
I think this way is very simple to achieve.
import java.util.concurrent.*
//Thread number
THREADS = 100
pool = Executors.newFixedThreadPool(THREADS)
defer = { c -> pool.submit(c as Callable) }
def urls = [
"http://www.wordpress.com",
"http://www.subaru.com",
]
def getUrl = { url ->
def connection = url.openConnection()
if (connection.responseCode == 200) {
return true
} else {
return false
}
}
def up = urls.collect { ur ->
try {
def url = new URL(ur)
defer{ getUrl(url) }.get()
} catch (Exception e) {
return false
}
}
println up
pool.shutdown()
This is how I implemented:
class ValidateLinks extends Thread{
def valid
def url
ValidateLinks( url ) {
this.url = url
}
void run() {
try {
def connection = url.toURL().openConnection()
connection.setConnectTimeout(5000)
valid = ( connection.responseCode == 200 ) as Boolean
} catch ( Exception e ) {
println url + "-" + e.message
valid = Boolean.FALSE
}
}
}
def threads = [];
urls.each { ur ->
def reader = new ValidateLinks(ur.site_url)
reader.start()
threads.add(reader);
}
while (threads.size() > 0) {
for(int i =0; i < threads.size();i++) {
def tr = threads.get(i);
if (!tr.isAlive()) {
println "URL : " + tr.url + "Valid " + tr.valid
threads.remove(i);
i--;
}
}
}

Resources