1

I would like to parse an xml file and i'm using Java and xpath evaluation.

I would like to output the current's node sibling with an xpath expression and without using getNextSibling() function, is that possible?

e.g. if we read the name element i would like to add the xpath expression ="./address" in order to output the sibling of "name" without using getNextSibling()/.

The xml file is as follows:

  <root>            
        <name>
        <address>
        <profession>
  </root>

My code is as follows:

  package dom_stack4;

  import org.w3c.dom.*;
  import javax.xml.xpath.*;
  import javax.xml.parsers.*;
  import java.io.IOException;
  import org.xml.sax.SAXException;


  public class Dom_stack4 {

public static void main(String[] args) throws ParserConfigurationException,       SAXException, 
    IOException, XPathExpressionException {
    // TODO code application logic here


    DocumentBuilderFactory domFactory = 
    DocumentBuilderFactory.newInstance();
    domFactory.setNamespaceAware(true); 
    DocumentBuilder builder = domFactory.newDocumentBuilder();
    Document doc = builder.parse("root.xml");
    XPath xpath = XPathFactory.newInstance().newXPath();
     // XPath Query for showing all nodes value
    XPathExpression expr = xpath.compile("/root/name/text()");

    Object result = expr.evaluate(doc, XPathConstants.NODESET);
    NodeList nodes = (NodeList) result;
    for (int i = 0; i < nodes.getLength(); i++) {
          System.out.println(" Name is : " +  nodes.item(i).getNodeValue()); 

          /* IS that possible here ?? */
         /* ./address/text() => outputs the current's node sibling */
          expr = xpath.compile("./address/text()");
          Object result1 = expr.evaluate(doc, XPathConstants.NODESET);
          NodeList nodes1 = (NodeList) result1;
           for (int j = 0; j < nodes1.getLength(); j++) {
               System.out.println(" ---------------- " + nodes1.item(j).getNodeValue()); 
              }

    }
    }
    }

Thanks, in advance

1 Answer 1

2

First off, it would be good if you were running your code using properly formed xml, the name address and profession tags should be closed or you will get an error when you try to parse it. Secondly, if you want to select the text child of the node, you need to make sure there is actually something there, so your xml should look something like this:

<root>
    <name>hi</name>
    <address>hi</address>
    <profession>hi</profession>
</root>

Now, what you have for selecting the text of the name element is fine, so starting with your IS that possible here ?? comment there are some changes you need to make.

If you want to evaluate a relative XPath, you don't want to be passing your document object to the XPath's evaluate method. The current location that the XPath is being evaluated from is determined by the item that you give to it, and the document object is always evaluated at the root. If you want to evaluate relative to a specific node, rather than giving it the document, give it that node.

So you would have something like this for your evaluate method call:

Object result1 = expr.evaluate(nodes.item(i), XPathConstants.NODESET);

Next, you should make sure that your XPath is actually correct. The node that we currently have selected is the text node of name. Which means we need to first go to the name node instead of the text node. The . expression in XPath syntax selects the current node, so all you are doing with that is selecting the same node. You want the .. expression which selects the parent node.

So with our current XPath of .. we are selecting the name node. What we want to do is select address nodes that are sibilings of the name node. There are two ways we can do this, we could select the parent of the name node, the root node, and select address nodes that are children of that, or we could use an XPath axis to select the siblings (information about axes can be found here http://www.w3schools.com/xpath/xpath_axes.asp)

If we are going through the root node, we would need to select the parent of the parent of our current node so ../.. which gives us the root node, followed by the address children: ../../address/text(), which would give us all address siblings.

Alternatively, using an axis, we could do .. to select the name node followed by ../following-sibling::address (NOTE: this only works if the address nodes are after the name node) and then select the text of the address nodes with ../following-sibling:address/text().

This gives us those two lines as either

expr = xpath.compile("../../address/text()"); 
Object result1 = expr.evaluate(nodes.item(i), XPathConstants.NODESET);

or

expr = xpath.compile("../following-sibling::address/text()");
Object result1 = expr.evaluate(nodes.item(i), XPathConstants.NODESET);
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.