I want to modify the incoming message (As shown in the Modified XML) output.
Incoming XML
<xml>
<Body>
<Request>
<Container>
<name>test</name>
<Numbers>
<sn>//base64encodedstring//</sn>
<sn>//base64encodedstring//</sn>
<sn>//base64encodedstring//</sn>
</Numbers>
</Container>
</Request>
</Body>
</xml>
Modified XML
<xml>
<Body>
<Request>
<Container>
<name>test</name>
<Numbers>
<sn>//Decodedstring//</sn>
<sn>//Decodedstring//</sn>
<sn>//Decodedstring//</sn>
</Numbers>
</Container>
</Request>
</Body>
</xml>
As per the answer received: I can create an array of ListOfResults.
def listOfResults = new XmlSlurper()
.parseText(xml)
.Body.Request.Container.Numbers.sn
.collect { new String(it.text().decodeBase64()) }
I can do the following
def data = "<xml><Body><Request><Container><name>test</name><Numbers>"
for (i= 0; i <listOfResults.size(); i++)
{
data = data +"<sn>" +listOfResults[i] + "</sn>";
}
data = data + "<Numbers></Container></Request></Body></xml>";
Modified data
<xml><Body><Request><Container><name>test</name>
<Numbers>
<sn>decoded string</sn>
<sn>decoded string</sn>
<sn>decoded string</sn>
</Numbers> </Container></Request></Body></xml>
Is this the fastest way to do this operation? Is there any other better way?
You should be able to do (assuming your XML is in a string variable called xml):
def listOfResults = new XmlSlurper()
.parseText(xml)
.Body.Request.Container.Numbers.sn
.collect { new String(it.text().decodeBase64()) }
Related
I'm trying to figure out how to add attributes to an array element
I get an error Error: Invalid character in name when trying to build the following XML from an object.
<?xml version="1.0" encoding="UTF-8"?>
<Requests xmlns="http://example.com">
<Request>
</Request>
<Request>
</Request>
</Requests>
Here is my object
let myObject = {
Requests:[
{$:{xmlns:"http://example.com"}},
{Request:{}},
{Request:{}}
]
}
let builder = new xml2js.Builder();
let xml = builder.buildObject(myObject);
console.log(xml)
I've also tried wrapping the name in quotes
{"$":{"xmlns":"http://example.com"}},
Stripping out the attribute declaration altogether produces the desired XML but obviously leaves out the needed attribute
<?xml version="1.0" encoding="UTF-8"?>
<Requests>
<Request>
</Request>
<Request>
</Request>
</Requests>
I suppose you should try this:
let myObject = {
Requests:{
$:{xmlns:"http://example.com"},
Request:[{}, {}]
}
I've been trying to get data from a specifix XML file into a SQLite3 database using ElementTree. The XML has the following structure:
<?xml version="1.0" encoding="UTF-8" ?>
<chat xmlns="http://test.org/net/1.3">
<event sender="Frank" time="2016-02-03T22:58:19+01:00" />
<message sender="Karen" time="2016-02-03T22:58:19+01:00">
<div>
<span>Hello Frank</span>
</div>
</message>
<message sender="Frank" time="2016-02-03T22:58:39+01:00">
<div>
<span>Hi there Karen</span>
</div>
<div>
<span>I'm back from New York</span>
</div>
</message>
<message sender="Karen" time="2016-02-03T22:58:56+01:00">
<div>
<span>How are you doing?</span>
<span>Everything OK?</span>
</div>
</message>
</chat>
For each message or event I create a record in the database with the following columns: sender, time, message. The following code is used to process the XML:
import xml.etree.ElementTree as ET
import sqlite3 as lite
con = None
con = lite.connect('dbtest.db')
cur = con.cursor()
xmlfile = 'test.xml'
tree = ET.parse(xmlfile)
root = tree.getroot()
for m in root.findall('./*'):
msg = m.find('.')
msg.tag = 'div'
sender = str(m.get('sender'))
time = m.get('time')
message = str(ET.tostring(msg))
print('Sender: ' + sender)
print('Time: ' + time)
print('HTML: ' + message)
print()
query = ("INSERT INTO chat('time', 'sender', 'message') VALUES(?,?,?)")
values = (time, sender, message)
with con:
cur = con.cursor()
cur.execute(query, values)
if con:
con.close()
This results in several problems.
First of all I don't get the result I want. The "message" should be what's inside the message tag, not including the enclosing message tag, now renamed to div. This is what I should get:
<div>
<span>Hi there Karen</span>
</div>
<div>
<span>I'm back from New York</span>
</div>
Or maybe this:
<div><span>Hi there Karen</span></div><div><span>I'm back from New York</span></div>
Instead I get this:
b'<div xmlns:ns0="http://test.org/net/1.3" sender="Karen" time="2016-02-03T22:58:19+01:00">\n\t\t<ns0:div>\n\t\t\t<ns0:span>Hello Frank</ns0:span>\n\t\t</ns0:div>\n\t</div>\n\t'
So I'm trying to "fix" this, by removing the b' etc, but I hope there is a better method. And removing that starting b' works, but I can't get rid of the \t and \n somehow, using string replace.
Question
How can I get proper XML data into the table without all those escape characters?
So, ElementTree.tostring returns a byte object by default, not a string. So when you print it out, you're seeing that byte object's serialized form, when what you expected and want is a string. I didn't look into it but I suspect that the sqlite binding will insert byte objects as BLOB and strings as TEXT values into the database and that byte by byte they end up being identical.
Anyways, to print out the xml in a more human readable form like you want:
import xml.etree.ElementTree as ET
rawxml='''<?xml version="1.0" encoding="UTF-8" ?>
<chat xmlns="http://test.org/net/1.3">
<event sender="Frank" time="2016-02-03T22:58:19+01:00" />
<message sender="Karen" time="2016-02-03T22:58:19+01:00">
<div>
<span>Hello Frank</span>
</div>
</message>
<message sender="Frank" time="2016-02-03T22:58:39+01:00">
<div>
<span>Hi there Karen</span>
</div>
<div>
<span>I'm back from New York</span>
</div>
</message>
<message sender="Karen" time="2016-02-03T22:58:56+01:00">
<div>
<span>How are you doing?</span>
<span>Everything OK?</span>
</div>
</message>
</chat>'''
ns={'msg' : "http://test.org/net/1.3"}
xml = ET.fromstring(rawxml)
for msg in xml.findall("msg:message", ns):
print("Sender: " + msg.get("sender"))
print("Time: " + msg.get("time"))
body=""
for d in msg.findall("msg:div", ns):
body = body + ET.tostring(d, encoding="unicode")
print("Content: " + body)
Note the use of the encoding="unicode" argument to tostring(), which makes it return a string. Adding the XML namespace attributes is just how ElementTree works with them.
I have mule flow which stores the xml in session variable. I want this xml to be inserted in the xml which is generated in groovy.
My session variable looks like #[sessionVars.shippingdetails]
This session variable has <a><Subject1>science</Subject1><Subject2>Maths</Subject2></a>
When i use session variable in my xmlmarkup builder as like below. I am getting error as groovy.lang.GroovyRuntimeException: Namespace prefix: CDATA is not bound to a URI (javax.script.ScriptException). Message payload is of type: CaseInsensitiveHashMap (org.mule.api.transformer.TransformerMessagingException). Message payload is of type: CaseInsensitiveHashMap
import groovy.xml.XmlUtil
def builder = new groovy.xml.StreamingMarkupBuilder()
builder.encoding = "UTF-8"
// MAPPING
def person = {
// use mkp object which provides features like setting the namespace
mkp.xmlDeclaration()
mkp.declareNamespace("":"urn:abc:alos:BaseComponents")
//start with the XML root node closure
ItemRequest {
Requester{
subject(message.payload.subject)
}
Item{
Title(message.payload.name)
Description(message.payload.desc)
Category {
CategoryID(message.payload.cat_id)
}
ConditionID (message.payload.condition)
Mark (message.payload.Mark)
ShippingDetails [CDATA[sessionVars.shippingdetails]]
}
}
}
// WRITING
def writer = new StringWriter()
writer << builder.bind(person)
println writer.toString()
XmlUtil.serialize(builder.bind(person))
Hence my output xml should like below.
<?xml version="1.0" encoding="UTF-8"?>
<ItemRequest xmlns="urn:abc:alos:BaseComponents">
<Requester>
<subject>something</subject>
</Requester>
<Item>
<Title>Cooler Can Blue</Title>
<Description>This is the place for description.</Description>
<Category>
<CategoryID>562</CategoryID>
</Category>
<ConditionID>25</ConditionID>
<Mark>3</Mark>
<ShippingDetails>
<a>
<Subject1>science</Subject1>
<Subject2>Maths</Subject2>
</a>
</ShippingDetails>
</Item>
</ItemRequest>
Using Groovy 2.4.3, here is one way to get the output specified. (This does not address Mule):
import groovy.xml.*
def markupBuilder = new StreamingMarkupBuilder()
def xml = markupBuilder.bind { builder ->
mkp.declareNamespace( "": "urn:abc:alos:BaseComponents" )
ItemRequest {
Requester {
subject("something")
}
Item {
Title("Cooler Can Blue")
Description("This is the place for description.")
Category {
CategoryID("562")
}
ConditionID("25")
Mark("3")
ShippingDetails {
a {
Subject1("science")
Subject2("Maths")
}
}
}
}
}
def goal = """<?xml version="1.0" encoding="UTF-8"?><ItemRequest xmlns="urn:abc:alos:BaseComponents">
<Requester>
<subject>something</subject>
</Requester>
<Item>
<Title>Cooler Can Blue</Title>
<Description>This is the place for description.</Description>
<Category>
<CategoryID>562</CategoryID>
</Category>
<ConditionID>25</ConditionID>
<Mark>3</Mark>
<ShippingDetails>
<a>
<Subject1>science</Subject1>
<Subject2>Maths</Subject2>
</a>
</ShippingDetails>
</Item>
</ItemRequest>
"""
assert goal == XmlUtil.serialize(xml)
I want to create a xml file using SSJS on server. Is there a way to do so? Can anyone please give a sample code to create a xml file on server.
There are quite some ways. The seemingly easiest one is to create a string that looks like XML.
The next one would be the use of Java DOM classes. There is an article describing it.
Finally you can use SAX with a little helper class
Let us know how it goes.
Update: This would be my version of #Michael's code sample:
<?xml version="1.0" encoding="UTF-8"?>
<!-- XPage which is not rendered but returns data like XML, JSON, etc. -->
<!-- More: http://www.wissel.net/blog/d6plinks/shwl-7mgfbn -->
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" rendered="false">
<xp:this.beforeRenderResponse><![CDATA[#{javascript:try {
var out = facesContext.getOutputStream();
var exCon = facesContext.getExternalContext();
var response = exCon.getResponse(); // get the response context
// set content type, e.g. ...
response.setContentType("text/xml");
// set caching option
response.setHeader("Cache-Control", "no-cache");
// write XML output ...
var result = new biz.taoconsulting.xmltools.SimpleXMLDoc();
result.setOut(out);
result.openTag("result");
result.dateTag("created", new java.util.Date());
result.addSimpleTag("Author",#UserName);
result.openTag("FruitList");
result.addComment("Stephan really likes the fruits example");
var attributes = new java.util.HashMap();
attributes.add("name","Durian");
attributes.add("color","white");
attributes.add("taste","Don't ask");
result.addEmptyTag("fruit",attributes);
result.closeDocument();
// close the output
exCon.responseComplete();
out.close();
} catch (e) {
print(e.toString());
}}]]>
</xp:this.beforeRenderResponse>
</xp:view>
Note the differences here:
I use the beforeRenderResponse event
Access to outputStream instead of writer (stream is not accessible in the afterRenderResponse event)
set the response complete to stop the page from further output, so you can simply type comments on the page what it does
use of the helper class
What seems a little odd when you read the source of the helper class: why not use the output stream in the constructor, so you won't miss it? - I would today add a second constructor with that, but the parameterless constructor allow me to define that class as a managed bean if I fancy that.
to "render" XML in a String as #Stefan suggested I would use the XAgent approach:
<?xml version="1.0" encoding="UTF-8"?>
<!-- XPage which is not rendered but returns data like XML, JSON, etc. -->
<!-- More: http://www.wissel.net/blog/d6plinks/shwl-7mgfbn -->
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" rendered="false">
<xp:this.afterRenderResponse><![CDATA[#{javascript:try {
var writer = facesContext.getResponseWriter(), // get a writer object
response = facesContext.getExternalContext().getResponse(); // get the response context
// set content type, e.g. ...
response.setContentType("text/xml");
// set caching option
response.setHeader("Cache-Control", "no-cache");
// write XML output ...
writer.write(
'<?xml version="1.0"?>\n'
+ '<root>\n'
+ '<entity>Example Content</entity>\n'
+ '</root>\n'
);
// close the stream
writer.endDocument();
} catch (e) {
print(e.toString());
}}]]>
</xp:this.afterRenderResponse>
<xp:this.resources>
<xp:script src="/XBAN.jss" clientSide="false"></xp:script>
</xp:this.resources>
</xp:view>
Simply put his code into a newly created XPage and test it. Modify the lines in writer.write() to fit to your needs.
I get this extra value when I try to generate an html using groovy, here is my code and output below
code:
import groovy.xml.MarkupBuilder
println("let us try a HTML page..\n")
def mkp= new MarkupBuilder()
mkp.html{head{ title "bijoy's groovy"
body{
div{style:"color:red"}
{p "this is cool"}
}}}
and the output has grrovyTest$_run_closure1_closure3_closure4_closure5#4d1abd as extra.. how do I remove it?
<html>
<head>
<title>bijoy's groovy</title>
<body>
<div>grrovyTest$_run_closure1_closure3_closure4_closure5#4d1abd
<p>this is cool</p>
</div>
</body>
</head>
</html>
Attributes to a DOM element are mentioned in () with a map representation as shown below for <div>.
import groovy.xml.MarkupBuilder
println("let us try a HTML page..\n")
def writer = new StringWriter()
def mkp = new MarkupBuilder(writer)
mkp.html{
head{
title "bijoy's groovy"
}
body{
div(style:"color:red"){
p "this is cool"
}
}
}
println writer
Also note, I rectified head and body and added a writer. I suppose you do not want body inside html head. :)