Currently our Java application uses the values held within a tab delimited *.cfg file. We need to change this application so that it now uses an XML file.
What is the best/simplest library to use in order to read in values from this file?
12 Answers
There are of course a lot of good solutions based on what you need. If it is just configuration, you should have a look at Jakarta commons-configuration and commons-digester.
You could always use the standard JDK method of getting a document :
import java.io.File; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; [...] File file = new File("some/path"); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document document = db.parse(file); 3XML Code:
<?xml version="1.0"?> <company> <staff> <firstname>yong</firstname> <lastname>mook kim</lastname> <nickname>mkyong</nickname> <salary>100000</salary> </staff> <staff> <firstname>low</firstname> <lastname>yin fong</lastname> <nickname>fong fong</nickname> <salary>200000</salary> </staff> </company> Java Code:
import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilder; import org.w3c.dom.Document; import org.w3c.dom.NodeList; import org.w3c.dom.Node; import org.w3c.dom.Element; import java.io.File; public class ReadXMLFile { public static void main(String argv[]) { try { File fXmlFile = new File("/Users/mkyong/staff.xml"); DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); Document doc = dBuilder.parse(fXmlFile); doc.getDocumentElement().normalize(); System.out.println("Root element :" + doc.getDocumentElement().getNodeName()); NodeList nList = doc.getElementsByTagName("staff"); System.out.println("----------------------------"); for (int temp = 0; temp < nList.getLength(); temp++) { Node nNode = nList.item(temp); System.out.println("\nCurrent Element :" + nNode.getNodeName()); if (nNode.getNodeType() == Node.ELEMENT_NODE) { Element eElement = (Element) nNode; System.out.println("Staff id : " + eElement.getAttribute("id")); System.out.println("First Name : " + eElement.getElementsByTagName("firstname") .item(0).getTextContent()); System.out.println("Last Name : " + eElement.getElementsByTagName("lastname") .item(0).getTextContent()); System.out.println("Nick Name : " + eElement.getElementsByTagName("nickname") .item(0).getTextContent()); System.out.println("Salary : " + eElement.getElementsByTagName("salary") .item(0).getTextContent()); } } } catch (Exception e) { e.printStackTrace(); } } } Output:
---------------- Root element :company ---------------------------- Current Element :staff Staff id : 1001 First Name : yong Last Name : mook kim Nick Name : mkyong Salary : 100000 Current Element :staff Staff id : 2001 First Name : low Last Name : yin fong Nick Name : fong fong Salary : 200000 I recommended you reading this: Normalization in DOM parsing with java - how does it work?
6What is the best/simplest library to use in order to read in values from this file?
As you're asking for the simplest library, I feel obliged to add an approach quite different to that in Guillaume's top-voted answer. (Of the other answers, sjbotha's JDOM mention is closest to what I suggest).
I've come to think that for XML handling in Java, using the standard JDK tools is certainly not the simplest way, and that only in some circumstances (such as not being able to use 3rd party libraries, for some reason) it is the best way.
Instead, consider using a good XML library, such as XOM. Here's how to read an XML file into a nu.xom.Document object:
import nu.xom.Builder; import nu.xom.Document; import java.io.File; [...] File file = new File("some/path"); Document document = new Builder().build(file); So, this was just a little bit simpler, as reading the file into org.w3c.dom.Document wasn't very complicated either, in the "pure JDK" approach. But the advantages of using a good library only start here! Whatever you're doing with your XML, you'll often get away with much simpler solutions, and less of your own code to maintain, when using a library like XOM. As examples, consider this vs. this, or this vs. this, or this post containing both XOM and W3C DOM examples.
Others will provide counter-arguments (like these) for why sticking to Java's standard XML APIs may be worth it - these probably have merit, at least in some cases, although personally I don't subscribe to all of them. In any case, when choosing one way or the other, it's good to be aware of both sides of the story.
(This answer is part of my evaluation of XOM, which is a strong contender in my quest for finding the best Java XML library to replace dom4j.)
1Is there a particular reason you have chosen XML config files? I have done XML configs in the past, and they have often turned out to be more of a headache than anything else.
I guess the real question is whether using something like the Preferences API might work better in your situation.
Reasons to use the Preferences API over a roll-your-own XML solution:
Avoids typical XML ugliness (DocumentFactory, etc), along with avoiding 3rd party libraries to provide the XML backend
Built in support for default values (no special handling required for missing/corrupt/invalid entries)
No need to sanitize values for XML storage (CDATA wrapping, etc)
Guaranteed status of the backing store (no need to constantly write XML out to disk)
Backing store is configurable (file on disk, LDAP, etc.)
Multi-threaded access to all preferences for free
JAXB is simple to use and is included in Java 6 SE. With JAXB, or other XML data binding such as Simple, you don't have to handle the XML yourself, most of the work is done by the library. The basic usage is to add annotation to your existing POJO. These annotation are then used to generate an XML Schema for you data and also when reading/writing your data from/to a file.
Look into JAXB.
I've only used jdom. It's pretty easy.
Go here for documentation and to download it:
If you have a very very large document then it's better not to read it all into memory, but use a SAX parser which calls your methods as it hits certain tags and attributes. You have to then create a state machine to deal with the incoming calls.
The simplest by far will be Simple , you only need to annotate a single object like so
@Root public class Entry { @Attribute private String a @Attribute private int b; @Element private Date c; public String getSomething() { return a; } } @Root public class Configuration { @ElementList(inline=true) private List<Entry> entries; public List<Entry> getEntries() { return entries; } } Then all you have to do to read the whole file is specify the location and it will parse and populate the annotated POJO's. This will do all the type conversions and validation. You can also annotate for persister callbacks if required. Reading it can be done like so.
Serializer serializer = new Persister(); Configuration configuraiton = serializer.read(Configuration.class, fileLocation); 2Depending on your application and the scope of the cfg file, a properties file might be the easiest. Sure it isn't as elegant as xml but it certainly easier.
Use java.beans.XMLDecoder, part of core Java SE since 1.4.
XMLDecoder input = new XMLDecoder(new FileInputStream("some/path.xml")); MyConfig config = (MyConfig) input.readObject(); input.close(); It's easy to write the configuration files by hand, or use the corresponding XMLEncoder with some setup to write new objects at run-time.
This is what I use. It sits on top of the standard JDK tools, so if it's missing some feature you can always use the JDK version.
This really makes things easier for me. It's especially nice when I'm reading a config file that was saved by and older version of the software, or was manually edited by a user. It's very robust and won't throw an exception if some data is not exactly in the format you expect.
Here's a really simple API that I created for reading simple XML files in Java. It's incredibly simple and easy to use. Hope it's useful for you.