0

I am trying to parse XML in Java using SAX. For that reason, I made myself a UnitTest.

When I try to parse the XML from a File, everything works wonderfully, but when I try to parse the exact same XML from a String the parsing fails and gives me the following Error:

java.net.MalformedURLException: no protocol: <?xml version="1.0" encoding="UTF-8"?>
<root>                                    
    <subnode>                              
        <id>s1</id>                        
        <name>Subnode one</name>           
        <value>11</value>                  
    </subnode>                             
    <subnode>                              
        <id>s2</id>                        
        <name>Subnode two</name>           
        <value>22</value>                  
    </subnode>                             
</root>                                   
    at java.net.URL.<init>(URL.java:586)
    at java.net.URL.<init>(URL.java:483)
    at java.net.URL.<init>(URL.java:432)
    at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:619)
    at com.sun.org.apache.xerces.internal.impl.XMLVersionDetector.determineDocVersion(XMLVersionDetector.java:189)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:812)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:777)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:649)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl.parse(SAXParserImpl.java:333)
    at javax.xml.parsers.SAXParser.parse(SAXParser.java:274)
    at tests.xmlparsing.XMLParserTest.ParseStringTest(XMLParserTest.java:89)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:211)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)

My UnitTest-File: http://pastebin.com/vd2zjWHu

package tests.xmlparsing;

import org.junit.Test;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import java.io.*;
import java.util.LinkedList;
import java.util.List;
import javax.xml.parsers.*;

import static org.junit.Assert.*;

/**
 * Created by simonlammer on 14.03.15.
 */
public class XMLParserTest {
    private static SAXHandler handler;
    private static String xmlString;
    static {
        handler = new SAXHandler();
        xmlString =
            "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "\r\n" +
            "<root>                                    " + "\r\n" +
            "   <subnode>                              " + "\r\n" +
            "       <id>s1</id>                        " + "\r\n" +
            "       <name>Subnode one</name>           " + "\r\n" +
            "       <value>11</value>                  " + "\r\n" +
            "   </subnode>                             " + "\r\n" +
            "   <subnode>                              " + "\r\n" +
            "       <id>s2</id>                        " + "\r\n" +
            "       <name>Subnode two</name>           " + "\r\n" +
            "       <value>22</value>                  " + "\r\n" +
            "   </subnode>                             " + "\r\n" +
            "</root>                                   ";
    }
    private SAXParser parser;

    public XMLParserTest() throws ParserConfigurationException, SAXException {
        this.parser = newSAXParser();
    }

    private SAXParser newSAXParser() throws ParserConfigurationException, SAXException {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser parser = factory.newSAXParser(); // throws ParserConfigurationException
        return parser;
    }

    @Test
    public void SAXParserNotNullTest() {
        assertNotNull(parser);
    }

    @Test
    public void SAXHandlerNotNullTest() {
        assertNotNull(handler);
    }

    @Test
    public void ParseFileTest() throws IOException, SAXException {
        // create File
        File file = new File("temporaryXMLFileUsedForUnitTest.xml");
        try {
            FileWriter fw = new FileWriter(file);
            fw.write(xmlString);
            fw.flush();
            fw.close();
        } catch (IOException e) {
            fail("Could not create file");
        }

        // parse
        handler.clearElements();
        parser.parse(file, handler);
        List<SampleElement> elements = handler.getElements();

        // validate
        validateElementList(elements);

        // delete file
        file.delete();
    }

    @Test
    public void ParseStringTest() throws IOException, SAXException {
        // parse
        handler.clearElements();
        parser.parse(xmlString, handler);
        List<SampleElement> elements = handler.getElements();

        // validate
        validateElementList(elements);
    }

    private void validateElementList(List<SampleElement> elements) {
        assertEquals(2,             elements.size());
        assertEquals("s1",          elements.get(0).getId());
        assertEquals("Subnode one", elements.get(0).getName());
        assertEquals(11,            elements.get(0).getValue());
        assertEquals("s2",          elements.get(1).getId());
        assertEquals("Subnode two", elements.get(1).getName());
        assertEquals(22,            elements.get(1).getValue());
    }

    public static class SampleElement {
        private String id;
        private String name;
        private int value;

        public SampleElement(String id, String name, int value) {
            this.id = id;
            this.name = name;
            this.value = value;
        }

        public String getId() {
            return id;
        }

        public String getName() {
            return name;
        }

        public int getValue() {
            return value;
        }
    }

    public static class SAXHandler extends DefaultHandler {
        private LinkedList<SampleElement> elements;
        private String id;
        private String name;
        private boolean tagId = false;
        private boolean tagName = false;
        private boolean tagValue = false;
        private String value;

        public SAXHandler() {
            elements = new LinkedList<>();
        }

        public void clearElements() {
            elements.clear();
        }

        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
            String str = new String(ch, start, length);
            if (tagId) {
                id = str;
            } else if (tagName) {
                name = str;
            } else if (tagValue) {
                value = str;
            }
        }

        public List<SampleElement> getElements() {
            return (LinkedList<SampleElement>) elements.clone();
        }

        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            if (qName.equalsIgnoreCase("id")) {
                tagId = false;
            } else if (qName.equalsIgnoreCase("name")) {
                tagName = false;
            } else if (qName.equalsIgnoreCase("value")) {
                tagValue = false;

                // create new SampleElement
                if (id != null && name != null && value != null) {
                    int val = Integer.parseInt(value);
                    SampleElement element = new SampleElement(id, name, val);
                    elements.add(element);

                    // clear strings
                    id = name = value = null;
                }
            }
        }

        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
            if (qName.equalsIgnoreCase("id")) {
                tagId = true;
                id = null;
            } else if (qName.equalsIgnoreCase("name")) {
                tagName = true;
                name = null;
            } else if (qName.equalsIgnoreCase("value")) {
                tagValue = true;
                value = null;
            }
        }
    }
}

Question: Why does it work when parsing from a file but not when parsing from a String? How do I parse from a String using the SAX parser, without receiving this error?

Edit: The solution was found by RealSkeptic, thank you very much. The overload which I used was not supposed to be the XML itself, rather a path to a XML-file. In order to solve the problem, I had to change "parser.parse(xmlString), handler);" to "parser.parse(new InputSource(new StringReader(xmlString)), handler);"

1 Answer 1

3

You use

parser.parse(xmlString, handler);

But the documentation of SAXParser.parse(String uri,DefaultHandler dh) clearly tells you that the string to pass it is a URI of where the XML actually is. It is not the XML itself!

If you want to read the XML directly from a string, you need to create an InputSource from the string, and then use the SAXParser.parse(InputSource is,DefaultHandler dh) method.

To create an InputSource from a String, you may use

InputSource is = new InputSource( new StringReader( xmlString ) );

StringReader is a special type of Reader that reads from a string (just as it would from an InputStream).

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.