I have the following XML file :
<?xml version="1.0" encoding="UTF-8"?>
<bpmn2:process id="process_1" isExecutable="true">
<bpmn2:subProcess id="SubProcess_1" name="Sub Process 1">
<bpmn2:task id="Task_4" name="Task 4">
</bpmn2:task>
<bpmn2:task id="Task_2" name="Task 2">
</bpmn2:task>
<bpmn2:startEvent id="StartEvent_2" name="">
</bpmn2:startEvent>
<bpmn2:endEvent id="EndEvent_2" name="">
</bpmn2:endEvent>
<bpmn2:task id="Task_3" name="Task 3">
</bpmn2:task>
</bpmn2:subProcess>
<bpmn2:subProcess id="SubProcess_2" name="Sub Process 2">
<bpmn2:startEvent id="StartEvent_3" name="">
</bpmn2:startEvent>
<bpmn2:endEvent id="EndEvent_3" name="">
</bpmn2:endEvent>
<bpmn2:task id="Task_5" name="Task 5">
</bpmn2:task>
</bpmn2:subProcess>
</bpmn2:process>
I want to generate the Json String for this xml.
I have already writen the code for generating the Json String if inside the <bpmn2:process> </bpmn2:process> tags there is only one <bpmn2:subProcess> node, but now I don't know how to do when I have more than one bpmn2:subProcess node.
My code so far is :
Node nodeSubProcess = getNode("bpmn2:subProcess");
jw = new JSONStringer();
jw.object(); //create a new object for bpmn2:subProcess
generateChildNodesDefinitions(nodeSubProcess);
jw.endObject(); // close the object for bpmn2:subProcess
System.out.println(jw.toString());
And inside the generateChildNodesDefinitions(nodeSubProcess) method I have the code how I want to generate the Json string for my xml file, when I have only one subProcess node:
public static void generateChildNodesDefinitions(Node node) throws JSONException
{
if (node != null && node.hasChildNodes())
{
jw.key("nodes").array();
NodeList childnodelist = node.getChildNodes();
for (int k = 0; k < childnodelist.getLength(); k++)
{
Node childn = childnodelist.item(k);
if (childn.hasAttributes())
{
ArrayList<String> list = (ArrayList<String>) jsonValues.get(childn.getNodeName()); //where jsonValues is e Map where I have defined some new values I want to generate for each node I have inside pbmn2:subProcess node
// get attributes for each childnode
NamedNodeMap nnmchildnodes = childn.getAttributes();
// for each node create a JsonObject
jw.object();
if (list != null && !list.isEmpty())
{
jw.key("stencil").value(list.get(0));
jw.key("category").value("NODE");
if (list.get(1) != null)
{
jw.key(list.get(1)).value(list.get(2));
}
}
jw.endObject();
}
}
jw.endArray();
}
}
Try the JSON in Java API. It does all of the hard work for you.
public String xmlToJSON(String xmlString){
try {
JSONObject xmlJSONObj = XML.toJSONObject(xmlString);
String jsonString = xmlJSONObj.toString(4);
}catch (JSONException je){
je.printStackTrace();
}
return jsonString;
}
You might be better off to use Jackson both for parsing the xml and for writing the json back. Especially if you plan to process your data in java. If you only want a conversion, Jackson might be overkill. If you want your conversion to work in both ways, Jackson might provide an elegant solution. Jackson is meant for json (de-)serialization and can be extended to be used with xml.
Parsing your xml into your data classes is as simple as:
ObjectMapper xmlMapper = new XmlMapper();
YourRootClass yourRootObject = xmlMapper.readValue(xml, YourRootClass.class);
Writing your json back is as simple as:
ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(fileOutput, yourRootObject);
You need to annotate your data classes in order for Jackson to work.
Jackson Annotations
Additional XML Annotations
Related
A real example of the XML data I have to parse through and how the file is configured. this is how the file is presented to me.
<?xml version="1.0"?>
<session>
<values>
<value id="FILE_CREATE_DATE">
<timestamp>2012-04-16T21:33:31Z</timestamp>
</value>
<value id="LAST_ACCESSED">
<timestamp>2012-09-17T17:15:23Z</timestamp>
</value>
<value id="VERSION_TIMESTAMP">
<timestamp>2012-04-16T21:33:31Z</timestamp>
</value>
</values>
</session>
I need to go into this file and retrieve the FILE_CREATE_DATE data.
My code so far:
File xmlFile = new File(XMLFileData[i].getPath());
FileInputStream myXMLStream = new FileInputStream(xmlFile);
XMLInputFactory XMLFactory = XMLInputFactory.newInstance();
XMLStreamReader XMLReader = XMLFactory.createXMLStreamReader(myXMLStream);
while(XMLReader.hasNext())
{
if (XMLReader.getEventType() == XMLStreamReader.START_ELEMENT)
{
String XMLTag = XMLReader.getLocalName();
if(XMLReader.hasText())
{
System.out.println(XMLReader.getText());
break;
}
}
XMLReader.next();
}
the 'getLocalName()' function returns 'Sessions' then 'value' then 'values' but never returns the actual name of the element. I need to test to see if I am at the right element then retrieve the data from that element...
I use Jsoup which is a library for parsing HTML. But it can be used for xml too. you would first have to load the XML file into a Document object then simply call
doc.getElementById("FILE_CREATE_DATE");
This will return an Element object that will have the timestamp as a child. Here's a link to the library: https://jsoup.org/
This is my first StackOverflow answer so let me know if it helps !
Your id is not an element - it's element attribute.
You should read attribute of your value node, see the javadoc for getAttributeValue method:
http://docs.oracle.com/javase/6/docs/api/javax/xml/stream/XMLStreamReader.html#getAttributeValue(java.lang.String,%20java.lang.String)
Returns the normalized attribute value of the attribute with the
namespace and localName If the namespaceURI is null the namespace is
not checked for equality
So it will be:
String XMLTag = XMLReader.getLocalName();
if(XMLTag.equals("value")) {
String idValue = XMLReader.getAttributeValue(null, "id");
//here idValue will be equal to FILE_CREATE_DATE, LAST_ACCESSED or VERSION_TIMESTAMP
}
try something like
if(XMLReader.getAttributeValue(0).equalIgnorecase("FILE_CREATE_DATE"))
getAttributeValue : Return value of the given index of the attribute. for
<value id="FILE_CREATE_DATE">
id is the first attribute. So XMLReader.getAttributeValue(0)
but before calling this you have to validate whether element has the first attribute. Because all the tags does not have at least 1 attribute.
in jsoup you can query like this
public static void main(String[] args) {
Document doc;
try {
doc = Jsoup.connect("http://www.dropbox.com/public/xml/yourfile.xml").userAgent("Mozilla").get();
//<value id="FILE_CREATE_DATE">
Elements links = doc.select("value[id=FILE_CREATE_DATE]");
for (Element link : links) {
if(link.attr("id").contains("FILE_CREATE_DATE"))//find the link with some texts
{
System.out.println("here is the element you need");
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
XMLInputFactory XMLFactory = XMLInputFactory.newInstance();
XMLStreamReader XMLReader = XMLFactory.createXMLStreamReader(myXMLStream);
while(XMLReader.hasNext())
{
if (XMLReader.getEventType() == XMLStreamReader.START_ELEMENT)
{
String XMLTag = XMLReader.getLocalName();
if(XMLTag.equals("value"))
{
String idValue = XMLReader.getAttributeValue(null, "id");
if (idValue.equals("FILE_CREATE_DATE"))
{
System.out.println(idValue);
XMLReader.nextTag();
System.out.println(XMLReader.getElementText());
}
}
}
XMLReader.next();
}
So this code is the final result of all my anguish on the topic of recovering specific data from a XML data file. I want to thank everyone who helped me out with answers - regardless on if it was what I was looking for they got me thinking and that led to the solution...
I have this question for your.
I've a simple file xml and I have to convert it to file Json. So far that's all right but, the output that gives me back isn't well formatted.
Here is the code:
modalities.xml
<cons>
<modalities type="mod">
<modality id="001">
<name>CC</name>
</modality>
<modality id="002">
<name>RS</name>
</modality>
<modality id="003">
<name>TC</name>
</modality>
<modality id="004">
<name>US</name>
</modality>
</modalities>
And ListModalities.java
{ ...
String path = "modalities.xml";
ModalitiesMapperImpXml modXml = new ModalitiesMapperImpXml();
if (modality.equals("list"))
modXml.load(path); //The method return the list that contain the name of modality ( CC - US )
try {
ObjectMapper mp = new ObjectMapper();
return mp.writeValueAsString(modXml);
}
catch (JsonProcessingException jpe) {
return jpe.getMessage();
}
}
Output:
{"modalities":[{"value":"\n\t\t\n\t\t\tCC\n\t\t\n\t\t\n\t\t\tRS\n\t\t\n\t\t\n\t}]}
how can I delete the spaces and the tab character?
Can you help me? Thanks
Regard
Vit
Problem is how you iterate over the XML:
element.getNodeValue()
should be replaced by
element.getTextContent()
I am working with the Play framework (2.4) for Java. I want to pass a JSONObject to a javascript used inside one of the Play view templates.
On the Java side I prepare the JSONObject, like so:
(Keep in mind that this is a test vehicle.)
public static Result showBusinesses(){
List<Item> list = new ArrayList<Item>();
Item r = new Item();
r.id = "23234";
r.name = "Joes hardware";
Item s = new Item();
s.id = "23254";
s.name = "Martys collision";
list.add(r);
list.add(s);
return ok(views.html.wheel.render(getJSONObject(list)));
}
public static JSONObject getJSONObject(List<Item> list){
JSONObject jsonObject = new JSONObject();
try{
for (int i = 0; i < list.size(); i++) {
jsonObject.put(list.get(i).id, list.get(i).name);
}
}catch (JSONException e) {
}
return jsonObject;
}
In my Play template, I accept the JSONObject parameter:
#(item : org.json.JSONObject)
#import helper._
#import helper.twitterBootstrap._
#import play.api.libs.json.Json
...
So far, so good.
Until I attempt to use the object in my javascript:
If I place my object, #item, anywhere in the template besides inside the javascript, I get this:
{"23254":"Martys Pancakes","23234":"Joes place"};
which looks like a properly formed var to me.
I am inserting the JSONObject into the javascript like this:
<script type="text/javascript">
businesses = #item;
and I expect that to translate like this:
businesses = {
"23332" : "Joe's hardware",
"56755" : "Marty's collision"
};
And yet the object does not behave as expected. I suspect that I am not passing the parameter to the javascript in the correct way.
Can anyone enlighten me? Thanks.
I found the answer to my own question. It ended up being fairly simple. First of all, you don't need to mess with JSON. You pass a standard Java List to the Play template. Then you iterate through that list inside the Javascript variable curly braces. Here is the template code:
#(businesses: List[Business])
#import helper._
#import helper.twitterBootstrap._
...
<script type="text/javascript">
places = {
#for((item, index) <- businesses.zipWithIndex) {
#if(index != businesses.size-1) {
"#item.id" : "#Html(item.name)",}
else {"#item.id" : "#Html(item.name)"}
}
};
I used the built-in zipWithIndex because I needed commas separating every line but the last. The #Html() was needed to escape all the special chars that HTML needs to have translated. Once the javascript runs, you end up with your variable:
places = {
"345" : "Joe's Hardware",
"564" : "Jan's Party Store"
}
I have to parse an XML file with following structure:
<root>
<object_1>
<pro1> abc </pro1>
<pro2> pqr </pro2>
<pro3> xyz </pro3>
<children>
<object_a>
<pro1> abc </pro1>
<pro2> pqr </pro2>
<pro3> xyz </pro3>
<children>
.
.
.
</children>
</object_a>
</children>
</object_1>
<object_2>
.
.
.
</object_n>
</root>
Aim is to parse this multilevel nesting. A few classes are defined in Java.
Class Object_1
Class Object_2
.
.
.
Class Object_N
with their respective properties.
The following code is working for me, but then this is not the best way of doing things.
File file = new File(fileName);
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(file);
doc.getDocumentElement().normalize();
if(doc ==null) return;
Node node = doc.getFirstChild();
NodeList lst = node.getChildNodes();
Node children = null ;
int len = lst.getLength();
for(int index=0;index<len;index++)
{
Node child = lst.item(index);
String name = child.getNodeName();
if(name=="Name")
name = child.getNodeValue();
else if(name=="Comment")
comment = child.getNodeValue());
else if(name=="children")
children = child;
}
if(children==null) return;
lst = children.getChildNodes();
len = lst.getLength();
Class<?> obj=null;
AbsModel model = null;
for(int index=0;index<len;index++)
{
Node childNode = lst.item(index);
String modelName = childNode.getNodeName();
try {
obj = Class.forName(modelName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
if(obj!=null)
model = (AbsModel) obj.newInstance();
else
model = new GenericModel();
model.restoreDefaultPropFromXML(childNode);
addChild(model);
}
}
Is there a better way of parsing this XML.
Consider using JAXB, which is part of Java since version 6. You should be able to parse (“unmarshall”) your XML file into your own classes with almost no code, just adding a few annotations expliciting the mapping between your object structure and your XML structure.
StAX and or JAXB is almost always the way to go.
If the XML is really dynamic (like attributes specify the property name) ie <prop name="property" value="" /> then you will need to use StAX only or live with what JAXB will map it to (a POJO with name and value properties) and post process.
Personally I find combining StAX and JAXB the best. I parse to the elements I want and then use JAXB to turn the element into a POJO.
See Also:
My own utility library that will turn an XML Stream into an iterator of objects.
Parsing very large XML files and marshalling to Java Objects
http://tedone.typepad.com/blog/2011/06/unmarshalling-benchmark-in-java-jaxb-vs-stax-vs-woodstox.html
While JAXB may be the best choice I'd also like to mention jOOX which provides a JQuery-like API and makes working with XML documents really pleasant.
I have a XmlDocument in java, created with the Weblogic XmlDocument parser.
I want to replace the content of a tag in this XMLDocument with my own data, or insert the tag if it isn't there.
<customdata>
<tag1 />
<tag2>mfkdslmlfkm</tag2>
<location />
<tag3 />
</customdata>
For example I want to insert a URL in the location tag:
<location>http://something</location>
but otherwise leave the XML as is.
Currently I use a XMLCursor:
XmlObject xmlobj = XmlObject.Factory.parse(a.getCustomData(), options);
XmlCursor xmlcur = xmlobj.newCursor();
while (xmlcur.hasNextToken()) {
boolean found = false;
if (xmlcur.isStart() && "schema-location".equals(xmlcur.getName().toString())) {
xmlcur.setTextValue("http://replaced");
System.out.println("replaced");
found = true;
} else if (xmlcur.isStart() && "customdata".equals(xmlcur.getName().toString())) {
xmlcur.push();
} else if (xmlcur.isEnddoc()) {
if (!found) {
xmlcur.pop();
xmlcur.toEndToken();
xmlcur.insertElementWithText("schema-location", "http://inserted");
System.out.println("inserted");
}
}
xmlcur.toNextToken();
}
I tried to find a "quick" xquery way to do this since the XmlDocument has an execQuery method, but didn't find it very easy.
Do anyone have a better way than this? It seems a bit elaborate.
How about an XPath based approach? I like this approach as the logic is super-easy to understand. The code is pretty much self-documenting.
If your xml document is available to you as an org.w3c.dom.Document object (as most parsers return), then you could do something like the following:
// get the list of customdata nodes
NodeList customDataNodeSet = findNodes(document, "//customdata" );
for (int i=0 ; i < customDataNodeSet.getLength() ; i++) {
Node customDataNode = customDataNodeSet.item( i );
// get the location nodes (if any) within this one customdata node
NodeList locationNodeSet = findNodes(customDataNode, "location" );
if (locationNodeSet.getLength() > 0) {
// replace
locationNodeSet.item( 0 ).setTextContent( "http://stackoverflow.com/" );
}
else {
// insert
Element newLocationNode = document.createElement( "location" );
newLocationNode.setTextContent("http://stackoverflow.com/" );
customDataNode.appendChild( newLocationNode );
}
}
And here's the helper method findNodes that does the XPath search.
private NodeList findNodes( Object obj, String xPathString )
throws XPathExpressionException {
XPath xPath = XPathFactory.newInstance().newXPath();
XPathExpression expression = xPath.compile( xPathString );
return (NodeList) expression.evaluate( obj, XPathConstants.NODESET );
}
How about an object oriented approach? You could deserialise the XML to an object, set the location value on the object, then serialise back to XML.
XStream makes this really easy.
For example, you would define the main object, which in your case is CustomData (I'm using public fields to keep the example simple):
public class CustomData {
public String tag1;
public String tag2;
public String location;
public String tag3;
}
Then you initialize XStream:
XStream xstream = new XStream();
// if you need to output the main tag in lowercase, use the following line
xstream.alias("customdata", CustomData.class);
Now you can construct an object from XML, set the location field on the object and regenerate the XML:
CustomData d = (CustomData)xstream.fromXML(xml);
d.location = "http://stackoverflow.com";
xml = xstream.toXML(d);
How does that sound?
If you don't know the schema the XStream solution probably isn't the way to go. At least XStream is on your radar now, might come in handy in the future!
You should be able to do this with query
try
fn:replace(string,pattern,replace)
I am new to xquery myself and I have found it to be a painful query language to work with, but it does work quiet well once you get over the initial learning curve.
I do still wish there was an easier way which was as efficient?