当String解析时无法解析XML,从File解析时没有问题

时间:2015-04-02 15:08:33

标签: java xml parsing saxparser

我正在尝试使用SAX解析Java中的XML。出于这个原因,我自己做了一个UnitTest。

当我尝试从文件解析XML时,一切都运行得非常好,但是当我尝试从String解析完全相同的XML时,解析失败并给出以下错误:

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)

我的UnitTest文件: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;
            }
        }
    }
}

问题:为什么在从文件解析时却有效,而在从String解析时却没有?如何使用SAX解析器从String解析,而不会收到此错误?

编辑:解决方案是由RealSkeptic发现的,非常感谢。 我使用的重载不应该是XML本身,而是XML文件的路径。 为了解决这个问题,我不得不改变&#34; parser.parse(xmlString),handler);&#34; to&#34; parser.parse(new InputSource(new StringReader(xmlString)),handler);&#34;

1 个答案:

答案 0 :(得分:3)

您使用

parser.parse(xmlString, handler);

SAXParser.parse(String uri,DefaultHandler dh)的{​​{3}}清楚地告诉您传递它的字符串是XML实际所在的 URI XML本身!

如果要直接从字符串中读取XML,则需要从字符串中创建InputSource,然后使用SAXParser.parse(InputSource is,DefaultHandler dh)方法。

要从InputSource创建String,您可以使用

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

StringReader是一种特殊类型的Reader,可以从字符串中读取(就像从InputStream中读取的那样)。