解析xml文件有好几种方法,包括有:Dom、Jdom、SAX解析、Demo4j 等等
本篇主要讲解SAX是如何解析xml文件的。
项目结构如下:
新建一个ParserUtil类,继承自DefaultHandler,并重写五个方法:startDocument()、startElement、characters()、endElement、endDocument()
public class ParserUtil extends DefaultHandler{
//开始xml解析时调用
@Override
public void startDocument() throws SAXException {
// TODO Auto-generated method stub
super.startDocument();
}
//开始解析某个节点时调用
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
// TODO Auto-generated method stub
super.startElement(uri, localName, qName, attributes);
}
//获取节点内容时调用
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
// TODO Auto-generated method stub
super.characters(ch, start, length);
}
//完成某个节点解析时调用
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
// TODO Auto-generated method stub
super.endElement(uri, localName, qName);
}
//完成整个xml解析时调用
@Override
public void endDocument() throws SAXException {
// TODO Auto-generated method stub
super.endDocument();
}
}
在项目下创建一个data.xml文件,作为解析源使用:
像<Users>、<user>这种结构的xml文件称为ElementNode
<?xml version="1.0" encoding="UTF-8"?>
<Users>
<user>
<id>1</id>
<name>Tom</name>
<age>21</age>
</user>
<user>
<id>2</id>
<name>Jerry</name>
<age>20</age>
</user>
<user>
<id>3</id>
<name>Iris</name>
<age>22</age>
</user>
</Users>
根据data.xml的构成方式,ParserUtil重写父类方法的具体实现如下:
public class ParserUtil extends DefaultHandler{
private String nodeName;
private StringBuilder id;
private StringBuilder name;
private StringBuilder age;
@Override
public void startDocument() throws SAXException {
System.out.println("***开始解析***");
id = new StringBuilder();
name = new StringBuilder();
age = new StringBuilder();
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
//记录节点名
nodeName = qName;
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
//根据当前节点名判断将内容添加到哪一个对象中
if (nodeName.equals("id")) {
id.append(ch,start,length);
}else if (nodeName.equals("name")) {
name.append(ch, start, length);
}else if (nodeName.equals("age")) {
age.append(ch, start, length);
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (qName.equals("user")) {
System.out.println("id:"+id.toString().trim());
System.out.println("name:"+name.toString().trim());
System.out.println("age:"+age.toString().trim());
id.setLength(0);
name.setLength(0);
age.setLength(0);
}
}
@Override
public void endDocument() throws SAXException {
System.out.println("***解析完成***");
}
}
SAXParser类:
public class SAXpaser{
/**
* 获取本地xml文件数据
* @param args
*/
public static String getXMLData(){
try {
InputStream is = new FileInputStream(new File("WebContent/data.xml"));
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line = "";
StringBuilder sb = new StringBuilder();
while((line=br.readLine())!=null){
sb.append(line).append("\n");
}
is.close();
br.close();
return sb.toString();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
/**
* 使用SAX解析xml文件
* @param args
*/
public static void parserXMLWtihSAX(String xmlData){
SAXParserFactory factory = SAXParserFactory.newInstance();
try {
XMLReader xmlReader = factory.newSAXParser().getXMLReader();
ParserUtil parserUtil = new ParserUtil();
xmlReader.setContentHandler(parserUtil);
xmlReader.parse(new InputSource(new StringReader(xmlData)));
} catch (SAXException | ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
String xmlData = getXMLData();
parserXMLWtihSAX(xmlData);
}
}
***开始解析***
id:1
name:Tom
age:21
id:2
name:Jerry
age:20
id:3
name:Iris
age:22
***解析完成***
注意:在解析xml过程博主遇到了一个奇怪的问题,startElement()、endElement()方法中,通过localName匹配节点名称失败,通过System.out.println(localName)查看,结果什么都没输出。在网上搜索一通之后,终于找到问题了,原因是不同计算机的运行环境有可能不一样,导致localName的值为空。如果通过localName获取不到解析结果,请尝试使用qName匹配节点名称,获取解析结果。