Hi!
I'm a java rookie and I'm trying to learn how to read and write to xml documents. I have a xml-file called tasklist which lies directly in the src directory, at the same level as the executing program but I get the following error:

java.io.FileNotFoundException: tasklist.xml (Det går inte att hitta filen)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(FileInputStream.java:106)
at java.io.FileInputStream.<init>(FileInputStream.java:66)
at nr.xml.stax.read.StaXParser.readTasks(StaXParser.java:35)
at TestRead.main(TestRead.java:9)

and here's the code:

import java.util.List;

import nr.xml.stax.model.Task;
import nr.xml.stax.read.StaXParser;

public class TestRead {
	public static void main(String args[]) {
		StaXParser read = new StaXParser();
		List<Task> readTasks = read.readTasks("tasklist.xml");
		for (Task task : readTasks) {
			System.out.println(task);
		}
	}
}

As I said is the two files in the same directory so I just can't understand why it won't find the file!

All help and comments are welcome!

Dani AI

Generated

Short version: the JVM was looking in the process working directory (your project root), not "next to the .java file", which is why src/tasklist.xml worked with FileInputStream. was right to point you toward loading resources from the classpath, but there are three separate things to understand so the behavior is predictable and safe when you build a JAR.

Explanation and pitfalls

  • FileInputStream with a relative name is resolved against the JVM working directory (check System.getProperty("user.dir")). In your run configuration that happened to be the project root, so src/tasklist.xml matched the physical file.
  • Classpath resources (the approach you want for packaging) must be on the classpath. Putting the XML in a source/resource folder makes the build copy it into the output (bin/ or target/classes). getResourceAsStream looks on the classpath: a leading slash means “from the classpath root”, no slash means “relative to this class’ package”.
  • If getResourceAsStream returns null the parser can fail with confusing errors (including XMLStreamException / MalformedURLException) because the parser may try to resolve system IDs or external entities without a proper base URI. Always check the stream/URL before parsing and use the resource URL as the parser’s base URI if the XML has DOCTYPE/external entities.

Quick checklist to fix and harden

  • Put tasklist.xml where your build will copy it into classes (or use src/main/resources for Maven/Gradle).
  • Prefer classpath access (getResource/getResourceAsStream). Use an absolute path (/tasklist.xml) if it lives at classpath root or a package-relative name if it sits alongside the class.
  • Before parsing, assert the resource is non-null and print the URL (getResource) or user.dir to debug where the JVM is looking.
  • Don’t rely on relative filesystem paths for resources you will ship in a JAR.

This explains why src/tasklist.xml worked during development and why switching to the classpath-based approach (as suggested) is the robust solution for running inside an IDE and after packaging.

Recommended Answers

All 19 Replies

You need this :

List<Task> readTasks = read.readTasks("/tasklist.xml");

Hope it helps.

I still receive the same error :/

So whold you give some information about the readTasks function; or the StaXParser class please!

The StaxParser is based on a tutorial with some slight naming modifications. The code is:

package nr.xml.stax.read;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;

import nr.xml.stax.model.Task;

public class StaxParser {
	static final String DATE = "date";
	static final String ITEM = "item";
	static final String MODE = "mode";
	static final String UNIT = "unit";
	static final String CURRENT = "current";
	static final String INTERACTIVE = "interactive";

	@SuppressWarnings({ "unchecked", "null" })
	public List<Task>  readTasks(String taskFile) {
		List<Task> tasks = new ArrayList<Task>();
		try {
			// First create a new XMLInputFactory
			XMLInputFactory inputFactory = XMLInputFactory.newInstance();
			// Setup a new eventReader
			InputStream in = new FileInputStream(taskFile);
			XMLEventReader eventReader = inputFactory.createXMLEventReader(in);
			// Read the XML document
			Task task = null;

			while (eventReader.hasNext()) {
				XMLEvent event = eventReader.nextEvent();

				if (event.isStartElement()) {
					StartElement startElement = event.asStartElement();
					// If we have a item element we create a new item
					if (startElement.getName().getLocalPart().equals(ITEM)) {
						task = new Task();
						// We read the attributes from this tag and add the date attribute to our object
						Iterator<Attribute> attributes = startElement
								.getAttributes();
						while (attributes.hasNext()) {
							Attribute attribute = attributes.next();
							if (attribute.getName().toString().equals(DATE));
							task.setDate(attribute.getValue());
						}
					}

					if (event.isStartElement()) {
						if (event.asStartElement().getName().getLocalPart()
								.equals(MODE)) {
							event = eventReader.nextEvent();
							task.setMode(event.asCharacters().getData());
							continue;
						}
					}
					if (event.asStartElement().getName().getLocalPart().equals(UNIT)) {
						event = eventReader.nextEvent();
						task.setUnit(event.asCharacters().getData());
						continue;
					}

					if (event.asStartElement().getName().getLocalPart().equals(CURRENT)) {
						event = eventReader.nextEvent();
						task.setCurrent(event.asCharacters().getData());
						continue;
					}

					if (event.asStartElement().getName().getLocalPart().equals(INTERACTIVE)) {
						event = eventReader.nextEvent();
						task.setInteractive(event.asCharacters().getData());
						continue;
					}
				}
				// If we reach the end of an item element we add it to the list
				if (event.isEndElement()){
					EndElement endElement = event.asEndElement();
					if (endElement.getName().getLocalPart().equals(ITEM)){
						tasks.add(task);
					}
				}

			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (XMLStreamException e) {
			e.printStackTrace();
		}
		return tasks;
	}

}

and the Task class looks like this:

package nr.xml.stax.model;

public class Task {
	private String date;
	private String mode;
	private String unit;
	private String current;
	private String interactive;

	public String getDate() {
		return date;
	}

	public void setDate(String date) {
		this.date = date;
	}
	public String getMode() {
		return mode;
	}
	public void setMode(String mode) {
		this.mode = mode;
	}
	public String getUnit() {
		return unit;
	}
	public void setUnit(String unit) {
		this.unit = unit;
	}
	public String getCurrent() {
		return current;
	}
	public void setCurrent(String current) {
		this.current = current;
	}
	public String getInteractive() {
		return interactive;
	}
	public void setInteractive(String interactive) {
		this.interactive = interactive;
	}

	@Override
	public String toString() {
		return "Item [current=" + current + ", date=" + date + ", interactive="
				+ interactive + ", mode=" + mode + ", unit=" + unit + "]";
	}
}

The Task class is still the unmodified code from the tutorial since I haven't gotten it to work yet.

Well there is many ways to resolve this
Tou can do this

InputStream in = getClass().getResourceAsStream(taskFile);

instead of

in= new FileInputStream(taskFile);

And call the readTasks function without slash:

readTasks("yourfile.xml");

here is assumed that all the files are in the same package as you note before.

Hope it helps.

I looked through the code and saw that it wasn't adjusted enough for my program so I made a whole lot of changes and now I don't get the error any longer! Thanks for your time! But I still can't get it to write out the content but that is a problem I will look into myself first :) thank you very much!

Good luck.

Ok, now I've made some major modifications so that it should work properly but when the code comes to the part with all the if's:

if (startElement.getName().getLocalPart().equals(TASK)) { //Here I've tried with System.out.println("!"); but nothing gets printed

None of the if-statements return true. Even though the getLocalPart should return the same as my ITEM variable. any ideas? I'll post the updated StaxParser code below:

package nr.xml.stax.read;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;

import nr.xml.stax.model.Task;

public class StaxParser {
	static final String DATE = "date";
	static final String TASK = "task";
	static final String DEADLINE = "deadline";
	static final String PRIORITY = "priority";
        static final String DESCRIPTION = "description";

	@SuppressWarnings({ "unchecked", "null" })
	public List<Task> readTasks(String taskFile){
		List<Task> tasks = new ArrayList<Task>();

		try {
			// First create a new XMLInputFactory
			XMLInputFactory inputFactory = XMLInputFactory.newInstance();
			// Setup a new eventReader
			InputStream in = new FileInputStream(taskFile);
			XMLEventReader eventReader = inputFactory.createXMLEventReader(in);
			// Read the XML document
			Task task = null;

			while (eventReader.hasNext()) {
				XMLEvent event = eventReader.nextEvent();

				if (event.isStartElement()) {
					StartElement startElement = event.asStartElement();
					// If we have a task element we create a new task
					if (startElement.getName().getLocalPart().equals(TASK)) {
						task = new Task();
						// We read the attributes from this tag and add the date attribute to our object
						Iterator<Attribute> attributes = startElement
								.getAttributes();
						while (attributes.hasNext()) {
							Attribute attribute = attributes.next();
							if (attribute.getName().toString().equals(DATE));
                                                            System.out.println(attribute.getValue());
							task.setDate(attribute.getValue());
						}
					}
					if (event.asStartElement().getName().getLocalPart().equals(DEADLINE)) {
						event = eventReader.nextEvent();
						task.setDeadline(event.asCharacters().getData());
						continue;
					}
					if (event.asStartElement().getName().getLocalPart().equals(PRIORITY)) {
						event = eventReader.nextEvent();
						task.setPriority(event.asCharacters().getData());
						continue;
					}
                                        if (event.asStartElement().getName().getLocalPart().equals(DESCRIPTION)) {
						event = eventReader.nextEvent();
						task.setDesc(event.asCharacters().getData());
						continue;
					}

				}
				// If we reach the end of an item element we add it to the list
				if (event.isEndElement()){
					EndElement endElement = event.asEndElement();
					if (endElement.getName().getLocalPart().equals(TASK)){
						tasks.add(task);
					}
				}

			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (XMLStreamException e) {
			e.printStackTrace();
		}
		return tasks;
	}

}

I should probably post the xml as well to see if the structure is wrong:

<?xml version="1.0" encoding="UTF-8"?>
<tasklist>
    <task date="2007-12-01">
        <deadline>2010-10-01</deadline>
        <priority>2</priority>
        <description>Fixa TODOList programmet!</description>
    </task>
    <task date="2007-12-24">
        <deadline>2010-10-01</deadline>
        <priority>2</priority>
        <description>Ett test med ett till inlägg!</description>
    </task>
</tasklist>

Hi again;
it seem that it works for me:

public class StaxParser {
	static final String DATE = "date";
	static final String TASK = "task";
	static final String DEADLINE = "deadline";
	static final String PRIORITY = "priority";
        static final String DESCRIPTION = "description";

	@SuppressWarnings({ "unchecked", "null" })
	public List<Task> readTasks(String taskFile){
		List<Task> tasks = new ArrayList<Task>();

		try {
			// First create a new XMLInputFactory
			XMLInputFactory inputFactory = XMLInputFactory.newInstance();
			// Setup a new eventReader
			InputStream in = this.getClass().getResourceAsStream(taskFile);
			XMLEventReader eventReader = inputFactory.createXMLEventReader(in);
			// Read the XML document
			Task task = null;

			while (eventReader.hasNext()) {
				XMLEvent event = eventReader.nextEvent();

				if (event.isStartElement()) {
					StartElement startElement = event.asStartElement();
					// If we have a task element we create a new task
                                        
					if (startElement.getName().getLocalPart().equals(TASK)) {
                                            System.out.println(startElement.getName().getLocalPart());
						task = new Task();
						// We read the attributes from this tag and add the date attribute to our object
						Iterator<Attribute> attributes = startElement
								.getAttributes();
						while (attributes.hasNext()) {
							Attribute attribute = attributes.next();
							if (attribute.getName().toString().equals(DATE));
                                                            System.out.println(attribute.getValue());
							task.setDate(attribute.getValue());
						}
					}
					if (event.asStartElement().getName().getLocalPart().equals(DEADLINE)) {
						event = eventReader.nextEvent();
						//task.setDeadline(event.asCharacters().getData());
						continue;
					}
					if (event.asStartElement().getName().getLocalPart().equals(PRIORITY)) {
						event = eventReader.nextEvent();
						//task.setPriority(event.asCharacters().getData());
						continue;
					}
                                        if (event.asStartElement().getName().getLocalPart().equals(DESCRIPTION)) {
						event = eventReader.nextEvent();
						//task.setDesc(event.asCharacters().getData());
						continue;
					}

				}
				// If we reach the end of an item element we add it to the list
				if (event.isEndElement()){
					EndElement endElement = event.asEndElement();
					if (endElement.getName().getLocalPart().equals(TASK)){
						tasks.add(task);
					}
				}

			}
		} /*catch (FileNotFoundException e) {
                e.printStackTrace();
                }*/ catch (XMLStreamException e) {
			e.printStackTrace();
		}
		return tasks;
	}

}

I'll see with the xml file you sent.

Hey! Now it works! Apparently I had to write the src as "src/tasklist.xml". Why is that? Why does it look for "tasklist.xml" outside of the source?

It works too.

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;

//import nr.xml.stax.model.Task;
public class StaxParser {

    static final String DATE = "date";
    static final String TASK = "task";
    static final String DEADLINE = "deadline";
    static final String PRIORITY = "priority";
    static final String DESCRIPTION = "description";

    @SuppressWarnings({"unchecked", "null"})
    public List<Task> readTasks(String taskFile) {
        List<Task> tasks = new ArrayList<Task>();

        try {
            // First create a new XMLInputFactory
            XMLInputFactory inputFactory = XMLInputFactory.newInstance();
            // Setup a new eventReader
            InputStream in = this.getClass().getResourceAsStream(taskFile);
            XMLEventReader eventReader = inputFactory.createXMLEventReader(in);
            // Read the XML document
            Task task = null;

            while (eventReader.hasNext()) {
                XMLEvent event = eventReader.nextEvent();

                if (event.isStartElement()) {
                    StartElement startElement = event.asStartElement();
                    // If we have a task element we create a new task

                    if (startElement.getName().getLocalPart().equals(TASK)) {
                        System.out.println(startElement.getName().getLocalPart());
                        task = new Task();
                        // We read the attributes from this tag and add the date attribute to our object
                        Iterator<Attribute> attributes = startElement.getAttributes();
                        while (attributes.hasNext()) {
                            Attribute attribute = attributes.next();
                            if (attribute.getName().toString().equals(DATE));
                            System.out.println(attribute.getValue());
                            task.setDate(attribute.getValue());
                        }
                    }
                    if (event.asStartElement().getName().getLocalPart().equals(DEADLINE)) {
                        event = eventReader.nextEvent();
                       [B] // please here I commented this instruction for debuging task.setDeadline(event.asCharacters().getData());[/B]
                        continue;
                    }
                    if (event.asStartElement().getName().getLocalPart().equals(PRIORITY)) {
                        event = eventReader.nextEvent();
                        //task.setPriority(event.asCharacters().getData());
                        continue;
                    }
                    if (event.asStartElement().getName().getLocalPart().equals(DESCRIPTION)) {
                        event = eventReader.nextEvent();
                        //task.setDesc(event.asCharacters().getData());
                        continue;
                    }

                }
                // If we reach the end of an item element we add it to the list
                if (event.isEndElement()) {
                    EndElement endElement = event.asEndElement();
                    if (endElement.getName().getLocalPart().equals(TASK)) {
                        tasks.add(task);
                    }
                }

            }
        } /*catch (FileNotFoundException e) {
        e.printStackTrace();
        }*/ catch (XMLStreamException e) {
            e.printStackTrace();
        }
        return tasks;
    }
//Main for just test please remove it after teste
    public static void main(String[] args) throws FileNotFoundException {
        new StaxParser().readTasks("tasklist.xml");
    }
}

Note: I commented some instructions for debuging.
Note: the three files are in the same package.

Test it it works.

Hope it helps

Thank you for your time, I just recently managed to make it work as well :) Do you have any idea why the relative path must have "src/tasklist.xml" instead of just "tasklist.xml" like a I asked in my previous post?

I did not recognize the structure of your project but it works for me just by "fileName.xml" and I put the 3 files in the same package and by using the getResourceAsStream method.

But in all cases you should resolve the path by using gerRessource, or getRessourceAsStream or by using the URL class because I think that the "scr/..." will not be resolved if you make tha jar file.

How do I use getResourceAsStrem? Or do you want me to just google it :P

Hi;
Please take a look to the ocde sent in my previse post you found how to use it:

InputStream in = this.getClass().getResourceAsStream(taskFile);
            XMLEventReader eventReader = inputFactory.createXMLEventReader(in);

Sorry for the late answer. Everytime I try with the getResourceAsStream method I get the following error:

run:
javax.xml.stream.XMLStreamException: java.net.MalformedURLException
        at com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl.setInputSource(XMLStreamReaderImpl.java:218)
        at com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl.<init>(XMLStreamReaderImpl.java:190)
        at com.sun.xml.internal.stream.XMLInputFactoryImpl.getXMLStreamReaderImpl(XMLInputFactoryImpl.java:264)
        at com.sun.xml.internal.stream.XMLInputFactoryImpl.createXMLStreamReader(XMLInputFactoryImpl.java:131)
        at com.sun.xml.internal.stream.XMLInputFactoryImpl.createXMLEventReader(XMLInputFactoryImpl.java:80)
        at nr.xml.stax.read.StaxParser.readTasks(StaxParser.java:36)
        at TaskTableModel.updateContent(TaskTableModel.java:34)
        at Test.<init>(Test.java:56)
        at Test.main(Test.java:89)
Caused by: java.net.MalformedURLException
        at java.net.URL.<init>(URL.java:601)
        at java.net.URL.<init>(URL.java:464)
        at java.net.URL.<init>(URL.java:413)
        at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:650)
        at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startEntity(XMLEntityManager.java:1315)
        at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startDocumentEntity(XMLEntityManager.java:1267)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.setInputSource(XMLDocumentScannerImpl.java:281)
        at com.sun.org.apache.xerces.internal.impl.XMLStreamReaderImpl.setInputSource(XMLStreamReaderImpl.java:205)
        ... 8 more
BUILD SUCCESSFUL (total time: 19 seconds)

Why is that? I can't get it to work. I can't fix it for the Stax Writer either. Please help!

p.s. I implemented the code just as you did:

InputStream in = this.getClass().getResourceAsStream(taskFile);
                        XMLEventReader eventReader = inputFactory.createXMLEventReader(in);

Is it because that I have a completely different project structure? I'm trying to call this from the source folder and this is in nr/xml/stax/read/

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.