I know this was asked many times but I still cannot get it to work. I convert xml string to Document object and then parse it. Here is the code:
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.*;
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
try
{
builder = factory.newDocumentBuilder();
Document document = builder.parse( new InputSource( new StringReader( result ) ) );
Node head = document.getFirstChild();
if(head != null)
{
NodeList airportList = head.getChildNodes();
for(int i=0; i<airportList.getLength(); i++) {
Node n = airportList.item(i);
Element airportElem = (Element)n;
}
}
catch (Exception e) {
e.printStackTrace();
}
When I cast the Node object n to Element I get an exception java.lang.ClassCastException: org.apache.harmony.xml.dom.TextImpl cannot be cast to org.w3c.dom.Element. When I check the node type of the Node object it says Node.TEXT_NODE. I believe it should be Node.ELEMENT_NODE. Am I right?
So how do I convert Node to Element, so I can do something like element.getAttribute("attrName").
Here is my XML:
<?xml version="1.0" encoding="utf-8" ?>
<ArrayOfCity xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
<City>
<strName>Abu Dhabi</strName>
<strCode>AUH</strCode>
</City>
<City>
<strName>Amsterdam</strName>
<strCode>AMS</strCode>
</City>
<City>
<strName>Antalya</strName>
<strCode>AYT</strCode>
</City>
<City>
<strName>Bangkok</strName>
<strCode>BKK</strCode>
</City>
</ArrayOfCity>
Thanks in advance!
I think you need something like this:
NodeList airportList = head.getChildNodes();
for (int i = 0; i < airportList.getLength(); i++) {
Node n = airportList.item(i);
if (n.getNodeType() == Node.ELEMENT_NODE) {
Element elem = (Element) n;
}
}
When I cast the Node object n to Element I get an exception java.lang.ClassCastException: org.apache.harmony.xml.dom.TextImpl cannot be cast to org.w3c.dom.Element. When I check the node type of the Node object it says Node.TEXT_NODE. I believe it should be Node.ELEMENT_NODE. Am I right?
Probably not, the parser is probably right. It means that some of the nodes in what you're parsing are text nodes. For example:
<foo>bar</foo>
In the above, we have a foo element containing a text node. (The text node contains the text "bar".)
Similarly, consider:
<foo>
<bar>baz</bar>
</foo>
If your XML document literally looks like the above, it contains a root element foo with these child nodes (in order):
A text node with some whitespace in it
A bar element
A text node with some more whitespace in it
Note that the bar element is not the first child of foo. If it looked like this:
<foo><bar>baz</bar></foo>
then the bar element would be the first child of foo.
you can also try to "protect" your casting
Node n = airportList.item(i);
if (n instanceof Element)
{
Element airportElem = (Element)n;
// ...
}
but as pointed by others, you have text node, those won't be casted by this method, be sure you don't need them of use the condition to have a different code to process them
Related
I Need to list all the Elements which contain at least one child. For example, in the below XML, H,I,T have at least one child field each. I Need to list out H,I,T only & ignore other parents such as G_GT, Rec etc.
<?xml version="1.0" encoding="UTF-8"?>
<Doc>
<Rec>
<H>
<Key>H</Key>
<F1>1</F1>
<I>
<Key>I</Key>
<F2>08</F2>
<G_GT>
<T>
<Key>T</Key>
<F3>1</F3>
</T>
<T>
<Key>T</Key>
<F3>2</F3>
</T>
</G_GT>
</I>
</H>
</Rec>
</Doc>
The Code should give Output as H,I,T.
I am working on Java with DOM parser. Could anyone suggest how to do this in Java using DOM? I cannot use functions as getElementByTagName etc as I can get XML with different parent & child names. Thus, I have to avoid any hardcoding of child or parent Name.
Regards,
Phil
To find the parent ELEMENT_NODE of an ELEMENT_NODE without a child ELEMENT_NODE you might start with following snippet
NodeList elements = document.getElementsByTagName("*");
Set<String> nodesNames = new LinkedHashSet<>();
for (int i = 0; i < elements.getLength(); i++) {
Node node = elements.item(i);
NodeList nodeList = node.getChildNodes();
for (int j = 0; j < nodeList.getLength(); j++) {
Node currentNode = nodeList.item(j);
if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
nodesNames.add(node.getParentNode().getNodeName());
break;
}
}
}
System.out.println("nodesNames = " + nodesNames);
would produce the output
[H, I, T]
As an example, this is the kind of xml file I have:
<Node>
<Sample A>
...
</Sample A>
<Sample B>
<myType>importantValue</myType>
</Sample B>
...
<Sample Z>
<myValue>16</myValue>
</Sample Z>
<Node>
<Sample A>
...
</Sample A>
<Sample B>
<myType>importantValue</myType>
</Sample B>
...
<Sample Z>
<myValue>16</myValue>
</Sample Z>
How do I make a query similar to "Select myType and myValue where myValue > x"?
I am trying to use xPath to find the right element, and I am sure there is an easy way to do it, but as I am new to queries in XML I dont find a simple way.. Thanks in advance!
Assuming your XML is structured like this:
<Node>
<Sample>
<someValue>sharks</someValue>
</Sample>
<Sample>
<myValue>16</myValue>
</Sample>
<Sample>
<myType>importantValue</myType>
</Sample>
</Node>
<Node>
...
</Node>
...
And Samples are grouped by Node elements, then what you want is to find a specific Node with the properties you want, and then find the values from that same Node that you want.
Here's an XPath expression that gets a Node by Sample/myValue:
//Node[Sample/myValue = '16']
This reads as "get all Nodes whose child Sample's child myValue's value is '16'".
You can add to it to get different values:
//Node[Sample/myValue = '16']/Sample/myType
This changes the return value of the XPath expression, it reads as "get the value from myType, whose parent is Sample, whose parent is a Node whose Sample/myValue's value is '16'".
To get multiple values out of an XPath expression, you can use the | operator to combine multiple expressions together:
//Node[Sample/myValue = '16'] | //Node[Sample/myValue = '15']
This reads as "get all Nodes whose Sample/myValue value is '16' or '15'".
Following are the steps. Hope you didn't missed out them.
Create a Document from a file or stream
StringBuilder xmlStringBuilder = new StringBuilder();
xmlStringBuilder.append("<?xml version="1.0"?> <class> </class>");
ByteArrayInputStream input = new ByteArrayInputStream(
xmlStringBuilder.toString().getBytes("UTF-8"));
Document doc = builder.parse(input);
Build XPath
XPath xPath = XPathFactory.newInstance().newXPath();
Prepare Path expression and evaluate it
String expression = "/Node/SampleB";
NodeList nodeList = (NodeList) xPath.compile(expression).evaluate(doc, XPathConstants.NODESET);
Iterate over NodeList
for (int i = 0; i < nodeList.getLength(); i++) {
Node nNode = nodeList.item(i);
...
}
Examine attributes
//returns specific attribute
getAttribute("attributeName");
//returns a Map (table) of names/values
getAttributes();
Examine sub-elements
//returns a list of subelements of specified name
getElementsByTagName("subelementName");
//returns a list of all child nodes
getChildNodes();
In your case,
String expression = "/Node/SampleB";
for (int i = 0; i < nodeList.getLength(); i++) {
Node nNode = nodeList.item(i);
System.out.println("\nCurrent Element :" + nNode.getNodeName());
if (nNode.getNodeType() == Node.ELEMENT_NODE) {
Element eElement = (Element) nNode;
System.out.println(eElement.getElementsByTagName("myType")
.item(0).getTextContent());}}
I know how to parse XML documents with DOM when they are in the form:
<tagname> valueIWant </tagname>
However, the element I'm now trying to get is instead in the form
<photo farm="9" id="8147664661" isfamily="0" isfriend="0" ispublic="1"
owner="8437609#N04" secret="4902a217af" server="8192" title="Rainbow"/>
I usually use cel.getTextContent() to return the value, but that doesn't work in this case. Neither does cel.getAttributes(), which I thought would work...
Ideally, I need to just get the id and owner numerical values. However if someone can help on how to get all of it, then I can deal with removing the parts I don't want later.
What you're looking to retrieve is the value of different attributes that are attached with an Element. Look at using the getAttribute(String name) method to achieve this
If you want to retrieve all the attributes, all you can do so using getAttributes() and iterate through it. An example of both of these methods might be something like this:
private void getData(Document document){
if(document == null)
return;
NodeList list = document.getElementsByTagName("photo");
Element photoElement = null;
if(list.getLength() > 0){
photoElement = (Element) list.item(0);
}
if(photoElement != null){
System.out.println("ID: "+photoElement.getAttribute("id"));
System.out.println("Owner: "+photoElement.getAttribute("owner"));
NamedNodeMap childList = photoElement.getAttributes();
Attr attribute;
for(int index = 0; index < childList.getLength(); index++){
if(childList.item(index).getNodeType() == Node.ATTRIBUTE_NODE){
attribute = ((Attr)childList.item(index));
System.out.println(attribute.getNodeName()+" : "+attribute.getNodeValue());
}else{
System.out.println(childList.item(index).getNodeType());
}
}
}
}
Something like:
Element photo = (Element)yournode;
photo.getAttribute("farm");
will get you the value of the farm attribute. You need to treat your node as an Element to have access to these attributes (doc).
I am trying to parse an xml file in which there is a group element "patent-assignee" which contains some elements- name, address1, address2,city,state, postcode, country.
While values will always be there for "name" and "address1" the other elements may or may not have values.
I have navigated to a single patent-assignee element, and now want to check if this record has value for address2 (and other fields) or not.
Some relevant code is given below--
el_patentassignees= (Element) npassignee.item(ncount);
//now el_patentassignee has in it the content of one patent assignee element
el_assigneeaddress2= (Element) el_patentassignees.getElementsByTagName("address2").item(0);
val_assigneeaddress2= el_assigneeaddress2.getTextContent();
Iterate through all child nodes of el_assigneeaddress2, then, if you see a Text node, take the value:
NodeList nodeList = el_assigneeaddress2.getChildNodes();
for (int i = 0; i < nodeList.getLength(), i++) {
Node child = nodeList.item(i);
if (child.getName().equals("#text")) {
val_assigneeaddress2= child.getTextContent();
break;
}
}
I want to modify xml file using dom ,but when I make node.getNodeValue(); it returns null !I don't know why? my xml file contains the following tags:
[person] which contains child [name] which contains childs [firstname ,middleInitial ,lastName] childs
I want to update First name , middleInitial and last name using dom
this is my java dom processing file:
NodeList refPeopleList = doc.getElementsByTagName("person");
for (int i = 0; i < refPeopleList.getLength(); i++) {
NodeList personList = refPeopleList.item(i).getChildNodes();
for (int personDetalisCnt = 0; personDetalisCnt < refPeopleList.getLength(); personDetalisCnt++) {
{
currentNode = personList.item(personDetalisCnt);
String nodeName = currentNode.getNodeName();
System.out.println("node name is " + nodeName);
if (nodeName.equals("name")) {
System.out.println("indise name");
NodeList nameList = currentNode.getChildNodes();
for(int cnt=0;cnt<nameList.getLength();cnt++)
{
currentNode=nameList.item(cnt);
if(currentNode.getNodeName().equals("firstName"))
{
System.out.println("MODIFID NAME :"+currentNode.getNodeValue()); //prints null
System.out.println("indide fname"+" node name is "+currentNode.getNodeName()); //prints firstName
String nodeValue="salma";
currentNode.setNodeValue(nodeValue);
System.out.println("MODIFID NAME :"+currentNode.getNodeValue());//prints null
}
}
}
}
Rather than calling getNodeValue() / setNodeValue() on the <firstName> element node, try getting the firstName element's text node child, and call getNodeValue() / setNodeValue() on it.
Try
if(currentNode.getNodeName().equals("firstName"))
{
Node textNode = currentNode.getFirstChild();
System.out.println("Initial value:" + textNode.getNodeValue());
String nodeValue="salma";
textNode.setNodeValue(nodeValue);
System.out.println("Modified value:" + textNode.getNodeValue());
}
From the DOM spec,
The attributes nodeName, nodeValue and
attributes are included as a mechanism
to get at node information without
casting down to the specific derived
interface. In cases where there is no
obvious mapping of these attributes
for a specific nodeType (e.g.,
nodeValue for an Element or attributes
for a Comment), this returns null.
Similarly in the Java docs for the Node interface, the table near the top shows that the nodeValue of an element is null.
This is why using getNodeValue on an element will always return null, and why you need to use getFirstChild() first in order to get the text node (assuming there are no other child nodes). If there is a mixture of element and text child nodes, you can use getNodeType() to check which child is which (text is type 3).
Is it firstName or firstname (watch the case).