4

Say I have the following XML file:

<?xml version="1.0" encoding="utf-8"?> <venues> <group type="Nearby"> <venue> <id>222307</id> <name>Union Chapel</name> <primarycategory> <id>78967</id> <fullpathname>Arts &amp; Entertainment:Music Venue</fullpathname> <nodename>Music Venue</nodename> <iconurl>http://foursquare.com/img/categories/arts_entertainment/musicvenue.png</iconurl> </primarycategory> <address>Compton Ave</address> <city>Islington</city> <state>Greater London</state> <zip>N1 2XD</zip> <verified>false</verified> <geolat>51.5439732</geolat> <geolong>-0.1020908</geolong> <stats> <herenow>0</herenow> </stats> <phone>02073594019</phone> <distance>33</distance> </venue> 

.............

and my code is the following:

 XPathFactory factory = XPathFactory.newInstance(); XPath xpath = factory.newXPath(); XPathExpression expr = xpath.compile("//venue/*"); Object result = expr.evaluate(document, XPathConstants.NODESET); NodeList nodes = (NodeList) result; //System.out.println(nodes.getLength()); Venue ven = new Venue(); for (int i = 0; i < nodes.getLength(); i++) { String nodeName = nodes.item(i).getNodeName(); String nodeValue = nodes.item(i).getNodeValue(); if (nodeName.equals("id")){ ven = new Venue(); if (nodeValue != null) ven.id = Integer.parseInt(nodeValue); System.out.println(ven.id); } if (nodeName.equals("name")){ ven.name = nodeValue; System.out.println(ven.name); } if (nodeName.equals("address")){ ven.address = nodeValue; System.out.println(ven.address); } 

How can I do all of this in one for loop for efficiency? Otherwise for every attribute in the xml that I want to extract I need to create a for loop for each one of them

    2 Answers 2

    6

    If you use this as your xpath:

    //venue/* 

    You'll get all the child nodes of venue. You can then iterate over this and do a big if else on the node name's and assign them as needed.

    Like this:

    XPathFactory factory = XPathFactory.newInstance(); XPath xpath = factory.newXPath(); XPathExpression expr = xpath.compile("//venue/*"); Object result = expr.evaluate(document, XPathConstants.NODESET); NodeList nodes = (NodeList) result; for (int i = 0; i < nodes.getLength(); i++) { Node node = nodes.item( i ); String nodeName = node.getNodeName(); String nodeValue = node.getChildNodes().item( 0 ).getNodeValue(); if( nodeName.equals( "name" ) ) { name = nodeValue; } else if( nodeName.equals( "address" ) ) { address = nodeValue; } // ... the rest goes here } 

    If you don't want to iterate over all child elements you could do something like this:

     XPathExpression expr = xpath.compile( "//venue" ); Object result = expr.evaluate( document, XPathConstants.NODESET ); NodeList nodes = (NodeList)result; for( int i = 0; i < nodes.getLength(); i++ ) { Node node = nodes.item( i ); NodeList venueChildNodes = node.getChildNodes(); String id = venueChildNodes.item( 1 ).getChildNodes().item( 0 ).getNodeValue(); System.out.println( "id: " + id ); String name = venueChildNodes.item( 3 ).getChildNodes().item( 0 ).getNodeValue(); System.out.println( "name: " + name ); String address = venueChildNodes.item( 7 ).getChildNodes().item( 0 ).getNodeValue(); System.out.println( "address: " + address ); } 

    Where you get all venue nodes and then map it's children. Though, this approach would require a fairly consistent xml structure. Though, something like this seems safest to me:

     XPathExpression expr = xpath.compile( "//venue" ); Object result = expr.evaluate( document, XPathConstants.NODESET ); NodeList nodes = (NodeList)result; for( int i = 0; i < nodes.getLength(); i++ ) { Node node = nodes.item( i ); NodeList venueChildNodes = node.getChildNodes(); String address = null; String name = null; for( int j = 0; j < venueChildNodes.getLength(); j++ ) { Node item = venueChildNodes.item( j ); String nodeName = item.getNodeName(); if ( nodeName.equals( "address" ) ) { address = item.getChildNodes().item( 0 ).getNodeValue(); } if ( nodeName.equals( "name" ) ) { name = item.getChildNodes().item( 0 ).getNodeValue(); } } System.out.println( "address: " + address ); System.out.println( "name: " + name ); } 
    9
    • If you do much xpath, I'd highly recommend getting sketchpath. It's a free tool that is well worth using IMHO (there is a free version out there, but it looks like they're now pushing a pro version).CommentedNov 2, 2010 at 23:11
    • why is it that I get 120 as the nodesLength, while there are only 10 venues... ? I have a class called venue and I want to store this information in those classCommentedNov 2, 2010 at 23:36
    • Because //venue means "venue, anywhere in the dom tree". So, //venue/* means "venue, anywhere in the dom tree all of it's children". My guess is that when you're checking the node name you'll need to do a "reset" as you've entered into another instance of venue.CommentedNov 2, 2010 at 23:41
    • I would take a look at XStream - it's a pretty handy little library for XML <-> Object mapping.CommentedNov 2, 2010 at 23:42
    • what do you mean by reseting it again? can you show how to do that in your code example above?CommentedNov 2, 2010 at 23:46
    4

    You can combine them like:

    //venue/address/text()|//venue/name/text() 

    This will return the nodes in document order and you can simply iterate over them.

      Start asking to get answers

      Find the answer to your question by asking.

      Ask question

      Explore related questions

      See similar questions with these tags.