解析XML的方式分为两种:
- 文档对象模型(Document Object Model)即DOM,该解析器为树形解析器,DOM解析器会将XML文档解析为对应的树形结构。
- XML简单接口(Simple API for XML) 即SAX,该解析器为流机制解析器,SAX解析器会将读入XML文档中的各个部分作为事件。
由于DOM解析器会将整个XML文档的内容转化为树形结构,故需要消耗大量的内存。其好处在于,我们可以随时查找之前的元素或文本。如果,我们不需要关注已遍历过的文本内容,那么我们就选用SAX解析方式。
下面我们来用两种不同的解析方式,遍历如下XML文档中的内容(由于文档校验DTD或者XML SCHEMA较为复杂,此处我们只是介绍如何遍历XML元素,故略去文档校验的部分代码)。
<?xml version="1.0" encoding="UTF-8"?>
<Log>
<!--log filename-->
<Filename>java</Filename>
<!--log limit,must between 10485760(10M) and 52428800(50M)-->
<Limit>20971520</Limit>
<!--log count,cannot be lower than 1-->
<Count>100</Count>
<!--whether to follow the existing file to write,just allow 'TRUE' or 'FALSE' and case insensitive-->
<isAppend>true</isAppend>
<!--Whether to compress the log,just allow 'True' or 'FALSE' and case insensitive-->
<isCompress>TRUE</isCompress>
</Log>
DOM解析器
DOM解析器解析XML文档的步骤为:
- 创建工厂对象,并设置工厂对象ignoringComments属性为true,即忽略XML文档中注释。如果不设置IgnoringComments属性为true,那么在遍历子元素时,解析器会将注释作为子元素进行遍历。
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
factory.setIgnoringComments(true);
- 生成文档对象Document
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
factory.setIgnoringComments(true);
DocumentBuilder builder=factory.newDocumentBuilder();
Document doc=builder.parse("./logConfig.xml");
- 生成根节点元素
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
factory.setIgnoringComments(true);//忽略文档中的注释
DocumentBuilder builder=factory.newDocumentBuilder();
Document doc=builder.parse("./logConfig.xml");
Element root=doc.getDocumentElement();
- 遍历Document文档中子元素、属性以及文本内容
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.DocumentBuilder;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import java.io.IOException;
public class xmlTest
{
public static void main(String[] args) throws ParserConfigurationException,SAXException,IOException
{
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
factory.setIgnoringComments(true);
DocumentBuilder builder=factory.newDocumentBuilder();
Document doc=builder.parse("./logConfig.xml");
Element root=doc.getDocumentElement();
System.out.println(root.getTagName());
NodeList list=root.getChildNodes();//获取根节点下子节点
for(int i=0;i<list.getLength();i++)//NodeList的getLength()方法返回子节点的个数
{
Node node=list.item(i);//方法item(i)获取NodeList中索引位置为i的节点
if(node instanceof Element)//排除掉子节点中的文本、元素间的空白字符
{
Element elem=(Element)node;
Node text=elem.getFirstChild();//获取元素的文本节点
System.out.println(elem.getTagName()+":"+((CharacterData)text).getData());//getTagName()方法用于获取元素名称,getData()方法用于获取元素的内容
NamedNodeMap attrs=elem.getAttributes();//遍历元素的属性,生成NamedNodeMap对象,与NodeList使用方式基本相同,当然如果知道属性名可以调用String getAttribute(String name)直接获取name属性的值
for(int j=0;j<attrs.getLength();j++)
{
Node attr=attrs.item(j);
System.out.println(attr.getNodeName()+":"+attr.getNodeValue());//getNodeName()获取属性名称,getNodeValue()用于获取属性值
}
}
}
}
}
流机制解析器
目前Java类库中可用的XML流机制解析器有两种:
- SAX解析器
- StAX解析器
因此,我们分别介绍两种流机制解析器的使用方法。
SAX解析器
步骤如下:
- 创建工厂对象
SAXParserFactory factory=SAXParserFactory.newInstance();
- 获取SAXParser对象
SAXParserFactory factory=SAXParserFactory.newInstance();
SAXParser parser=factory.newSAXParser();
- 拓展通用类org.xml.sax.helpers.DefaultHandler并
覆盖类中的方法
- startElement(String uri,String lName,String qName,Attributes attrs)
在遍历元素起始标签时调用 - characters(Char[] ch,int start,int length)
在访问字符内容时调用(元素内容、标签间空白字符)。 - endElement(String uri,String lName,String qName)
在访问元素结束标签时调用。
SAXParserFactory factory=SAXParserFactory.newInstance();
SAXParser parser=factory.newSAXParser();
DefaultHandler handler=new DefaultHandler(){
StringBuilder sb;//记录元素名称,属性名,属性值以及元素内容
public void startElement(String uri,String lName,String qName,Attributes attrs)
{
sb=new StringBuilder(qName+" [");//qName元素名
for(int i=0;i<attrs.getLength();i++)//获取元素属性名及属性值
{
sb.append("("+attrs.getLocalName(i)+","+attrs.getValue(i)+")");
}
sb.append("]");
}
public void characters(char[] ch,int start,int length)//读入文本字符串时调用
{
String text=new String(ch,start,length);
if(text.trim().length()!=0)//剔除元素标签间的空白字符
sb.append(" "+text);
}
public void endElement(String uri,String lName,String qName)//访问结束标签时调用
{
System.out.println(sb);//输出元素信息
}
};
- 遍历XML文档
SAXParserFactory factory=SAXParserFactory.newInstance();
SAXParser parser=factory.newSAXParser();
DefaultHandler handler=new DefaultHandler(){
StringBuilder sb;//记录元素名称,属性名,属性值以及元素内容
public void startElement(String uri,String lName,String qName,Attributes attrs)
{
sb=new StringBuilder(qName+" [");
for(int i=0;i<attrs.getLength();i++)
{
sb.append("("+attrs.getLocalName(i)+","+attrs.getValue(i)+")");
}
sb.append("]");
}
public void characters(char[] ch,int start,int length)
{
String text=new String(ch,start,length);
if(text.trim().length()!=0)
sb.append(" "+text);
}
public void endElement(String uri,String lName,String qName)
{
System.out.println(sb);
}
};
parser.parse(new File("./logConfig.xml"),handler);//遍历XML文档
完整的代码如下:
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.Attributes;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
public class xmlTest
{
public static void main(String[] args) throws ParserConfigurationException,SAXException,IOException
{
SAXParserFactory factory=SAXParserFactory.newInstance();
SAXParser parser=factory.newSAXParser();
DefaultHandler handler=new DefaultHandler(){
StringBuilder sb;
public void startElement(String uri,String lName,String qName,Attributes attrs)
{
sb=new StringBuilder(qName+" [");
for(int i=0;i<attrs.getLength();i++)
{
sb.append("("+attrs.getLocalName(i)+","+attrs.getValue(i)+")");
}
sb.append("]");
}
public void characters(char[] ch,int start,int length)
{
String text=new String(ch,start,length);
if(text.trim().length()!=0)
sb.append(" "+text);
}
public void endElement(String uri,String lName,String qName)
{
System.out.println(sb);
}
};
parser.parse(new File("./logConfig.xml"),handler);
}
}
StAX解析器
步骤如下:
- 生成工厂对象
XMLInputFactory factory=XMLInputFactory.newInstance();
- 生成XMLStreamReader对象
XMLInputFactory factory=XMLInputFactory.newInstance();
XMLStreamReader parser=factory.createXMLStreamReader(Files.newInputStream(new File("./logConfig.xml").toPath()));
- 遍历XML文档
XMLStreamReader对象就是由XML各个部分内容对应的事件组成的集合,通过遍历XMLStreamReader对象来达到遍历XML文档内容的目的,XMLStreamReader类似于迭代器对象,因此我们可以用类似的方法遍历XMLStreamReader对象,如下所示:
XMLInputFactory factory=XMLInputFactory.newInstance();
XMLStreamReader parser=factory.createXMLStreamReader(Files.newInputStream(new File("./logConfig.xml").toPath()));
while(parser.hasNext())//XMLStreamReader对象中是否还存在事件
{
int event=parser.next();//下一个事件
if(event==XMLStreamConstants.START_ELEMENT)//判断当前事件是否表示起始标签,即我们遍历位置在标签起始处。
{
StringBuilder sb=new StringBuilder();
sb.append(parser.getLocalName()+" [");//getLocalName()方法获取元素名
for(int i=0;i<parser.getAttributeCount();i++)//getAttributeCount()获取元素属性数量
{
if(i==0)
sb.append("("+parser.getAttributeName(i)+","+parser.getAttributeValue(i)+")");//getAttributeName(int i)获取索引位置i处的属性名,getAttributeValue(int i)获取获取索引位置i处的属性值
else
sb.append(",("+parser.getAttributeName(i)+","+parser.getAttributeValue(i)+")");
}
sb.append("]");
if(parser.getLocalName()!="Log")
sb.append(" "+parser.getElementText());//getElementText()方法获取元素内容,该方法会内部调用next()方法,故获取元素内容放在获取属性内容之后。该方法源码细节可以查看[JDK10文档](https://docs.oracle.com/javase/10/docs/api/javax/xml/stream/XMLStreamReader.html#getElementText%28%29)
System.out.println(sb);
}
}
}
完整的代码如下所示:
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLStreamException;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.SAXException;
import java.nio.file.Files;
import java.io.File;
import java.io.IOException;
public class xmlTest
{
public static void main(String[] args) throws FactoryConfigurationError,XMLStreamException,SAXException,IOException
{
XMLInputFactory factory=XMLInputFactory.newInstance();
XMLStreamReader parser=factory.createXMLStreamReader(Files.newInputStream(new File("./logConfig.xml").toPath()));
while(parser.hasNext())//XMLStreamReader对象中是否还存在事件
{
int event=parser.next();//下一个事件
if(event==XMLStreamConstants.START_ELEMENT)//判断当前事件是否表示起始标签,即我们遍历位置在标签起始处。
{
StringBuilder sb=new StringBuilder();
sb.append(parser.getLocalName()+" [");//getLocalName()方法获取元素名
for(int i=0;i<parser.getAttributeCount();i++)//getAttributeCount()获取元素属性数量
{
if(i==0)
sb.append("("+parser.getAttributeName(i)+","+parser.getAttributeValue(i)+")");//getAttributeName(int i)获取索引位置i处的属性名,getAttributeValue(int i)获取获取索引位置i处的属性值
else
sb.append(",("+parser.getAttributeName(i)+","+parser.getAttributeValue(i)+")");
}
sb.append("]");
if(parser.getLocalName()!="Log")
sb.append(" "+parser.getElementText());//getElementText()方法获取元素内容,该方法会内部调用next()方法,故获取元素内容放在获取属性内容之后。该方法源码细节可以查看[JDK10文档](https://docs.oracle.com/javase/10/docs/api/javax/xml/stream/XMLStreamReader.html#getElementText%28%29)
System.out.println(sb);
}
}
}
}