Obtaining Xpath of all nodes in an xml - java

I have an xml. I want to obtain/print the Xpath(complete) of all the nodes in it using Java. I'm trying to use a DOM parser.
File stocks = new File("File Name");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(stocks);
System.out.println("Parsed successfully");
doc.getDocumentElement();
System.out.println("root of xml file : " + doc.getDocumentElement().getNodeName());
I'm able to get my root node to print, But not its children.

Strangely enough I just wrote a method that could be used for this. This however isn't fully namespace aware, so be warned, it also only works for ELEMENT types.
For this method to work you also need your document to be namespace aware. dbFactory.setNamespaceAware(true);. If you can't have it namespace aware then replace everywhere you see getLocalName() to getTagName().
try {
XPath xpath = XPathFactory.newInstance().newXPath();
// get all nodes in the document
NodeList nList = (NodeList) xpath.evaluate("//*", doc.getDocumentElement() ,XPathConstants.NODESET);
for(int i=0;i<nList.getLength();i++) {
if(nList.item(i).getNodeType() == Node.ELEMENT_NODE)
System.out.println(getElementXPath((Element)nList.item(i), doc.getDocumentElement()));
}
} catch (XPathExpressionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
/**
* Finds the xPath relative to the given node, the relativeTo should always be a parent of elt
* #param elt
* #param relativeTo should be a parent of elt, if it isnt the path from the document root will be returned
* #return
*/
public static String getElementXPath(Element elt, Element relativeTo) {
String path = "";
do {
String xname = elt.getLocalName() + "[" + getElementIndex(elt) + "]";
path = "/" + xname + path;
if(elt.getParentNode() != null && elt.getParentNode().getNodeType() == Element.ELEMENT_NODE)
elt = (Element) elt.getParentNode();
else
elt = null;
} while(elt != null && !elt.equals(relativeTo));
return path;
}
/**
* #param original
* #return the index this element is among its siblings, only accounts for siblings with the same tag name as itself. Used for xpath indexing
*/
private static int getElementIndex(Element original) {
int count = 1;
for (Node node = original.getPreviousSibling(); node != null; node = node.getPreviousSibling()) {
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element element = (Element) node;
if (element.getLocalName().equals(original.getLocalName()) &&
(element.getNamespaceURI() == original.getNamespaceURI() || (element.getNamespaceURI() != null && element.getNamespaceURI().equals(original.getNamespaceURI())))) {
count++;
}
}
}
return count;
}

Related

XML parsing to Java - getting root attribute value

I'm having a slight problem with XML parsing.
I'm creating a function where the parameter is a certain "element" from the XML file.
When found, I want to return the value of the root attribute.
Here's my code:
FileInputStream file = new FileInputStream(new File("C:\\Users\\Grizzly\\Java\\Projet_16_17-20161214\\bdd.xml"));
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(file);
doc.getDocumentElement().normalize();
NodeList nList = doc.getElementsByTagName("type");
for (int temp = 0; temp < nList.getLength(); temp++)
{
Node nNode = nList.item(temp);
if(nNode.toString().equalsIgnoreCase(element))
{
Element eElement = (Element) nNode;
System.out.println("Taxe= "+ eElement.getAttribute("taxe"));
}
}
}
Any idea on how to do this?
Here's my XML file:
<?xml version="1.0"?>
-<types>
-<type id="Nourriture" taxe="0.1">
<element>pomme</element>
<element>fraise</element>
<element>fromage</element>
<element>viande rouge </element>
</type>
-<type id="Matiere Premiere" taxe="0.2">
<element>fer</element>
<element>polypropylene</element>
</type>
-<type id="Element Solide" taxe="0.3">
<element>voiture</element>
<element>planche surf</element>
<element>pistolet</element>
</type>
</types>
In my code, I tried to get the elements of a certain node from the nodelist and then compare it to the the string "element" which is the input of the user, and if they match it will check the attribute value of taxe linked to it.
Thanks in advance.
EDIT: I'm getting closer to what I need:
NodeList nList = doc.getElementsByTagName("type");
for (int temp = 0; temp < nList.getLength(); temp++)
{
Node nNode = nList.item(temp);
NodeList nChildren = nNode.getChildNodes();
Element eElement = (Element) nNode;
for(int i = 0; i < nChildren.getLength(); i++)
{
String onElement = eElement.getElementsByTagName("element").item(i).getTextContent();
if(onElement.equalsIgnoreCase(element))
{
System.out.println("id : " + eElement.getAttribute("id"));
System.out.println("taxe : " + eElement.getAttribute("taxe"));
break;
}
}
}
But it's only reading the first element... and item(i) isn't working.
Any idea?
If I understand you correctly, you are trying to fetch specific attributes (id and taxe) of all the document nodes having at least one child element with specific name (element).
Although the problem can be solved by iterating the DOM and keeping the states, I would rather delegate this task to XPath. A code with XPath will look cleaner and be more maintainable. For example, in order to fetch all elements having attributes id and taxe and a child element element you can use an XPath expression like //*[#id and #taxe element]. The matching nodes are fetched in a single line. You can simply iterate the nodes and collect the attributes as shown in the following example.
Example
public static void main(String args[]) {
String element = args.length > 0 ? args[0] : "element";
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder builder = factory.newDocumentBuilder();
FileInputStream file = new FileInputStream(new File("/some/file.xml"));
Document doc = builder.parse(file);
XPath xPath = XPathFactory.newInstance().newXPath();
String expression = "//*[#id and #taxe and " + element + "]";
NodeList nodeList = (NodeList) xPath.compile(expression)
.evaluate(doc, XPathConstants.NODESET);
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
NamedNodeMap attributes = node.getAttributes();
for (int j = 0; j < attributes.getLength(); j++) {
Node aNode = attributes.item(j);
System.out.printf(
"%s: %s\n",
aNode.getNodeName(),
aNode.getNodeValue()
);
}
}
} catch (Exception e) {
System.err.println(e.getMessage());
System.exit(1);
}
}
Sample Output
id: Nourriture
taxe: 0.1
id: Matiere Premiere
taxe: 0.2
id: Element Solide
taxe: 0.3
Note, the sample above prints all attributes of the parent element. If you want to print only specific ones, you can, obviously, add a trivial check like this:
String aName = aNode.getNodeName();
if (aName.equals("taxe")) { // ...
But you can actually filter out the attributes with XPath:
String expression = "//*[ " + element + "]/#*[name() = 'id' or name() = 'taxe']";
NodeList nodeList = (NodeList) xPath.compile(expression)
.evaluate(doc, XPathConstants.NODESET);
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
System.out.printf("%s: %s\n", node.getNodeName(), node.getNodeValue());
}
The XPath expression above fetches all attribute nodes having names equal to whether id, or taxe. If you want all attributes, simply remove the last condition:
String expression = "//*[ " + element + "]/#*";

Java , XML User Verification Failure

I've been trying to make this work for longer than I'd like to say now and just can't figure out why it won't recognize the password,I get a null pointer exception on this line if (userPassword.getTextContent().equals(password)
Here is the method
public class XML {
public static boolean login(String email, String password) {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse("data.xml");
Element root = document.getDocumentElement();
NodeList nList = root.getChildNodes();
for (int i = 0; i < nList.getLength(); i++) {
Node nNode = nList.item(i);
if (nNode.getNodeType() == Node.ELEMENT_NODE) {
Element users = (Element) nNode;
if (users.getNodeName().compareTo("users") == 0) {
NodeList userList = users.getChildNodes();
for (int j = 0; j < userList.getLength(); j++) {
Node userNode = userList.item(j);
NodeList AttributeList = userNode.getChildNodes();
Node userPassword = AttributeList.item(1);
Node userEmail = AttributeList.item(0);
if (userPassword.getTextContent().equals(password)
&& userEmail.getTextContent().equals(email)) {
return true;
}
}
}
}
}
} catch (ParserConfigurationException | SAXException | IOException e) {
}
return false;
}
Attribute nodes don't have text content but a value. You should use the following construct to retrieve it :
Node userNode = userList.item(j);
String attributeValue = userNode.getAttribute("attributeName")
Alternatively since you already have the attributes Nodes, you could cast them to org.w3c.dom.Attr and use their .getValue() method.

DOM - Missing Element in XML Document

The XML file contains Employee (with empID, empName, empCode). In some situation empCode is missing.
<Employee><Detail><empID>1</empID><empName>Abhi</empName><empCode>One</empCode>
</Detail>
<Detail><empID>2</empID><empName>Amit</empName>
</Detail>
</Employee>
I am getting the Null pointer Exception while calling the getTagValue() method for "empCode" as there is no tag available with the name in XML.
Java Code :
try
{
File xmlFile = new File("New.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(xmlFile);
doc.getDocumentElement().normalize();
NodeList nList = doc.getElementsByTagName("Detail");
for (int temp = 0; temp < nList.getLength(); temp++)
{
Node nNode = nList.item(temp);
if (nNode.getNodeType() == Node.ELEMENT_NODE)
{
Element eElement = (Element) nNode;
EmpDetail empInfo = new EmpDetail();
empInfo.SetEmpID(getTagValue("empID", eElement));
empInfo.SetEmpName(getTagValue("empName",eElement));
empInfo.SetEmpCode(getTagValue("empCode",eElement));
DBConnector.SaveinDB(empInfo);
}
}
}
catch (Exception e)
{
System.out.println("Error: ");
e.printStackTrace();
}
}
private static String getTagValue(String sTag, Element eElement)
{
NodeList nlList = eElement.getElementsByTagName(sTag).item(0).getChildNodes();
Node nValue = (Node) nlList.item(0);
if(nValue == null)
return null;
return insertEscapeSequance(nValue.getNodeValue());
}
private static String insertEscapeSequance(String str)
{
String returnstr = "";
String[] strarr = str.split("'");
returnstr = strarr[0];
for(int i=1;i<strarr.length;i++)
{
returnstr = returnstr + "\\'" + strarr[i];
}
return returnstr;
}
Now I want to save the XML data into sql like this :
1 Abhi One
2 Amit null
I tried so many links but not success. Can someone please help me
If this is possible that there is no such value, then simply handle it like that:
if(getTagValue("empCode",eElement) != null){
empInfo.SetEmpCode(getTagValue("empCode",eElement));
}
Regarding to adding them into SQL, do the same check while creating your statement. As SQL NULL type exists
The problem is caused by eElement.getElementsByTagName(sTag).item(0). The statement returns the first node specified by sTag. In the case of empCode, null is returned, and calling getChildNodes() will raise a null pointer exception.
Try:
Node node = eElement.getElementsByTagName(sTag).item(0);
if (node != null) {
Node nValue = node.getChildNodes().item(0);
if (nValue != null) {
return insertEscapeSequance(nValue.getNodeValue());
}
}
return null;

Getting attribute from XML document

I've looked on here for solutions, but I am still having problems getting this attribute from my xml document. I am trying to fetch the "1" from this: <update-comments total="1">
Here the code that I am using to fetch the other values without attributes:
DocumentBuilder dbBuilder = dbFactory.newDocumentBuilder();
doc = dbBuilder.parse(stream);
doc.getDocumentElement().normalize();
NodeList nodes = doc.getElementsByTagName("update");
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element element = (Element) node;
String update_type = getValue("update-type", element);
String numLikes = null;
String submittedUrl = null;
String comments = null;
if (update_type.equals("SHAR")) {
String shar_user = null;
String timestamp = null;
String id = null;
String updateKey = null;
String numComments = null;
try {
shar_user = getValue("first-name", element)
+ " " + getValue("last-name", element);
timestamp = getValue("timestamp", element);
id = getValue("id", element);
updateKey = getValue("update-key", element);
profilePictureUrl = getValue("picture-url", element);
numLikes = getValue("num-likes", element);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
private static String getValue(String tag, Element element)
{
NodeList nodes = element.getElementsByTagName(tag).item(0)
.getChildNodes();
Node node = (Node) nodes.item(0);
return node.getNodeValue();
}
This function will get an attribute value from an element using the same strategy that you used to find an element. (Note, you solution only works if an element actually exists.)
private static String getAttributeValue(String tag, Element element, String attribute)
{
NodeList nodes = element.getElementsByTagName(tag);
//note: you should actually check the list size before asking for item(0)
//because you asked for ElementsByTagName(), you can assume that the node is an Element
Element elem = (Element) nodes.item(0);
return elem.getAttribute(attribute);
}

Java save / read data from XML - parsing exceptions

My little chat client software uses a XML file to store chat history, my class for handling reading / writing is:
public class History {
public String filePath;
public History(String filePath) {
this.filePath = filePath;
}
public String stripNonValidXMLCharacters(String in ) {
StringBuffer out = new StringBuffer(); // Used to hold the output.
char current; // Used to reference the current character.
if ( in == null || ("".equals( in ))) return ""; // vacancy test.
for (int i = 0; i < in .length(); i++) {
current = in .charAt(i); // NOTE: No IndexOutOfBoundsException caught here; it should not happen.
if ((current == 0x9) ||
(current == 0xA) ||
(current == 0xD) ||
((current >= 0x20) && (current <= 0xD7FF)) ||
((current >= 0xE000) && (current <= 0xFFFD)) ||
((current >= 0x10000) && (current <= 0x10FFFF)))
out.append(current);
}
return out.toString();
}
public synchronized void addMessage(String from, String agentName, String msg, String time, String channel) {
try {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
org.w3c.dom.Document doc = docBuilder.parse(filePath);
Node data = doc.getFirstChild();
org.w3c.dom.Element root = doc.createElement(channel);
org.w3c.dom.Element message = doc.createElement("message");
org.w3c.dom.Element _sender = doc.createElement("sender");
_sender.setTextContent(stripNonValidXMLCharacters(from));
org.w3c.dom.Element _content = doc.createElement("content");
_content.setTextContent(stripNonValidXMLCharacters(msg));
org.w3c.dom.Element _recipient = doc.createElement("recipient");
_recipient.setTextContent(stripNonValidXMLCharacters(agentName));
org.w3c.dom.Element _time = doc.createElement("time");
_time.setTextContent(stripNonValidXMLCharacters(time));
message.appendChild(_sender);
message.appendChild(_content);
message.appendChild(_recipient);
message.appendChild(_time);
root.appendChild(message);
data.appendChild(root);
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File(filePath));
transformer.transform(source, result);
} catch (Exception ex) {
System.out.println(ex.getStackTrace());
// This is being trown randomly
}
}
public synchronized void getHistory(String channel) {
try {
File fXmlFile = new File(filePath);
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
org.w3c.dom.Document doc = dBuilder.parse(fXmlFile);
doc.getDocumentElement().normalize();
NodeList nList = doc.getElementsByTagName(channel);
for (int temp = 0; temp < nList.getLength(); temp++) {
Node nNode = nList.item(temp);
if (nNode.getNodeType() == Node.ELEMENT_NODE) {
org.w3c.dom.Element eElement = (org.w3c.dom.Element) nNode;
if (getTagValue("sender", eElement).contains("Serv1")) {
printServerMsg(getTagValue("content", eElement).replace("%27", "'"), "", getTagValue("time", eElement));
} else {
printMsg(getTagValue("content", eElement).replace("%27", "'"), getTagValue("sender", eElement), getTagValue("time", eElement));
}
}
}
} catch (Exception ex) {
System.out.println("Filling Exception");
// This is also being trown
}
}
public String getTagValue(String sTag, org.w3c.dom.Element eElement) {
NodeList nlList = eElement.getElementsByTagName(sTag).item(0).getChildNodes();
Node nValue = (Node) nlList.item(0);
return nValue.getNodeValue();
}
}
Exception when writing i am getting is:
`INVALID_CHARACTER_ERR: An invalid or illegal XML character is specified.``
And when reading the exception Filling exception
The exception here is java.lang.NullPointerException
Any ideas how i can guarantee that this wont happend? Problem is this basically breaks the whole client currently
Instead of
System.out.println("Filling Exception");
ALWAYS use either
e.printStackTrace();
Or a proper logging framework, like log4j, and log the error properly:
log.error("Filling Exception", e);
Why is this important?
Because by doing this, you could have provided the full stack trace for us...
Also, for escaping Strings to be used as XML content, it is wise to use an already well written, proven utility like the Apache commons StringEscapeUtils instead of reinventing the wheel
EDIT
From OPs comment
Oh thanks, i can now see that the error is in getTagValue()
There are multiple possibilities for NPE here, but the cuplrit is in this line
NodeList nlList = eElement.getElementsByTagName(sTag).item(0).getChildNodes();
the following can be null
eElement.getElementsByTagName(sTag).item(0)
if there is no tag by that name in the document.
From the documentation:
Returns the indexth item in the collection. If index is greater than or equal to the number of nodes in the list, this returns null.
So I'd rewrite the method like this:
public String getTagValue(String sTag, org.w3c.dom.Element eElement) {
Node n = eElement.getElementsByTagName(sTag).item(0);
if(e !=null) {
NodeList nlList = n.getChildNodes();
Node nValue = (Node) nlList.item(0);
if(nValue != null) {
return nValue.getNodeValue();
}
}
return ""; // or return null; if that is more applicable to the use case
}
Also be careful that now this returns an empty string, which might or might not be good: it can go unnoticed that said node does not exist...

Categories