Java appending XML data - java

I've already read through a few of the answers on this site but none of them worked for me. I have an XML file like this:
<root>
<character>
<name>Volstvok</name>
<charID>(omitted)</charID>
<userID>(omitted)</userID>
<apiKey>(omitted)</apiKey>
</character>
</root>
I need to add another <character> somehow.
I'm trying this but it does not work:
public void addCharacter(String name, int id, int userID, String apiKey){
Element newCharacter = doc.createElement("character");
Element newName = doc.createElement("name");
newName.setTextContent(name);
Element newID = doc.createElement("charID");
newID.setTextContent(Integer.toString(id));
Element newUserID = doc.createElement("userID");
newUserID.setTextContent(Integer.toString(userID));
Element newApiKey = doc.createElement("apiKey");
newApiKey.setTextContent(apiKey);
//Setup and write
newCharacter.appendChild(newName);
newCharacter.appendChild(newID);
newCharacter.appendChild(newUserID);
newCharacter.appendChild(newApiKey);
doc.getDocumentElement().appendChild(newCharacter);
}

Without seeing all your code, I suspect the problem is that you're adjusting the in-memory DOM, but not writing the result back to the file.
Writing it out looks something like:
TransformerFactory.newInstance().newTransformer()
.transform(new DOMSource(doc),
new StreamResult(f));
where doc is a Document, and f is the File to write to.
In order to find particular elements in a DOM, I recommend XPath.

Related

> and < gets converted to > and < while adding a xml like string in element.setTextContent()

I have a string which looks like an XML
Ex: String sample = "<GrpHdr><MsgId>MQSECJYJHRBPDTZTYNNEYXOZUPAUDEKVDFV</MsgId><CreDtTm>2023-02-02T21:48:58.075+05:30</CreDtTm></GrpHdr>";
I am trying to create an XML document with an element containing the above information:
Ex:
<ns1:TstCode>T</ns1:TstCode>
<ns1:FType>SCF</ns1:FType>
<ns1:FileRef>220811084023</ns1:FileRef>
<ns1:RoutingInd>ALL</ns1:RoutingInd>
<ns1:FileBusDt>2022-08-11</ns1:FileBusDt>
<ns1:FIToFI xmlns="urn:iso:std:iso:20022:tech:xsd">
<GrpHdr>
<MsgId>MQSECJYJHRBPDTZTYNNEYXOZUPAUDEKVDFV</MsgId>
<CreDtTm>2023-02-02T21:48:58.075+05:30</CreDtTm>
</GrpHdr>
</ns1:FIToFI>
When I create the document for the above XML using this code:
private static DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
DOMImplementation domImpl = db.getDOMImplementation();
private Document buildExampleDocumentWithNamespaces(DOMImplementation domImpl, String output) {
Document document = domImpl.createDocument("urn:Scf:xsd:$BlkCredTrf", "ns1:BlkCredTrf", null);
document.getDocumentElement().appendChild(document.createElement("ns1:TstCode")).setTextContent("T");
document.getDocumentElement().appendChild(document.createElement("ns1:FType")).setTextContent("SCF");
document.getDocumentElement().appendChild(document.createElement("ns1:FileRef")).setTextContent("220811084023");
document.getDocumentElement().appendChild(document.createElement("ns1:RoutingInd")).setTextContent("ALL");
document.getDocumentElement().appendChild(document.createElement("ns1:FileBusDt")).setTextContent("2022-08-11");
document.getDocumentElement().appendChild(document.createElementNS("urn:iso:std:iso:tech:xsd","ns1:FIToFI");
return document;
}
I do not have issues until this point.
When I try to add <GrpHdr><MsgId>MQSECJYJHRBPDTZTYNNEYXOZUPAUDEKVDFV</MsgId><CreDtTm>2023-02-02T21:48:58.075+05:30</CreDtTm></GrpHdr> as a Text content to the FIToFI tag at last, using the code:
document.getDocumentElement().appendChild(document.createElementNS("urn:iso:std:iso:tech:xsd","ns1:FIToFI").setTextContent(sample);
The XML gets created like this:
<ns1:TstCode>T</ns1:TstCode>
<ns1:FType>SCF</ns1:FType>
<ns1:FileRef>220811084023</ns1:FileRef>
<ns1:RoutingInd>ALL</ns1:RoutingInd>
<ns1:FileBusDt>2022-08-11</ns1:FileBusDt>
<ns1:FIToFI xmlns="urn:iso:std:iso:20022:tech:xsd">
<GrpHdr>
<MsgId>MQSECJYJHRBPDTZTYNNEYXOZUPAUDEKVDFV</MsgId>
<CreDtTm>2023-02-02T21:48:58.075+05:30</CreDtTm>
</GrpHdr>
</ns1:FIToFI>
Please help me to create this XML without the escape characters.
That the content is escaped is intended. When you set the text content of an element, any special character like < have to be escaped like <, otherwise the text content will be interpreted as other XML content like elements or comments. That's why setTextContent() will escape the content for you.
When you want to add an element instead, you use methods like appendChild() with an Element argument. Build your elements as usual with the createElement() method and add them together like this:
Element element = document.createElementNS("urn:iso:std:iso:tech:xsd","ns1:FIToFI");
Element grpHdr = document.createElement("GrpHdr");
Element msgId = document.createElement("MsgId");
msgId.setTextContent("MQSECJYJHRBPDTZTYNNEYXOZUPAUDEKVDFV");
grpHdr.appendChild(msgId);
Element creDtTm = document.createElement("CreDtTm");
creDtTm.setTextContent("2023-02-02T21:48:58.075+05:30");
grpHdr.appendChild(creDtTm);
element.appendChild(grpHdr);
document.getDocumentElement().appendChild(element);
This will add the XML element inside the other XML element.
When you have the inner XML as a string, parse the XML string with DocumentBuilder.parse() (see How to create a XML object from String in Java?) and import the Element with the Document.importNode() method (see org.w3c.dom.DOMException: WRONG_DOCUMENT_ERR: A node is used in a different document than the one that created it). The code can look like this:
String innerXml = "<GrpHdr><MsgId[...]eDtTm></GrpHdr>";
Document innerDocument = db.parse(new InputSource(new StringReader(innerXml)));
Element innerRootElement = innerDocument.getDocumentElement();
Node importedNode = document.importNode(innerRootElement, true);
element.appendChild(importedNode);

How to insert new node at specific position in XML?

I Have XML with this structure:
<ms:tech ID="TM_002">
<ms:wrap MDTYPE="NISOIMG" MIMETYPE="text/xml">
<ms:xmlData>
<ml:ml>
<mx:BasicInformation>
<mx:ObjectIdentifier>
<mx:objectIdentifierType>Value</mix:objectIdentifierType>
</mx:ObjectIdentifier>
**-----HERE AT THIS POSITION INSERT NEW XML TAG------**
<mx:byteOrder>Value2</mx:byteOrder>
<mx:Compression>
<mx:compressionScheme>Uncompressed</mx:compressionScheme>
</mx:Compression>
</mx:BasicInformation>
</ml:ml>
<ms:xmlData>
</ms:wrap>
</ms:tech>
I want to insert new XML tag at specific position in XML tree. My code so far looks like this:
String xp = "//ms:tech[#ID='TM_002']/ms:wrap/ms:xmlData/ml:ml/mx:BasicInformation";
List<Node> list = amdDocument.selectNodes(xp);
Node element = list.get(0);
By this I got the tag, and in this tag I want insert new one after . Im using dom4j. How can I do this? Thanks.

Java appendChild (CSV to XML conversion) doesn't work for ONE node

So I need to convert a CSV file to seperate XML files (one XML file per line in the CSV file). And this all works fine, except for the fact that it refuses to add one value. It adds the other without a problem, but for some mysterious reason refuses to create a tag for one of my nodes.
Document newDoc = documentBuilder.newDocument();
Element rootElement = newDoc.createElement("XMLoutput");
newDoc.appendChild(rootElement);
String header = headers.get(col);
String value = null;
String value2 = null;
if (col < rowValues.length) {
if(header.equals("delay")) {
value = rowValues[col];
Thread.sleep(Long.parseLong(value));
}
Element shipidElement = newDoc.createElement("shipID");
shipidElement.appendChild(newDoc.createTextNode(FilenameUtils.getBaseName(csvFileName)));
rootElement.appendChild(shipidElement);
if(header.equals("centraleID")) {
value = rowValues[col];
System.out.println(value); //to check if the if condition works, it does
Element centralElement = newDoc.createElement(header);
Text child = newDoc.createTextNode(value);
centralElement.appendChild(child);
rootElement.appendChild(centralElement);
}
else if(header.equals("afstandTotKade")) {
value2 = rowValues[col];
Element curElement = newDoc.createElement(header);
curElement.appendChild(newDoc.createTextNode(value2));
rootElement.appendChild(curElement);
}
String timeStamp = new SimpleDateFormat("HH:mm:ss").format(new Date());
Element timeElement = newDoc.createElement("Timestamp");
timeElement.appendChild(newDoc.createTextNode(timeStamp));
rootElement.appendChild(timeElement);
}
So in the above code, the if loop checking for CentraleID actually works, because it prints out the values, however the XML file does not add a tag, not even if I just insert a string instead of the header value. It does, however, insert the "afstandTotKade" node and timestamp node. I am dumbfounded.
PS: this is only part of the code of course, but the problem is so minute, that it seemed superfluous to add all of it.
PPS: the code was originally the same as the others, I've just been playing around.
This is the resulting XML File btw, so the other if does add the nodes, and I know the spelling is correct in checking the header because it does print out the values (the sout code) when I run it:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<XMLoutput>
<shipID>1546312</shipID>
<afstandTotKade>1000</afstandTotKade>
<Timestamp>22:06:33</Timestamp>
</XMLoutput>

Extracting Values From an XML File Either using XPath, SAX or DOM for this Specific Scenario

I am currently working on an academic project, developing in Java and XML. Actual task is to parse XML, passing required values preferably in HashMap for further processing. Here is the short snippet of actual XML.
<root>
<BugReport ID = "1">
<Title>"(495584) Firefox - search suggestions passes wrong previous result to form history"</Title>
<Turn>
<Date>'2009-06-14 18:55:25'</Date>
<From>'Justin Dolske'</From>
<Text>
<Sentence ID = "3.1"> Created an attachment (id=383211) [details] Patch v.2</Sentence>
<Sentence ID = "3.2"> Ah. So, there's a ._formHistoryResult in the....</Sentence>
<Sentence ID = "3.3"> The simple fix it to just discard the service's form history result.</Sentence>
<Sentence ID = "3.4"> Otherwise it's trying to use a old form history result that no longer applies for the search string.</Sentence>
</Text>
</Turn>
<Turn>
<Date>'2009-06-19 12:07:34'</Date>
<From>'Gavin Sharp'</From>
<Text>
<Sentence ID = "4.1"> (From update of attachment 383211 [details])</Sentence>
<Sentence ID = "4.2"> Perhaps we should rename one of them to _fhResult just to reduce confusion?</Sentence>
</Text>
</Turn>
<Turn>
<Date>'2009-06-19 13:17:56'</Date>
<From>'Justin Dolske'</From>
<Text>
<Sentence ID = "5.1"> (In reply to comment #3)</Sentence>
<Sentence ID = "5.2"> &gt; (From update of attachment 383211 [details] [details])</Sentence>
<Sentence ID = "5.3"> &gt; Perhaps we should rename one of them to _fhResult just to reduce confusion?</Sentence>
<Sentence ID = "5.4"> Good point.</Sentence>
<Sentence ID = "5.5"> I renamed the one in the wrapper to _formHistResult. </Sentence>
<Sentence ID = "5.6"> fhResult seemed maybe a bit too short.</Sentence>
</Text>
</Turn>
.....
and so on
</BugReport>
There are many commenter like 'Justin Dolske' who have commented on this report and what I actually looking for is the list of commenter and all sentences they have written in a whole XML file. Something like if(from == justin dolske) getHisAllSentences(). Similarly for other commenters (for all). I have tried many different ways to get the sentences only for 'Justin dolske' or other commenters, even in a generic form for all using XPath, SAX and DOM but failed. I am quite new to these technologies including JAVA and any don't know how to achieve it.
Can anyone guide me specifically how could I get it with any of above technologies or is there any other better strategy to do it?
(Note: Later I want to put it in a hashmap such as like this HashMap (key, value) where key = name of commenter (justin dolske) and value is (all sentences))
Urgent help will be highly appreciated.
There're several ways using which you can achieve your requirement.
One way would be use JAXB. There're several tutorials available on this on the web, so feel free to refer to them.
You can also think of creating a DOM and then extracting data from it and then put it into your HashMap.
One reference implementation would be something like this:
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
public class XMLReader {
private HashMap<String,ArrayList<String>> namesSentencesMap;
public XMLReader() {
namesSentencesMap = new HashMap<String, ArrayList<String>>();
}
private Document getDocument(String fileName){
Document document = null;
try{
document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new File(fileName));
}catch(Exception exe){
//handle exception
}
return document;
}
private void buildNamesSentencesMap(Document document){
if(document == null){
return;
}
//Get each Turn block
NodeList turnList = document.getElementsByTagName("Turn");
String fromName = null;
NodeList sentenceNodeList = null;
for(int turnIndex = 0; turnIndex < turnList.getLength(); turnIndex++){
Element turnElement = (Element)turnList.item(turnIndex);
//Assumption: <From> element
Element fromElement = (Element) turnElement.getElementsByTagName("From").item(0);
fromName = fromElement.getTextContent();
//Extracting sentences - First check whether the map contains
//an ArrayList corresponding to the name. If yes, then use that,
//else create a new one
ArrayList<String> sentenceList = namesSentencesMap.get(fromName);
if(sentenceList == null){
sentenceList = new ArrayList<String>();
}
//Extract sentences from the Turn node
try{
sentenceNodeList = turnElement.getElementsByTagName("Sentence");
for(int sentenceIndex = 0; sentenceIndex < sentenceNodeList.getLength(); sentenceIndex++){
sentenceList.add(((Element)sentenceNodeList.item(sentenceIndex)).getTextContent());
}
}finally{
sentenceNodeList = null;
}
//Put the list back in the map
namesSentencesMap.put(fromName, sentenceList);
}
}
public static void main(String[] args) {
XMLReader reader = new XMLReader();
reader.buildNamesSentencesMap(reader.getDocument("<your_xml_file>"));
for(String names: reader.namesSentencesMap.keySet()){
System.out.println("Name: "+names+"\tTotal Sentences: "+reader.namesSentencesMap.get(names).size());
}
}
}
Note: This is just a demonstration and you would need to modify it to suit your need. I've created it based on your XML to show one way of doing it.
I suggest to use JAXB to creates a Data Model reflecting your XML structure.
One done, you can load the XML into Java instances.
Put each 'Turn' into a Map< String, List< Turn >>, using Turn.From as key.
Once done, you'll can write:
List< Turn > justinsTurn = allTurns.get( "'Justin Dolske'" );

How to prevent xml transformer to transform empty tags into single tag

I'm using javax.xml.transform.Transformer class to transform the DOM source into XML string. I have some empty elements in DOM tree, and these become one tag which I don't want.
How do I prevent <sampletag></sampletag> from becoming <sampletag/>?
I hade the same problem.
This is the function to get that result.
public static String fixClosedTag(String rawXml){
LinkedList<String[]> listTags = new LinkedList<String[]>();
String splittato[] = rawXml.split("<");
String prettyXML="";
int counter = 0;
for(int x=0;x<splittato.length;x++){
String tmpStr = splittato[x];
int indexEnd = tmpStr.indexOf("/>");
if(indexEnd>-1){
String nameTag = tmpStr.substring(0, (indexEnd));
String oldTag = "<"+ nameTag +"/>";
String newTag = "<"+ nameTag +"></"+ nameTag +">";
String tag[]=new String [2];
tag[0] = oldTag;
tag[1] = newTag;
listTags.add(tag);
}
}
prettyXML = rawXml;
for(int y=0;y<listTags.size();y++){
String el[] = listTags.get(y);
prettyXML = prettyXML.replaceAll(el[0],el[1]);
}
return prettyXML;
}
If you want to control how XML is formatted, provide your own ContentHandler to prettify XML into "text". It should not matter to the receiving end (unless human) whether it receives <name></name> or <name/> - they both mean the same thing.
The two representations are equivalent to an XML parser, so it doesn't matter.
If you want to process XML with anything else than an XML-parser, you will end up with a lot of work and an XML-parser anyway.
If the process you are sending it through NEEDS the element not to be self-closing (which it should not), you can force the element not to be self-closing by placing content inside of it.
How does the PDF converter handle XML comments or processing instructions?
<sampletag>!<--Sample Comment--></sampletag>
<sampletag><?SampleProcessingInstruction?></sampletag>
I tried below to prevent transform empty tags into single tag :
Transformer tf = TransformerFactory.newInstance().newTransformer();
tf.setOutputProperty(OutputKeys.METHOD,"html")
It's retaining empty tags.

Categories

Resources