我正在尝试使用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;
答案 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
中读取的那样)。