Read the contents of child node from xml to Java - java

I have been trying to read this xml and fetch the values of id,active and MAIN_ID and store to string values in java as i need to process each values further. But i could read the Node document ,but iam not sure how to get the values of id ,active and MAIN_ID when we loop though the document. Can someone give me ideas to parse this xml and best way to do it.
<add>
<document>
<field name='id'>Summer id</field>
<field name='active' update='add'>yes</field>
<field name='MAIN_ID' update='add'>34242</field>
</doc>
<document>
<field name='id'>winter id</field>
<field name='active' update='add'>yes</field>
<field name='MAIN_ID' update='add'>5354</field>
</document>
<doc>
Right now this is my code .But iam not sure to retrive the child nodes based on fields.
DocumentBuilder builder = factory.newDocumentBuilder();
// create a new document from input stream and an empty systemId
Document doc = builder.parse(url);
// get the first element
Element element = doc.getDocumentElement();
System.out.println("element" + element);
// get all child nodes
NodeList nodes = element.getChildNodes();
// print the text content of each child
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
if (node instanceof Element) {
//need to know how to parse the child elements for above code
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}

First consider not using attributes in XML to specify node meaning, so instead have something like this
...
<document>
<id>winter id</id>
<active update='add'>yes</active>
<MAIN_ID update='add'>5354</MAIN_ID>
</document>
...
If your document is large, consider learning about and using a SAX parser. However if you want to use DOM, look at the org.w3c.dom.Element interface. There are lots of step by step posts on SO on how to parse HTML using DOM, like this one. But you want getElementsByTagName for elements named "document", then pull the individual fields from that Element using the same methods to get id, active, etc.

Related

How to add new attribute into XML string in JAVA? Condition: based on parent Key and I can use only JAVA internal api if we need to do parse or SAX

I have a following xml string.
<aa>
<bb>
<cc>
<cmd>
<efg sid="C1D7B70D7AF705731B0" mid="C1D7D7AF705731B0" stid="-1" dopt="3">
<pqr>
<dru fo="1" fps="1" nku="WBECDD6CC37656E6C9" tt="1"/>
<dpo drpr="67" dpi="16"/>
<dres >
<dre dreid="BB:8D679D3511D3E4981000E787EC6DE8A4:1:1:0:2:1" fa="1" dpt= "1" o="0"/>
</dres>
</pqr>
</efg>
</cmd>
</cc>
</bb>
</aa>
I need to add "login" attribute inside <efg> tag. So new XML would be
<aa>
<bb>
<cc>
<cmd>
<efg sid="C1D7B70D7AF705731B0" login="sdf34234dfs" mid="C1D7D7AF705731B0" stid="-1" dopt="3">
<pqr>
<dru fo="1" fps="1" nku="WBECDD6CC37656E6C9" tt="1"/>
<dpo drpr="67" dpi="16"/>
<dres >
<dre dreid="BB:8D679D3511D3E4981000E787EC6DE8A4:1:1:0:2:1" fa="1" dpt= "1" o="0"/>
</dres>
</pqr>
</efg>
</cmd>
</cc>
</bb>
</aa>
Condition is:
I can only use inbuilt Java API (java 8) or SAX parser or xmlbuilder
Add condition is based on Parent tag i.e need to check <cmd> then in child need to add <login> because it is not sure always that <efg> tag would always be there with the same name, it could be with any name.
I have tried with DOM parser with following code.
String xml = "xmlString";
//Use method to convert XML string content to XML Document object
Document doc = convertStringToXML( xml );
doc.getDocumentElement().normalize();
Node m = doc.getElementsByTagName("cmd").item(0).getFirstChild();
Attr login = doc.createAttribute("login");
login.setValue("123567");
m.appendChild(login);
However, I am getting following error in my last line of code.
Exception in thread "main" org.w3c.dom.DOMException: HIERARCHY_REQUEST_ERR: An attempt was made to insert a node where it is not permitted.
Please anyone suggest me, how to add new attribute login into based on my condition no 2.
NodeList nodeList = doc.getElementsByTagName("cmd");
//Check <cmd> tag is present and then check <cmd> tag has child nodes
if (nodeList != null && nodeList.item(0).hasChildNodes()) {
//Get first child node of <cmd> xml tag
String nodeName = doc.getElementsByTagName("cmd").item(0).getFirstChild().getNodeName();
NodeList childNodeList = doc.getElementsByTagName(nodeName);
Element el = (Element) childNodeList.item(0);
//set pgd_login attribute with respective value
el.setAttribute("login", "xyz");
//Convert back into xml string from Document
xml = XMLHelpers.TransformDOMDocumentToString(doc);
}

Xpath insert sequence of nodes under a node - Java

I am trying to add sequence of nodes under a node, below is my reference xml:
<?xml version="1.0" encoding="UTF-8"?>
<transformation>
<info>
<name>Bulkload</name>
<description/>
<extended_description/>
<trans_version/>
<trans_type>Normal</trans_type>
<trans_status>0</trans_status>
<directory>/</directory>
</info>
<connection>
<name>con_name</name>
<server>server</server>
<type>SYBASE</type>
<access>Native</access>
<database>database</database>
<port>port</port>
<username>user</username>
<password>Encrypted xyz</password>
</connection>
<step>
<name>Extract</name>
<type>TextFileOutput</type>
<fields>
**HERE**
<field>
</field>
</fields>
<cluster_schema/>
<remotesteps> <input> </input> <output> </output> </remotesteps> <GUI>
<xloc>300</xloc>
<yloc>168</yloc>
<draw>Y</draw>
</GUI>
</step>
</transformation>
I want to add below xml block inside field tag:
<field>
<name>field_name</name>
<type>Integer</type>
<format>#;-#</format>
<currency/>
<decimal>.</decimal>
<group>,</group>
<nullif/>
<trim_type>none</trim_type>
<length>9</length>
<precision>0</precision>
</field>
My requirement is to create new xml documents from the above template. I only found a method in Xpath to insert node before a node so I updated my template and added a blank field node in it inside fields node and with that I was able to insert a node with the below code:
File dest =new File("H:\\Project_Documents\\reference.ktr");
DocumentBuilderFactory factory = DocumentBuilderFactory
.newInstance();
factory.setIgnoringComments(true);
DocumentBuilder builder = factory.newDocumentBuilder();
String newLine = System.getProperty("line.separator");
Document document = builder.parse(dest);
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();
NodeList nodes = document.getElementsByTagName("field");
Text a = document.createTextNode("Anup");
Element p =document.createElement("field");
p.appendChild(a);
nodes.item(0).getParentNode().insertBefore(p, nodes.item(0));
but again I faced the dame problem for child nodes i.e name, type, format, etc. Could anybody please show me a way to achieve my purpose?
If I cannot achieve it with Xpath then which parser I should use?
One solution, which works:
You have to manage two XML Documents, find the tag you want, and replace.
With XPath you can select more precisely, but no use there.
1 get a DOM for your global XML
Document document= ...
2 get the node you want to insert
Document document_to_insert = builder.parse(new InputSource(new StringReader(xml_to_insert))); // ...
//GET NODE field
NodeList nodes_field_to_insert=document_to_insert.getElementsByTagName("field");
Element node_field_to_insert=null;
for(int i=0; i<nodes_field_to_insert.getLength(); i++)
{
Node the_node = nodes_field_to_insert.item(i);
// WE TAKE THE FIRST ONE
if(the_node instanceof Element)
{
node_field_to_insert=(Element) the_node;
break;
}
}
3 go to the field node in the global XML
4 replace inside the node
// GET NODE field
NodeList nodes=document.getElementsByTagName("field");
for(int i=0; i<nodes.getLength(); i++)
{
Node the_node = nodes.item(i);
if(the_node instanceof Element)
{
Element a_child = (Element) the_node;
Node newNode = document.importNode(node_field_to_insert, true);
// FATHER
Node the_parent=a_child.getParentNode();
the_parent.replaceChild(newNode,a_child);
// WE STOP
break;
}
}

CreateTextNode escape characters in large text string

charactersI am trying to include the correct characters in an XML document text node:
Element request = doc.createElement("requestnode");
request.appendChild(doc.createTextNode(xml));
rootElement.appendChild(request);
The xml string is a segment of a large xml file which I have read in:
Document doc = docBuilder.newDocument();
Element rootElement = doc.createElement("rootnode");
doc.appendChild(rootElement);
<firstname>John</firstname>
<dateOfBirth>28091999</dateOfBirth>
<surname>Doe</surname>
The problem is that passing this into createTextNode is replacing some of the charters:
<firstname>John</firstname>
<dateOfBirth>28091999</dateOfBirth>
<surname>Doe</surname>
Is there any way I can keep the correct characters (< , >) in the textnode. I have read about using importnode but this is not correctly XML, only a segment of a file.
Any help would be greatly appreciated.
EDIT: I need the xml string (which is not fully formatted xml, only a segment of an external xml file) to be in the "request node" as I am building XML to be imported into SOAP UI
You can't pass the element tag and text to the createTextNode() method. You only need to pass the text. You need then to append this text node to an element.
If the source is another XML document, you must extract the text node from an element and insert it in to the other. You can grab a Node (element and text) and try to inserted as a text node in the other. That is why you are seeing all the escape characters.
On the other hand, you can insert this Node into the other XML (if the structure is allowed) and it should be just fine.
In your context, I assume "request" is some sort of Node. The child element of a Node could be another element, text, etc. You have to be very specific.
You can do something like:
Element name = doc.createElement("name");
Element dob = doc.createElement("dateOfBirth");
Element surname = doc.createElement("surname");
name.appendChild( doc.createTextNode("John") );
dob.appendChild( doc.createTextNode("28091999") );
surname.appendChild( doc.createTextNode("Doe") );
Then you can add these element to a parent node:
node.appendChild(name);
node.appendChild(dob);
node.appendChild(surname);
UPDATE: As an alternative, you can open a stream to a document and insert your XML string as a byte stream. Something like this (untested code, but close):
String xmlString = "<firstname>John</firstname><dateOfBirth>28091999</dateOfBirth><surname>Doe</surname>";
DocumentBuilderFactory fac = javax.xml.parsers.DocumentBuilderFactory.newInstance();
DocumentBuilder builder = fac.newDocumentBuilder();
Document newDoc = builder.parse(new ByteArrayInputStream(xmlString.getBytes()));
Element newElem = doc.createElement("whatever");
doc.appendChild(newElem);
Node node = doc.importNode(newDoc.getDocumentElement(), true);
newElem.appendChild(node);
Something like that should do the trick.

Reading XML in java using DOM

I am new to read XML in Java using DOM. Could someone help me with simple code steps to read this XML in DOM?
Here is my XML:
<DataSet xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:noNamespaceSchemaLocation='datamartschema.1.3.xsd'>
<DataStream title='QUESTIONNAIRE'>
<Record>
<TransactionDate>2014-05-28T14:17:31.2186777-06:00</TransactionDate><SubType>xhaksdj</SubType>
<IntegerValue title='ComponentID'>11111</IntegerValue>
</Record><Record>
<TransactionDate>2014-05-28T14:17:31.2186777-06:00</TransactionDate><SubType>jhgjhg</SubType>
<IntegerValue title='ComponentID'>11111</IntegerValue>
</Record>
</DataStream>
</DataSet>
In this XML I need to read the DataStream value and Record values. My expected output is
DataStream=QUESTIONNAIRE and my records are
<TransactionDate>2014-05-28T14:17:31.2186777-06:00</TransactionDate><SubType>xhaksdj</SubType><IntegerValue title='ComponentID'>11111</IntegerValue><TransactionDate>2014-05-28T14:17:31.2186777-06:00</TransactionDate><SubType>jhgjhg</SubType><IntegerValue title='ComponentID'>11111</IntegerValue>
How can I get this output? I tried myself but I can't get the records output like above. I get the output without Tags which are present in the above output.I am using this line to get the output. But it does not give me correct output. Also, how to read the datastream value from this XML? Kindly help me.
This is my code snippets
NodeList datasetallRecords = indElement.getElementsByTagName("Record");
for (int y = 0; y < datasetallRecords.getLength(); y++) {
Element recordsElement = (Element) datasetallRecords.item(y);
recordXMl = recordXMl + recordsElement.getTextContent();
String d = datasetallRecords.item(y).getTextContent();
if (recordsElement.getTagName().equalsIgnoreCase("SubType")) {
lsDataStreamSubTypes.add(recordsElement.getTextContent());
}
recordCount = y;
}
When you create new instance of builder you can get DataStream
it would be look like this:
Element root = document.getDocumentElement();
NodeList dataStreams = root.getElementsByTagName("DataStream");
then get throw this list and get all info like this:
for (int i = 0; i < dataStreams.lenght(); i++) {
Element dataStream = (Element) dataStreams.item(i);
if (dataStream.getNodeType() == Element.ELEMENT_NODE) {
String title = dataStream.getAttributes()
.getNamedItem("title").getTextContent();
}
}
First you need to create a Node like this
Node nNode = datasetallRecords.item(y);
then an element like this
Element eElement = (Element) nNode;
now you can start taking the values from the element by using the getelementbyid and getnodevalue method.
You're not getting the tags because the call to getTextContent() on the "Record" node will return only the textual content of that node and its descendants.
If you need to nodes as well you'll have to process the XML by hand. Have a look at the DOM tutorial it covers processing a document in DOM mode very well including how to read out element names.

Inserting a node in an xml file

I would like to insert a node in an xml file using Java DOM. I am actually editing a lot of contents of a dummy file in order to mofidy it like the original.
I would want to add an open node and close node in between the following file;
<?xml version="1.0" encoding="utf-8"?>
<Memory xmlns:xyz="http://www.w3.org/2001/XMLSchema-instance"
xmlns:abc="http://www.w3.org/2001/XMLSchema" Derivative="ABC"
xmlns="http://..">
///////////<Address> ///////////(which I would like to insert)
<Block ---------
--------
-------
/>
////////// </Address> /////////(which I would like to insert)
<Parameters Thread ="yyyy" />
</Memory>
I hereby request you to let me know how to I insert -- in between the xml file?
Thanks in advance.!
What I have tried doing is;
Element child = doc.createElement("Address");
child.appendChild(doc.createTextNode("Block"));
root.appendChild(child);
But this gives me an output like;
<Address> Block </Address> and not the way i expect :(
And now, what I have tried is to add these lines;
Element cd = doc.createElement("Address");
Node Block = root.getFirstChild().getNextSibling();
cd.appendChild(Block);
root.insertBefore(cd, root.getFirstChild());
But still, this is not the output which i am looking for. I got this output as
---------
What you want is probably:
Node parent = block.getParentNode()
Node blockRemoved = parent.removeChild(block);
// Create address
parent.appendChild(address);
address.appendChild(blockRemoved);
This is the standard way to re-attach a node in another place under W3C DOM.
Here:
DocumentBuilder b = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document document = b.parse(...);
// Parent of existing Block elements and new Address elemet
// Might be retrieved differently depending on
// actual structure
Element parent = document.getDocumentElement();
Element address = document.createElement("address");
NodeList nl = parent.getElementsByTagName("Block");
for (int i = 0; i < nl.getLength(); ++i) {
Element block = (Element) nl.item(i);
if (i == 0)
parent.insertBefore(address, block);
parent.removeChild(block);
address.appendChild(block);
}
// UPDATE: how to pretty print
LSSerializer serializer =
((DOMImplementationLS)document.getImplementation()).createLSSerializer();
serializer.getDomConfig().setParameter("format-pretty-print", Boolean.TRUE);
LSOutput output =
((DOMImplementationLS)document.getImplementation()).createLSOutput();
output.setByteStream(System.out);
serializer.write(document, output);
I assume you are using the W3C DOM (e.g. http://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html ). If so try
insertBefore(address, block);

Categories