16

I have the following xml file:

<resources>
    <resource id="res001">
        <property name="propA" value="A" />
        <property name="propB" value="B" />
    </resource>
    <resource id="res002">
        <property name="propC" value="C" />
        <property name="propD" value="D" />
    </resource>
    <resource id="res003">
        <property name="propE" value="E" />
        <property name="propF" value="F" />
    </resource>
</resources>

How can I do something like this with Java/Xml:

Xml xml = new Xml("my.xml");
Resource res001 = xml.getResouceById("res003");
System.out.println("propF: " + res.getProperty("propF"));

So it prints:

F

I have tried apache commons-configurations XMLConfiguration with XPathExpressionEngine, but I just can't make it work. I have googled and found some examples, but neither would work :( I'm looking for a solution where I don't need to loop through all the elements.

Regards, Alex

3
  • Slightly off topic, but is there any particular reason you store your properties as individual elements and not as attributes? <resource id="res003" propE="E" propF="F"/> Commented Dec 15, 2011 at 23:32
  • I don't recognize that format. What is it? Commented Dec 15, 2011 at 23:40
  • Emil, It feels most natural this way. any other suggestions? Commented Dec 16, 2011 at 11:13

7 Answers 7

19

This is trivial, assuming you're willing to re-write your properties file into the standard Java format. Assume you have the following in a file called props.xml:

<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
    <comment>This is a comment</comment>
    <entry key="propA">A</entry>
    <entry key="propB">B</entry>
    <entry key="propC">C</entry>
    <entry key="propD">D</entry>
    <entry key="propE">E</entry>
    <entry key="propF">F</entry>
</properties>

Then read properties from the file like this:

java.util.Properties prop = new Properties();
prop.loadFromXML(new FileInputStream("props.xml"));
System.out.println(prop.getProperty("propF"));
Sign up to request clarification or add additional context in comments.

Comments

2

Thanks for all the answers/suggestions! I tried some of the xml libraries given above and decided to go with the Simple XML library. I found the "Dictionary" utility class especially useful, to avoid looping through all the elements. Elegant and simple :)

Below is how I used it. I hope it can help someone else...

Regards,

Alex

A working example (on Windows Vista):

package demo;

import java.io.File;

import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.core.Persister;

public class Demo {
    public static void main(String[] args) throws Exception {
        File file = new File("c:\\temp\\resources.xml");
        Serializer serializer = new Persister();
        Resources resources = serializer.read(Resources.class, file);

        Resource resource = resources.getResourceByName("res001");
        System.out.println(resource.getProperty("propA"));
        System.out.println(resource.getProperty("propB"));
    }
}

Console window:

A-001
B-001

Resources.java

package demo;

import org.simpleframework.xml.ElementList;
import org.simpleframework.xml.Root;
import org.simpleframework.xml.util.Dictionary;

@Root(name="resources")
public class Resources {
    @ElementList(entry = "resource", inline = true) 
    private Dictionary<Resource> resources = new Dictionary<Resource>();

    public Resources(@ElementList(entry = "resource", inline = true) Dictionary<Resource> resources) {
        this.resources = resources;
}

    public Resource getResourceByName(String name){
        return resources.get(name);
    }
}

Resource.java

package demo;

import org.simpleframework.xml.Attribute;
import org.simpleframework.xml.ElementList;
import org.simpleframework.xml.util.Dictionary;
import org.simpleframework.xml.util.Entry;

public class Resource  implements Entry{
    @Attribute(name = "name") private final String name;
    @ElementList(inline=true, name="property") private Dictionary<Property> properties;

    public Resource(
                    @Attribute(name = "name") String name, 
                    @ElementList(inline=true, name="property") Dictionary<Property> properties) {
            this.name = name;
            this.properties = properties;
    }

    public String getName() {
        return name;
    }

    public String getProperty(String name) {
        return properties.get(name).getValue();
    }
}

Property.java

package demo;

import org.simpleframework.xml.Attribute;
import org.simpleframework.xml.Root;
import org.simpleframework.xml.util.Entry;

@Root
public class Property implements Entry{
    @Attribute(name="name") private String name;
    @Attribute(name="value") private String value;

    public Property(@Attribute(name="name") String name, @Attribute(name="value") String value) {
        this.name = name;
        this.value = value;
    }

    public String getName() {
        return name;
    }

    public String getValue() {
        return value;
    }
}

resources.xml

<resources>
    <resource name="res001">
        <property name="propA" value="A-001" />
        <property name="propB" value="B-001" />
    </resource>
    <resource name="res002">
        <property name="propA" value="A-002" />
        <property name="propB" value="B-002" />
    </resource>
    <resource name="res003">
        <property name="propA" value="A-003" />
        <property name="propB" value="B-003" />
    </resource>
</resources>

Comments

1

I would just use JAXB to bind data into set of objects that have structure similar to your XML document.

Something like:

@XmlRootElement("resources")
public class Resources {
  public List<Resource> resource = new ArrayList<Resource>(); // important, can't be left null
}
public class Resource {
  @XmlAttribute public String id;
  public List<Property> property;
}
// and so on

one possible gotcha is regarding List serialization; there are two modes, wrapped and unwrapped; in your case, you want "unwrapped". Javadocs for annotations should show annotation to define this.

2 Comments

Yeah, but then create an XSD first, and generate the beans.jaxb.java.net/tutorial
No, absolutely not -- if XSD was needed, I'd rather have root canal. Instead, you just define POJOs (with setters and getters; or public fields), and use that. No Schemas involved.
1

There are many ways. One is to do JDOM and xpath. Something like this (from this article: http://onjava.com/onjava/2005/01/12/xpath.html):

SAXBuilder saxBuilder = 
    new SAXBuilder("org.apache.xerces.parsers.SAXParser");
org.jdom.Document jdomDocument =
    saxBuilder.build(new File("somefile");
org.jdom.Attribute levelNode = 
    (org.jdom.Attribute)(XPath.selectSingleNode(
        jdomDocument,
        "/resources/resource[@id='res003']/property[@name='propF']/@value"));
System.out.println(levelNode.getValue());

Did not test it, but should work. For xpath tutorial see http://zvon.org/xxl/XPathTutorial/General/examples.html . Its the best and fastest tutorial.

Take care about the saxbuilder lifecycle, if it is called often.

Comments

0

I redommend the XStream.

It parse the XML in the object with same strutuct.

About XStream

The your object will be:

List<Resources>

while Resourceshave the attributes, with setters and getters, id that is an object Property with attibutes name and value.

Hope this help

Comments

0

If I were you, I would use an interface with your desired methods (getProperty, Resource, etc) and provide an XPath implementation.

Comments

0

There are several parsers you can use. For me these parsers worked fine:

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.