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.
Related
I have JSON looking like:
{
"days": [
{
"mintemp": "21.8"
}
]
}
With Groovy, I parse it like this:
class WeatherRow {
String mintemp
}
def file = new File("data.json")
def slurper = new JsonSlurper().parse(file)
def days = slurper.days
def firstRow = days[0] as WeatherRow
println firstRow.mintemp
But actually, I would like to name my instance variable something like minTemp (or even something completely random, like numberOfPonies). Is there a way in Groovy to map a member of a map passed to a constructor to something else?
To clarify, I was looking for something along the lines of #XmlElement(name="mintemp"), but could not easily find it:
class WeatherRow {
#Element(name="mintemp")
String minTemp
}
Create a constructor that takes a map.
Runnable example:
import groovy.json.JsonSlurper
def testJsonStr = '''
{"days": [
{ "mintemp": "21.8" }
]}'''
class WeatherRow {
String minTemp
WeatherRow(map) {
println "Got called with constructor that takes a map: $map"
minTemp = map.mintemp
}
}
def slurper = new JsonSlurper().parseText(testJsonStr)
def days = slurper.days
def firstRow = days[0] as WeatherRow
println firstRow.minTemp
Result:
Got called with constructor that takes a map: [mintemp:21.8]
21.8
(of course you'd remove the println line, it's just there for the demo)
You can achieve this using annotation and simple custom annotation processor like this:
1. Create a Custom Annotation Class
#Retention(RetentionPolicy.RUNTIME)
#interface JsonDeserializer {
String[] names() default []
}
2. Annotate your instance fields with the custom annotation
class WeatherRow{
#JsonDeserializer(names = ["mintemp"])
String mintemp;
#JsonDeserializer(names = ["mintemp"])
String minTemp;
#JsonDeserializer(names = ["mintemp"])
String numberOfPonies;
}
3. Add custom json deserializer method using annotation processing:
static WeatherRow fromJson(def jsonObject){
WeatherRow weatherRow = new WeatherRow();
try{
weatherRow = new WeatherRow(jsonObject);
}catch(MissingPropertyException ex){
//swallow missing property exception.
}
WeatherRow.class.getDeclaredFields().each{
def jsonDeserializer = it.getDeclaredAnnotations()?.find{it.annotationType() == JsonDeserializer}
def fieldNames = [];
fieldNames << it.name;
if(jsonDeserializer){
fieldNames.addAll(jsonDeserializer.names());
fieldNames.each{i ->
if(jsonObject."$i")//TODO: if field type is not String type custom parsing here.
weatherRow."${it.name}" = jsonObject."$i";
}
}
};
return weatherRow;
}
Example:
def testJsonStr = '''
{
"days": [
{
"mintemp": "21.8"
}
]
}'''
def parsedWeatherRows = new JsonSlurper().parseText(testJsonStr);
assert WeatherRow.fromJson(parsedWeatherRows.days[0]).mintemp == "21.8"
assert WeatherRow.fromJson(parsedWeatherRows.days[0]).minTemp == "21.8"
assert WeatherRow.fromJson(parsedWeatherRows.days[0]).numberOfPonies == "21.8"
Check the full working code at groovyConsole.
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
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>
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 )
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()