updating xml node with JDOM - java

I have problem with updating data in my xml file.
My xml file looks like this :
<root>
<info>
.....
</info>
<OBJECT_TYPE>x2000</OBJECT_TYPE>
<prop>
<DESCRIPTION>fast train</DESCRIPTION>
<PARENT>NULL</PARENT>
<VIRTUAL>0</VIRTUAL>
<VISIBLE>1</VISIBLE>
<PICTURE>NULL</PICTURE>
<HELP>NULL</HELP>
<MIN_NO>1</MIN_NO>
<MAX_NO>1</MAX_NO>
<NAME_FORMAT>NULL</NAME_FORMAT>
</prop>
<param>
<PARAMETER>nidbrc</PARAMETER>
<DATA_TYPE>String</DATA_TYPE>
<DESCRIPTION>super fast</DESCRIPTION>
<MIN_NO>1</MIN_NO>
<MAX_NO>1</MAX_NO>
<ORDER1>1</ORDER1>
<NESTED>1</NESTED>
<DEFAULT1>NULL</DEFAULT1>
<FORMAT>100:45</FORMAT>
</param>
<param>
</param>
<param>
</param>
<param>
</param>
...
</type>
<type>
...
</type>
<type>
</root>
Here i am trying to get my first param from type number 1 and updating the first parameter of 9
public static void main(String[] args) {
File xml = new File("test.xml");
try {
XMLOutputter xmlOut = new XMLOutputter();
Document doc = (Document) new SAXBuilder().build(xml);
Element rootNode = doc.getRootElement();
Element typeContent = rootNode.getChildren().get(1);
System.out.println("typeContent : " + typeContent.getChildren());
for (int i = 0; i < typeContent.getContentSize(); i++) {
List<Element> list = typeContent.getChildren("param");
if (list.size() > 0) {
Element element = list.get(1);
List paramChilds = element.getChildren("PARAMETER");
for (int j = 0; j < paramChilds.size(); j++) {
Element node = (Element) paramChilds.get(j);
System.out.println(node.getText());
// xmlOut.setFormat(Format.getPrettyFormat());
// xmlOut.output(doc, new FileWriter("test.xml"));
}
}
}
} catch (IOException io) {
System.out.println(io.getMessage());
} catch (JDOMException jdomex) {
System.out.println(jdomex.getMessage());
}
What I find hard is to know how to dig into the xml file and therefore this one aint working but this one is null : node.getChild("PARAMETER").setText("Bla");

You could either loop all 'param' children like this:
Document doc = (Document) new SAXBuilder().build(xml);
Element rootNode = doc.getRootElement();
// get all 'param' children
List<Element> paramElements = root.getChildren("param");
for (Element param: paramElements) {
// do something intelligent
param.getChild("PARAMETER").setText("Bla");
}
// write to file
xmlOut.setFormat(Format.getPrettyFormat());
xmlOut.output(doc, new FileWriter("test.xml"));
Or you could use xpath to search for the elements and do stuff with it; example.

Here, you appear to be trying to set the text of the first PARAMETER element which is a child of the first PARAMETER element that is a child of the second child of the root element.
Element rootNode = doc.getRootElement();
...
Element typeContent = rootNode.getChildren().get(1);
...
Element node = typeContent.getChild("PARAMETER");
node.getChild("PARAMETER").setText("Bla");
No such element appears to exist in your example xml.
typeContent corresponds to the element <OBJECT_TYPE>x2000</OBJECT_TYPE>, which has no PARAMETER element children.
There are no PARAMETER elements that are children of
PARAMETER elements.
What's more, for some reason you seem to be doing exactly the same thing 15 times. Why is that?

You are looking for the param Elements like this:
List<Element> list = typeContent.getChildren("param");
But typeContent does not have any param children. typeContent is:
Element typeContent = rootNode.getChildren().get(1);
which, as far as I can tell, is:
<OBJECT_TYPE>x2000</OBJECT_TYPE>
You should, I guess, be looking for the param children like:
List<Element> paramElements = root.getChildren("param");
You should be using JDOM2 and not JDOM. With JDOM2 your XPath option is much simpler:
XPathExpression<Element> paramxpath = XPathFactory.instance()
.compile("/root/param", Filters.element());
for (Element param : paramxpath.evaluate(doc)) {
System.out.println(param.getText());
}

This is my complete solution :
public void updateParameters(int index, int row, int column,
String columnName, Object data) throws Exception {
int objTypeIndex = index + 1;
File xml = new File("xmlFiles/CoreDatamodel.xml");
try {
XMLOutputter xmlOut = new XMLOutputter();
org.jdom2.Document doc = new SAXBuilder().build(xml);
Namespace ns = Namespace.getNamespace("http://www.bombardier.com");
org.jdom2.Element rootNode = doc.getRootElement();
org.jdom2.Element typeContent = rootNode.getChildren().get(
objTypeIndex);
List<Element> list = typeContent.getChildren("param", ns);
if (list.size() > 0) {
Element element = list.get(row);
List paramChilds = element.getChildren(columnName, ns);
Element node = (Element) paramChilds.get(0);
node.setText(data.toString());
System.out.println(node.getText());
xmlOut.setFormat(Format.getPrettyFormat());
xmlOut.output(doc, new FileWriter("xmlFiles/CoreDatamodel.xml"));
}
} catch (IOException io) {
System.out.println(io.getMessage());
} catch (JDOMException jdomex) {
System.out.println(jdomex.getMessage());
}
}

Related

Java, XPath Expression to read all node names, node values, and attributes

I need help in make an xpath expression to read all node names, node values, and attributes in an xml string. I made this:
private List<String> listOne = new ArrayList<String>();
private List<String> listTwo = new ArrayList<String>();
public void read(String xml) {
try {
// Turn String into a Document
Document document = DocumentBuilderFactory.newInstance()
.newDocumentBuilder().parse(new ByteArrayInputStream(xml.getBytes()));
// Setup XPath to retrieve all tags and values
XPath xPath = XPathFactory.newInstance().newXPath();
NodeList nodeList = (NodeList) xPath.evaluate("//text()[normalize-space()='']", document, XPathConstants.NODESET);
// Iterate through nodes
for(int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
listOne.add(node.getNodeName());
listTwo.add(node.getNodeValue());
// Another list to hold attributes
}
} catch(Exception e) {
LogHandle.info(e.getMessage());
}
}
I found the expression //text()[normalize-space()=''] online; however, it doesn't work. When I get try to get the node name from listOne, it is just #text. I tried //, but that doesn't work either. If I had this XML:
<Data xmlns="Somenamespace.nsc">
<Test>blah</Test>
<Foo>bar</Foo>
<Date id="2">12242016</Date>
<Phone>
<Home>5555555555</Home>
<Mobile>5555556789</Mobile>
</Phone>
</Data>
listOne[0] should hold Data, listOne[1] should hold Test, listTwo[1] should hold blah, etc... All the attributes will be saved in another parallel list.
What expression should xPath evaluate?
Note: The XML String can have different tags, so I can't hard code anything.
Update: Tried this loop:
NodeList nodeList = (NodeList) xPath.evaluate("//*", document, XPathConstants.NODESET);
// Iterate through nodes
for(int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
listOne.add(i, node.getNodeName());
// If null then must be text node
if(node.getChildNodes() == null)
listTwo.add(i, node.getTextContent());
}
However, this only gets the root element Data, then just stops.
//* will select all element nodes, //#* all attribute nodes. However, an element node does not have a meaningful node value in the DOM, so you would need to read out getTextContent() instead of getNodeValue.
As you seem to consider an element with child elements to have a "null" value I think you need to check whether there are any child elements:
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
docBuilderFactory.setNamespaceAware(true);
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
Document doc = docBuilder.parse("sampleInput1.xml");
XPathFactory fact = XPathFactory.newInstance();
XPath xpath = fact.newXPath();
NodeList allElements = (NodeList)xpath.evaluate("//*", doc, XPathConstants.NODESET);
ArrayList<String> elementNames = new ArrayList<>();
ArrayList<String> elementValues = new ArrayList<>();
for (int i = 0; i < allElements.getLength(); i++)
{
Node currentElement = allElements.item(i);
elementNames.add(i, currentElement.getLocalName());
elementValues.add(i, xpath.evaluate("*", currentElement, XPathConstants.NODE) != null ? null : currentElement.getTextContent());
}
for (int i = 0; i < elementNames.size(); i++)
{
System.out.println("Name: " + elementNames.get(i) + "; value: " + (elementValues.get(i)));
}
For the sample input
<Data xmlns="Somenamespace.nsc">
<Test>blah</Test>
<Foo>bar</Foo>
<Date id="2">12242016</Date>
<Phone>
<Home>5555555555</Home>
<Mobile>5555556789</Mobile>
</Phone>
</Data>
the output is
Name: Data; value: null
Name: Test; value: blah
Name: Foo; value: bar
Name: Date; value: 12242016
Name: Phone; value: null
Name: Home; value: 5555555555
Name: Mobile; value: 5555556789

JDOM removing a element from root

I am not able to remove an element from root element. Below is the example of xml
<ADMIN-DATA>
<DATA-DECLARATION ID="Hi"> </DATA-DECLARATION>
<DATA ID="Hi">
<DATA-DECLARATION-REF ID-REF="Hi"> </DATA-DECLARATION-REF>
<DATA ID="Hi">
<DATA-DECLARATION ID="Delete"> </DATA-DECLARATION>
</DATA>
</DATA>
</ADMIN-DATA>
I want to delete
<DATA-DECLARATION ID="Delete"> </DATA-DECLARATION>
JDOM Code below
Element root = document.getRootElement();
String id = null;
boolean check = false;
String idRef = null;
ElementFilter filter = new org.jdom2.filter.ElementFilter(
"DATA-DECLARATION");
ElementFilter filter2 = new org.jdom2.filter.ElementFilter(
"DATA-DECLARATION-REF");
for (Element dataDecId : root.getDescendants(filter))
{
check = false;
id = dataDecId.getAttributeValue("ID");
for (Element dataDecIdRef : root.getDescendants(filter2))
{
idRef = dataDecIdRef.getAttributeValue("ID-REF");
if (null != idRef && idRef.equalsIgnoreCase(id))
{
check = true;
break;
}
}
if (!check)
{
root.removeContent(dataDecId);
}
}
Above root.removeContent(dataDecId); is not working. Correct me.
Note that <DATA-DECLARATION ID="Delete"> </DATA-DECLARATION> is not a child of the root element.... it's a child of a DATA element which in turn is a child of a DATA element which finally is a child of the ADMIN-DATA element.
You cannot ask the root element to remove DATA-DECLARATION ID="Delete" because it is not a direct child.
Note that the child itself knows it's location, so, the simpler way to do it, is to change root.removeContent(dataDecId) to be just dataDecId.detach()
Well, to me it looks like there are some errors in the .xml file. You're trying to get the ID-REF field whereas Delete only has an ID.
Moreover, I doubt that your XML file is correct considering you have a typo here:
<DATA-DECLARATION-REF ID-REF="Hi"> </ATA-DECLARATION-REF>
and two different tags here:
<DATA-DECLARATION ID="Delete"> </DATA-DECLARATION-REF>.
Another way:
XPATH combines tag and values in a clear way:
XPath xPath = XPathFactory.newInstance().newXPath();
String expression="//DATA-DECLARATION[#ID='Delete']"; // self-explained
NodeList nodes = (NodeList) xPath.compile(expression).evaluate(document, XPathConstants.NODESET);
for(int i=0; i<nodes.getLength(); i++)
{
Node the_node = nodes.item(i);
if(the_node instanceof Element)
{
Element the_element=(Element) the_node;
// FATHER
Node father=the_node.getParentNode();
// SUPPRESSION
father.removeChild(the_node);
// First one only ?
break;
}
}

java Convert Element to string

I am looking to get only the tag name, and not it's children.
I have an xml like this:
<RESPONSE>
<RESULT> !--TableName
<ADDRESS1>123 Main Street</ADDRESS1> !--ColumnName
<ZIP>12345</ZIP> !--ColumnName
</RESULT>
<RESULT> !--TableName
<ADDRESS1>245 Elm Street</ADDRESS1> !--ColumnName
<ZIP>45678</ZIP> !--ColumnName
</RESULT>
<VIN> !--TableName
<VIN_NUM>1K45678RTW23</VIN> !--ColumnName
</VIN>
….
</REPSONSE>
I am trying to dynamically save the xml into it's appropriate table and column names. So, I want to extract whatever the first element is, and assign it to a table name variable, and then it's children as columns.
Here is what I am doing so far:
private void extractToTableSet(Document doc, int appseqno ) throws Exception
{
NodeList responseList = doc.getElementsByTagName("RESPONSE");
for (int i = 0; i < responseList.getLength(); i++) {
Node currentNode = responseList.item(i);
if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
Element tableElement = (Element) responseList.item(i);
if (tableElement != null && tableElement.hasChildNodes()) {
for (columnNode = tableElement.getFirstChild(); columnNode != null; columnNode = columnNode.getNextSibling()) {
if (columnNode.getNodeType() == Node.TEXT_NODE) {
columnName = columnNode.getNodeValue;
}
}
}
}
}
}
This way I am only able to get the values in the child nodes. Is there a way to get the name of the Element tags? Like I want to extract the value RESULT from the Document object.
In DOM, an element name is retrieved using Node.getNodeName().
Example:
if(node.getNodeType() == Node.ELEMENT_NODE) {
String elementName = node.getNodeName();
...
}
To get element's tagname :
Element tableElement = (Element) responseList.item(i);
String tagname = tableElement .getTagName();

List of elements in JDOM

I have a question regarding list of elements in xml
I am trying to delete everything under and also the tags.
But when I debug my list of param I noticed my list looks like this :
text
element
text
element
text
element
text
element
But I want only the elements in the list and not the text so I can more easily delete the correct element.
How to do this?
This is my code :
public void deleteParameter(int row, int index) {
int objTypeIndex = index + 1;
File xml = new File(XMLEditorService.getXMLEditorService().getFile());
try {
XMLOutputter xmlOut = new XMLOutputter();
org.jdom2.Document doc = new SAXBuilder().build(xml);
Namespace ns = Namespace.getNamespace("http://www.xxx.com");
org.jdom2.Element rootNode = doc.getRootElement();
org.jdom2.Element typeContent = rootNode.getChildren().get(
objTypeIndex);
List<Element> list = typeContent.getChildren("param", ns);
if (list.size() > 0) {
Element element = list.get(row); //remove correct element
element.removeContent();
System.out.println("element removed: " + element.getName());
xmlOut.setFormat(Format.getPrettyFormat());
xmlOut.output(doc, new FileWriter(XMLEditorService
.getXMLEditorService().getFile()));
}
} catch (IOException io) {
System.out.println(io.getMessage());
} catch (JDOMException jdomex) {
System.out.println(jdomex.getMessage());
}
}
The list i am refering to is this line : List<Element> list = typeContent.getChildren("param", ns);
The method call: element.removeContent(); does not remove the Element from its parent, but instead it removes all content from the element (makes it empty).
You probably just want to do: element.detach(); instead.... which will remove the Element (and as a result all of its content too) from the document.
You could use a JDOM2 filter to get elements of a specific type.
Look at This example to see how to retrieve specific elements of the XML using Filters in JDOM2.

XML to Hashtable

Currently I have the code below to put the data in a Hash.
My question: which value do i have to put in the part of !!!SOMETHING!!!.
The code only has to read one elementtag and insert it's value in the hashtable.
public void ReadXML(){
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(fileout);
doc.getDocumentElement().normalize();
Hashtable hash = new Hashtable();
NodeList dataNodes = doc.getElementsByTagName("DataArea");
// getChildNodes().item(0).getChildNodes();
Element root = doc.getDocumentElement();
String dataNodeIndex = root.toString();
System.out.println("");
for (int dataNodeIndex1 = 0; dataNodeIndex1 < dataNodes.getLength(); dataNodeIndex1++)
{
Node nodeName = dataNodes.item(dataNodeIndex1);
if (nodeName.getNodeType() == Node.ELEMENT_NODE) {
Element elementName = (Element) nodeName;
NodeList elementNameList = elementName.getElementsByTagName(elementtag1);
Element elementName2 = (Element) elementNameList.item(0);
NodeList nameElement = elementName2.getChildNodes();
System.out.println("NodeContent: " + ((Node) nameElement.item(0)).getNodeValue());
}
hash.put(elementtag1, !!!SOMETHING!!!);
System.out.println(hash);
}
}
catch(Exception e){
e.printStackTrace();
}
}
You should use these method that i found :
protected String getString(String tagName, Element element) {
NodeList list = element.getElementsByTagName(tagName);
if (list != null && list.getLength() > 0) {
NodeList subList = list.item(0).getChildNodes();
if (subList != null && subList.getLength() > 0) {
return subList.item(0).getNodeValue();
}
}
return null;
}
use it like this :
if (NodeName.getNodeType() == Node.ELEMENT_NODE) {
Element ElementName = (Element) NodeName;
Hash.put(Elementtag1, getString(Elementtag1, ElementName));
}
Check it out :
http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/
and
How to retrieve element value of XML using Java?
You have chosen incorrect collection type for this operation, if you wanna save your element tag values in Set yes it is better to use HashSet but implementation of HashSet approximately you try to do, so values of Set puts into HashMap like keys, but you can use another collection like List, Queue, Stack try to find better for you.
And maybe SAX will be better DOM for you ...
To make things easier and more robust, you could use a Properties instead, which has an underlying implementation of a Hashtable (it actually extends it) and can import and export to/from XML (see loadFromXML and storeToXML methods). See http://www.ibm.com/developerworks/java/library/j-tiger02254/index.html for details.

Categories

Resources