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

标签 java xml parsing saxparser

我正在尝试使用 SAX 在 Java 中解析 XML。因此,我给自己做了一个单元测试。

当我尝试从文件中解析 XML 时,一切都运行良好,但是当我尝试从字符串中解析完全相同的 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)

我的单元测试文件: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;
            }
        }
    }
}

问题:为什么从文件解析时有效,但从字符串解析时无效?如何使用 SAX 解析器解析字符串而不收到此错误?

编辑:RealSkeptic 找到了解决方案,非常感谢。 我使用的重载不应该是 XML 本身,而是 XML 文件的路径。 为了解决这个问题,我不得不更改“parser.parse(xmlString), handler);”到“parser.parse(new InputSource(new StringReader(xmlString)), handler);”

最佳答案

你使用

parser.parse(xmlString, handler);

但是documentation SAXParser.parse(String uri,DefaultHandler dh) 清楚地告诉您传递给它的字符串是 XML 实际位置的 URI。它不是 XML 本身!

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

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

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

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

关于java - XML当String时无法解析,当从File解析时没有问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29416336/

相关文章:

json - JQ -c/--compact-output 无法正常工作? Json解析

java - Android HttpURLConnection 空帖子

java - 是否可以编译 Maven java 项目,忽略有错误的 java 文件并编译没有错误的 java 文件?

xml - Intellisense 无法使用 XML 引号 - 键入双引号会打开两个引号,再次键入双引号不会移动光标

PHP - 将 XML 用于配置文件是元素优于属性还是相反?

javascript - nodejs json.parse 保留科学记数法

java - 如何访问列表中对象的方法

java - 如何查找 hashmap a 中的值在 hashmap b 中是否不存在

java - 获取元素的 XPath 列表

java - Jackson API - 使用简单的动态对象反序列化 JSON