Fill data in XML from another XML file dynamically (Java) - java

I have a xml file where I would like to fill in values from another xml file. For example, if I have data.xml:
<Data>
<Person>
<Name>neby</Name>
<Phone>
<Home>5553456789</Home>
<Mobile>5559879876</Mobile>
</Phone>
</Person>
</Data>
I want to fill in test.xml like this (Data taken from the above file):
<Test>
<Name>${Name}</Name>
<Number>${Home}</Number>
</Test>
In my Java program, I create XML files during runtime. I would like to give a file name, "pass" it to test.xml, have test.xml read it, and fill in the text.
Is there a way to do this?
Am I doing it correctly? All I get is the encoding. Never mind, I got it to work. Using the data.xml from above.
MyXSL.xsl:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:for-each select="Data/Person">
<Test>
<Name><xsl:value-of select="Name"/></Name>
<Number><xsl:value-of select="Home"/></Number>
</Test>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Code:
try {
File stylesheet = new File("MyXSL.xsl");
File dataFile = new File("data.xml");
Document document = DocumentBuilderFactory.newInstance()
.newDocumentBuilder().parse(dataFile);
StreamSource stylesource = new StreamSource(stylesheet);
Transformer transformer = TransformerFactory.newInstance().newTransformer(stylesource);
StringWriter stringWriter = new StringWriter();
transformer.transform(new DOMSource(document), new StreamResult(stringWriter));
System.out.println(stringWriter.toString());
} catch(Exception e){
e.printStackTrace();
}
Output: <?xml version="1.0" encoding="UTF-8"?>
What am I doing wrong? Above code works.

Create XSLT and then something like that (very simple from oracle java tuts):
// ...
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.stream.StreamResult;
// ...
public class Stylizer {
// ...
public static void main (String argv[]) {
// ...
try {
File stylesheet = new File(argv[0]);
File datafile = new File(argv[1]);
DocumentBuilder builder = factory.newDocumentBuilder();
document = builder.parse(datafile);
// ...
StreamSource stylesource = new StreamSource(stylesheet);
Transformer transformer = Factory.newTransformer(stylesource);
}
}
}
All informations and step-by-step guide to create XSLT and this sample app is here.

Related

how should I store xml data in a java class

I am just beginning to learn to read xml in java. My question is very basic. How do I store attributes and sub-elements of an xml element in a java class.
Thus if I have a simple xml file as follows :
<?xml version="1.0"?>
<class>
<student rollno="393">
<firstname>dinkar</firstname>
<lastname>kad</lastname>
<nickname>dinkar</nickname>
<marks>85</marks>
</student>
<student rollno="493">
<firstname>Vaneet</firstname>
<lastname>Gupta</lastname>
<nickname>vinni</nickname>
<marks>95</marks>
</student>
<student rollno="593">
<firstname>jasvir</firstname>
<lastname>singn</lastname>
<nickname>jazz</nickname>
<marks>90</marks>
</student>
</class>
How do I design a java class to store student data. If sub-elements are stored as data members then how should I store the attribute rollno
I recommend you to use JAXB to map XML file into POJO objects.
First create a Student bean class as below:
public class Student {
private int id;
private String firstName;
private String lastName;
private String nickName;
private int marks;
// getters and setters
}
Then you can use DOM parser or SAX parser util populate the data.
You should use the TransformerFactory class as shown:
try {
Document document = null;
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
DOMSource source = new DOMSource(document);
File f = new File(fileName + ".xml");
StreamResult result = new StreamResult(f);
transformer.transform(source, result);
} catch (TransformerException e) {
throw e;
}
Remember that you have to add TransformerException to the method signature.

How to stop XML Tag Attributes from sorting in Ascending Order after modifying the XML file using Java?

I have written a program to find all XML files matching a particular pattern in a directory and modify it by adding a new tag.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<paths>
<upgradepath startversion="1.4.0.0" moduleid="${moduleId}" endversion="1.4.0.1">
<steps>
<!-- Put scripts here to go from 1.4.0.0 to 1.4.0.1 -->
</steps>
</upgradepath>
<upgradepath startversion="1.4.0.1" moduleid="${moduleId}" endversion="1.4.0.2">
<steps>
<!-- Put scripts here to go from 1.4.0.1 to 1.4.0.2 -->
</steps>
</upgradepath>
</paths>
After running my program the XML file gets modified as below :
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<paths>
<upgradepath endversion="1.4.0.1" moduleid="${moduleId}" startversion="1.4.0.0">
<steps>
<!-- Put scripts here to go from 1.4.0.0 to 1.4.0.1 -->
</steps>
</upgradepath>
<upgradepath endversion="1.4.0.2" moduleid="${moduleId}" startversion="1.4.0.1">
<steps>
<!-- Put scripts here to go from 1.4.0.1 to 1.4.0.2 -->
</steps>
</upgradepath>
<upgradepath endversion="1.4.0.3" moduleid="${moduleId}" startversion="1.4.0.2">
<steps>
<!--Put scripts here to go from 1.4.0.2 to 1.4.0.3-->
</steps>
</upgradepath>
</paths>
If you see the attributes of all the tags you will see that they have all been rearranged in ascending order. The startversion attribute now appears last and the endversion attribute appears first. I want the original order of the attributes after modification of the XML file. I have tried almost everything and have lost all hope. Is there any way I can do this? Also is there a way to sort the attributes in descending order? It's not the right solution but it helps.
Here is a code snippet from the program I am using to modify the files :
private static void updateXMLFiles(String sStartVersion, String sEndVersion) {
try {
for (int c = 0; c < pathsList.size(); c++) {
File xmlFile = new File(pathsList.get(c).toString());
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder;
dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(xmlFile);
doc.getDocumentElement().normalize();
// Get the last <upgradepath> tag in the file.
// Method Call to verify the version entered and update the XML Files.
// Write the updated document to the file.
doc.getDocumentElement().normalize();
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File(pathsList.get(c).toString()));
transformer.setOutputProperty(OutputKeys.STANDALONE, "yes");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
transformer.transform(source, result);
}
catch (SAXException e1) {
e1.printStackTrace();
}
catch (ParserConfigurationException e1) {
e1.printStackTrace();
}
catch (IOException e1) {
e1.printStackTrace();
}
catch (TransformerException e1) {
e1.printStackTrace();
}
}
private static void addNewVersion(Document doc, String sStartVersion, String sEndVersion) {
Element element = doc.getDocumentElement();
Element upgradePath = doc.createElement("upgradepath");
upgradePath.setAttribute("startversion", sStartVersion);
upgradePath.setAttribute("moduleid", "${moduleId}");
upgradePath.setAttribute("endversion", sEndVersion);
Element steps = doc.createElement("steps");
Comment comment = doc.createComment("Put scripts here to go from " + sStartVersion + " to " + sEndVersion);
steps.appendChild(comment);
upgradePath.appendChild(steps);
element.appendChild(upgradePath);
}
Is there any way I can keep the order of the attributes intact or in the worst case arrange it in descending order?
A friend of mine suggested I try out JAXB but I couldn't find a way to achieve this. If someone thinks JAXB can solve this do mention how to format an existing XML file and not creating one.
Another issue which is not a major concern is that although I have used the
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
the newly added tags are not indented correctly. Any way to fix this?
#XmlType(propOrder = {"startversion", "moduleid", "endversion", "steps"})
public class XmlSubModel {
private String startversion = "";
private String moduleid = "";
private String endversion = "";
private String steps = "";
#XmlAttribute
public String getStartversion() {
return startversion;
}
public void setStartversion(String startversion) {
this.startversion = startversion;
}
#XmlAttribute
public String getModuleid() {
return moduleid;
}
public void setModuleid(String moduleid) {
this.moduleid = moduleid;
}
#XmlAttribute
public String getEndversion() {
return endversion;
}
public void setEndversion(String endversion) {
this.endversion = endversion;
}
public String getSteps() {
return steps;
}
public void setSteps(String steps) {
this.steps = steps;
}
}

Allowed Special Character in Transformer

I am trying to send xml file to server after processing it which has some special character like "佥佬佧佼A£".
Currently code looks like
public class Utils {
public static String transformToString(Document activeDocument) throws TransformerException{
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty(OutputKeys.INDENT, "true");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
StringWriter writer = new StringWriter();
transformer.transform(new DOMSource(document), new StreamResult(writer));
writer.toString();
}
Test class
public class Test {
public static void main(String[] args){
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(xmlPath);
//Doing some process on doc and changing other values
String xmlString = Utils.transformToString(doc);
// Sending xml to soap
HttpPost post = new HttpPost(endpoint);
post.setEntity(new StringEntity(xmlString));
post.setHeader(new BasicHeader("content-type", "text/xml"));
.................
}
}
XML file
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope ....>
<soapenv:Header/>
<soapenv:Body>
<Test>
<Id>佥佬佧佼A£</Id>
..............
..........
</Test>
.........
I am getting xmlString with Id value : ????A£
What I want is : 佥佬佧佼A£
How can I do that ? I just want String format of that XML.
EDIT : I am loading one XML, Doing some changes into it, and sending that XML to SOAP, by Setting that document to httpPost.setEntity()
Thanks,
Ankit
You can try:
encoding="UTF-16"
instead of
encoding="UTF-8"

How do I give a argument to a XSL Transformation?

I'm following this article to get the contents of a iTunes playlist
The author says the following XSL can be used to transform a named iTunes playlist into M3U format:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:param name="playlist" />
<xsl:variable name="newline">
<xsl:text>
</xsl:text>
</xsl:variable>
<xsl:template match="/">
<xsl:for-each select="plist/dict/key[text()='Playlists']/
following-sibling::array/dict/key[text()='Name']/
following-sibling::string[text()=$playlist]/
following-sibling::key[text()='Playlist Items']/
following-sibling::array/dict">
<xsl:call-template name="track">
<xsl:with-param name="trackid" select=
"key[text()='Track ID']/following-sibling::integer" />
</xsl:call-template>
</xsl:for-each>
</xsl:template>
<xsl:template name="track">
<xsl:param name="trackid" />
<xsl:variable name="url"
select="//plist/dict/key[text()='Tracks']/
following-sibling::dict/dict/key[text()='Track ID']/
following-sibling::integer[text()=$trackid]/../
key[text()='Location']/following-sibling::string" />
<xsl:value-of select="$url" /><xsl:value-of select="$newline" />
</xsl:template>
</xsl:stylesheet>
How can I do that? From what I learned so far about XSL I thought I might have to replace $playlist with the the playlist's name. Am I right? And if yes, how can I do that efficiently as addition to the following code:
public String getPlaylist(String playlist) {
Source source = new StreamSource(library);
StreamSource xsl = new StreamSource(getClass().getResourceAsStream("M3Utransformation.xml"));
StringWriter w = new StringWriter();
Result result = new StreamResult(w);
try {
Transformer transformer = TransformerFactory.newInstance().newTransformer(xsl);
transformer.transform(source, result);
return w.getBuffer().toString();
} catch (Throwable t) {
t.printStackTrace();
return null;
}
}
Transformer has an API to pass in parameter values, you just need to add
transformer.setParameter("playlist", playlist);
immediately before the transformer.transform(...) line.
If you're going to be calling this method repeatedly then rather than loading and compiling the stylesheet every time it would be more efficient to load it once and then re-use the same Transformer for future calls:
private Transformer transformer = null;
public String getPlaylist(String playlist) {
if(transformer == null) {
StreamSource xsl = new StreamSource(getClass().getResourceAsStream("M3Utransformation.xml"));
try {
transformer = TransformerFactory.newInstance().newTransformer(xsl);
} catch (Throwable t) {
t.printStackTrace();
return null;
}
}
StringWriter w = new StringWriter();
Source source = new StreamSource(library);
Result result = new StreamResult(w);
try {
transformer.setParameter("playlist", playlist);
transformer.transform(source, result);
return w.getBuffer().toString();
} catch (Throwable t) {
t.printStackTrace();
return null;
}
}
(Note that Transformer is not thread safe, so if you're making calls from multiple threads you'd need to use the Templates mechanism instead)

Java JAXB - link output to XSLT document

I am producing a XML file by the help of JAXB.
public String getPrices() {
StringWriter writer = new StringWriter();
JAXBContext context;
try {
context = JAXBContext.newInstance(AllMerchandises.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal(this.allMerchandises, writer);
} catch (JAXBException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return writer.toString();
}
the resulting XML String looks like this.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:merchandises xmlns:ns2="example/test/workspace">
<merchandise id="1">
<name>Cat</name>
<price>50</price>
</merchandise>
<merchandise id="2">
<name>Dog</name>
<price>100</price>
</merchandise>
<merchandise id="3">
<name>Ape</name>
<price>150</price>
</merchandise>
<merchandise id="4">
<name>Gorilla</name>
<price>200</price>
</merchandise>
<merchandise id="5">
<name>Elephant</name>
<price>250</price>
</merchandise>
</ns2:merchandises>
It is my task that the document could be showed a little bit designed in a browser by using XSLT. Therefor I need to include the .xsl in my XML file. Is there a maybe a way to tell the JAXB marshaller to make a inclusion? What could I do otherwise?
I need to include sth like this as 2nd line:
<?xml-stylesheet type="text/xsl" href="myfile.xsl"?>
thanks for every good idea
Finally I ended up using the same solution as described in this thread.
Making JAXB generate an XML processing instruction

Categories