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();
Related
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
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;
}
}
I have a simple .xml file and need to parse it. The file is the following:
<table name="agents">
<row name="agent" password="pass" login="agent" ext_uid="133"/>
</table>
I need to get values of name, password, login, ext_uid to create a DB record.
What I have done for this:
created an or.w3c.dom.Document:
public Document getDocument(String fileName){
DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
f.setValidating(false);
DocumentBuilder builder = f.newDocumentBuilder();
return builder.parse(new File(fileName));
}
next I'm trying to print values:
document = getDocument(fileName);
NodeList nodes = document.getChildNodes();
for (int i=0; i<nodes.getLength(); i++){
Node node = nodes.item(i);
if(node.getNodeType() == Node.ELEMENT_NODE){
NodeList listofNodes = node.getChildNodes();
for(int j=0; j<listofNodes.getLength(); j++){
if(node.getNodeType() == Node.ELEMENT_NODE){
Node childNode = listofNodes.item(j);
System.out.println(childNode.getNodeValue()+" " + childNode.getNodeName());
}
}
}
}
I use this because I'm trying to find out how to get values: childNode.getNodeValue()+" " + childNode.getNodeName()
but the result is the following:
#text
null row
#text
in the first and te third cases the NodeValue is empty and in the second case it is null, that means, I guess that there no NodeValue at all.
So my question is how to get values of name, password, login, ext_uid?
childNode.getNodeValue() is obviously null as its an empty tag. You have to look for attributes
Node childNode = listofNodes.item(j);
Element e = (Element)childNode;
String name = e.getAttribute("name");
String password= e.getAttribute("password");
String login= e.getAttribute("login");
String ext_uid= e.getAttribute("ext_uid");
The <row> element has no value, it only has attributes. If it had a value it would look more like <row>this would be the value returned from getNodeValue()</row>.
One way to get the data is to iterate the XML node attributes, for example:
NamedNodeMap attrs = childNode.getAttributes();
if (attrs != null) {
for (int k = 0; k < attrs.getLength(); k++) {
System.out.println("Attribute: "
+ attrs.item(k).getNodeName() + " = "
+ attrs.item(k).getNodeValue());
}
}
The output of your code is showing #text due to the carriage returns (\n characters) in the example XML file, which, according the specification, should be preserved. The null in the example output is the empty node value from the value-less <row> element.
Use XPath instead:
XPath xp = XPathFactory.newInstance().newXPath();
System.out.println(xp.evaluate("/table/row/#name", doc));
System.out.println(xp.evaluate("/table/row/#password", doc));
System.out.println(xp.evaluate("/table/row/#login", doc));
System.out.println(xp.evaluate("/table/row/#ext_uid", doc));
I have a xml file
<Response>
<StatusCode>0</StatusCode>
<StatusDetail>OK</StatusDetail>
<AccountInfo>
<element1>value</element1>
<element2>value</element2>
<element3>value</element2>
<elementN>value</elementN>
</AccountInfo>
</Response>
And I want parse my elements in AccountInfo, but I dont know elements tag names.
Now Im using and have this code for tests, but in future I will recieve more elemenets in AccountInfo and I dont know how many or there names
String name="";
String balance="";
Node accountInfo = document.getElementsByTagName("AccountInfo").item(0);
if (accountInfo.getNodeType() == Node.ELEMENT_NODE){
Element accountInfoElement = (Element) accountInfo;
name = accountInfoElement.getElementsByTagName("Name").item(0).getTextContent();
balance = accountInfoElement.getElementsByTagName("Balance").item(0).getTextContent();
}
Heres 2 ways you can do it:
Node accountInfo = document.getElementsByTagName("AccountInfo").item(0);
NodeList children = accountInfo.getChildNodes();
or you can do
XPath xPath = XPathFactory.newInstance().newXPath();
NodeList children = (NodeList) xPath.evaluate("//AccountInfo/*", document.getDocumentElement(), XPathConstants.NODESET);
Once you have your NodeList you can loop through them.
for(int i=0;i<children.getLength();i++) {
if(children.item(i).getNodeType() == Node.ELEMENT_NODE) {
Element elem = (Element)children.item(i);
// If your document is namespace aware use localName
String localName = elem.getLocalName();
// Tag name returns the localName and the namespace prefix
String tagName= elem.getTagName();
// do stuff with the children
}
}
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());
}
}