1.DOM解析
使用DOM方式解析xml文件,首先通过DocumentBuilderFactory实例创建DocumentBuilder对象,通过该对象的parse(“url”)方法对xml文件进行解析获得Document对象。
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
//创建DocumentBuilder对象
DocumentBuilder db = dbf.newDocumentBuilder();
//通过DocumentBuilder对象调用parse方法解析
Document document = db.parse("book.xml");
1.1 解析文件的属性名和属性值
//创建DocumentBuilder对象
DocumentBuilder db = dbf.newDocumentBuilder();
//通过DocumentBuilder对象调用parse方法解析
Document document = db.parse("book.xml");
//获得所有book节点集合
NodeList bookList = document.getElementsByTagName("book");
System.out.println("共有"+bookList.getLength()+"本书");
//遍历获得每一个book节点
for (int i = 0; i < bookList.getLength(); i++) {
Node book = bookList.item(i);
//下面注释是两种方法获得book属性
// //获得book节点所有属性集合(在不知道属性有多少情况)
// NamedNodeMap attrs = book.getAttributes();
// System.out.println("第"+(i+1)+"本书共有"+attrs.getLength()+"个属性");
// for (int j = 0; j < attrs.getLength(); j++) {
// Node attr = attrs.item(j);
// //获取属性值
// System.out.print(attr.getNodeName()+" ");
// System.out.println(attr.getNodeValue());
// }
//知道book节点有且只有一个属性id
//首先通过强制类型转化为Element类型,node(节点)只有getattributes方法,element(元素)有getattribute方法
// Element book = (Element)bookList.item(i);
// //获得id属性值
// String attrValue = book.getAttribute("id");
// System.out.println("id属性值为"+attrValue);
1.2 解析文件的节点名和节点值
//获取book节点的子节点集合(不是数组或iterable的实例不能使用foreach遍历)
NodeList childNotes = book.getChildNodes();
//在解析xml文档时会把文本也解析为该节点下面的子节点,空格解析为文本
System.out.println("第"+(i+1)+"个节点共有"+childNotes.getLength()+"个子节点");
for (int j = 0; j < childNotes.getLength(); j++) {
Node childNote = childNotes.item(j);
//区分出text类型的node及element类型的node
if(childNote.getNodeType() == Node.ELEMENT_NODE){
System.out.print(childNote.getNodeName()+" ");
//不能直接getNodeValue会返回null
//因为把一对节点之间的内容也看成该节点的子节点
System.out.println(childNote.getFirstChild().getNodeValue());
//也可以用getTextContent方法获得节点内容,与getNodeValue不同的是
//如果子节点下仍有子节点则getNodeValue返回null,而getTextContent返回该节点及子节点内容
// System.out.println(childNote.getTextContent());
}
}
}
2.SAX解析
与DOM解析将整个文档加载不同的是,SAX通过自己创建的Handler类逐个解析。大致包括下面步骤
首先通过SAXParserFactory的静态newInstance方法创建SAXParserFactory实例
然后通过SAXParserFactory的实例的newSAXParser()方法获得SAXParser实例parser
然后创建一个类继承DefaultHandler,重写其中的一些方法进行业务处理并创建这个类的实例handler
最后调用parser的parse("url",handler);进行文件解析。
下面给出主要业务处理函数。
startElement() 用来遍历开始标签(文件名和节点名都使用这个函数遍历)
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
// TODO Auto-generated method stub
super.startElement(uri, localName, qName, attributes);
//获得book文件的属性名,属性值
if(qName.equals("book")){
//创建一个book对象
book = new Book();
bookIndex++;
System.out.println("=================开始遍历第"+bookIndex+"本书的内容=================");
// //已知文件的属性名,根据属性名获取属性值
// String value = attributes.getValue("id");
// System.out.println("id的属性值是: "+value);
//不知道文件的属性名和属性值的个数
int num = attributes.getLength();
for (int i = 0; i < num; i++) {
System.out.print("book元素第"+(i+1)+"个属性名是:"+attributes.getQName(i));
System.out.println("---属性值是:"+attributes.getValue(i));
}
//获得文件的节点名,节点值
}else if(!qName.equals("bookstore") && !qName.equals("book")){
System.out.print("节点名是: "+ qName);
}
}
endElement() 用来遍历结束标签(文件名,节点名结束都使用)
public void endElement(String uri, String localName, String qName) throws SAXException {
// TODO Auto-generated method stub
super.endElement(uri, localName, qName);
if(qName.equals("book")){
//在endElement说明遍历一本书结束,将其加入到book类中
bookList.add(book);
book = null;
System.out.println("=================结束遍历第"+bookIndex+"本书的内容=================");
} else if (qName.equals("name")) {
book.setName(value);
} else if (qName.equals("author")) {
book.setAuthor(value);
} else if (qName.equals("year")) {
book.setYear(value);
} else if (qName.equals("language")) {
book.setLanguage(value);
} else if (qName.equals("price")) {
book.setPrice(value);
}
characters() 获取节点值
public void characters(char[] ch, int start, int length) throws SAXException {
// TODO Auto-generated method stub
super.characters(ch, start, length);
value = new String(ch, start, length);
//将空格换行过滤
if(!value.trim().equals("")){
System.out.println("---节点值是:"+value);
}
}
startDocument() ,endDocument()分别表识文档解析开始,结束。
xml解析目的是为了将其中信息保存到对象中,在自创建的handler类中重要功能是为了解析出节点属性,节点值并按照相应层次关系保存到Book对象中,其中节点名保存在形参qName中,相对应的属性值保存在characters()中的字符数组char[] 中,由于属性名,属性值在不同的成员函数中应该将characters方法中得到的属性值设为handler类的成员变量。
还有在解析多个对象时应在handler中创建List<object>存放,并且在startElement中匹配到文件名新建对象,在endElement中匹配到文件节点名时将节点值存入对象并将对象添加到对象集合中。(不可以在startElement中赋值,只有匹配到结束标签characters方法中的value才是该节点的值)
3 JDOM解析
上面两种是官方提供的解析方式,使用jdom解析要导入相应jar包(导入jar包如果使用external如果把工程打包则会出现错误,可新建follder粘贴jar包,在jar上add to builderpath即可),解析过程中会自动把空格和换行过滤(使用DOM解析要判断节点类型是否是node),可直接调用getName,getValue方法(DOM中不过滤调用则会返回null),值得注意的是,因为采用输入流进行解析,可能由于编码出现乱码问题,这时可在inputstream上包装成inputstreamreader并指定编码方式即可(不需要和xml编码一致)。
将解析出的属性赋值给相应对象,只需在文件属性和节点属性遍历时进行if匹配赋值即可。
//1.创建saxBuilder对象
SAXBuilder saxBuilder = new SAXBuilder();
//2.创建输入流,将xml文件加载到输入流中
InputStream in;
try {
in = new FileInputStream("book.xml");
//3.通过build方法,将输入流加载到saxBilder中
Document document = saxBuilder.build(in);
//4.通过Document对象获取根节点
Element rootElement = document.getRootElement();
//5.获取根节点下的子节点的List集合
List<Element> bookList = rootElement.getChildren();
for (Element book : bookList) {
System.out.println("======开始遍历第"+(bookList.indexOf(book)+1)+"本书======");
//知道属性名时获取节点值
// String name = book.getAttributeValue("id");
// System.out.println("属性id对应的属性值为: "+name);
//获得文件属性集合,不知道属性名的及数量情况下
List<Attribute> attrs = book.getAttributes();
//遍历属性集合,获得属性名属性值
for (Attribute attribute : attrs) {
String attrName = attribute.getName();
System.out.print("属性名是: "+attrName);
String attrValue = attribute.getValue();
System.out.println("---属性值是:"+attrValue);
}
List<Element> chlidrenList = book.getChildren();
for (Element child : chlidrenList) {
System.out.print("节点名为: "+ child.getName());
System.out.println("---节点值为: "+child.getValue());
}
System.out.println("======结束遍历第"+(bookList.indexOf(book)+1)+"本书======");
}
4.DOM4J 解析
DOM4J和JDOM解析都是非官方解析方式,但使用更方便,推荐使用。
private static Book bookEntity;
private static ArrayList<Book> bookList = new ArrayList<>();
//与JDOM不同的是通过根节点创建迭代器,得到book节点迭代器,再创键迭代器得到book下子节点
//JDOM是通过根节点调用getChildren得到book节点集合,在book集合中在调用getChildren方法的到book下子节点集合
public static void main(String[] args) {
//创建SAXReader对象
SAXReader saxReader = new SAXReader();
try {
//通过reader对象的read方法加载xml文件,获取document对象
Document document = saxReader.read(new File("book.xml"));
//通过document对象获取根结点bookstore
Element element = document.getRootElement();
//通过element对象的elementIterator方法获取迭代器
Iterator it = element.elementIterator();
//遍历迭代器,获取根节点中信息(book)
while(it.hasNext()){
bookEntity = new Book();
System.out.println("======开始遍历某一本书");
Element book = (Element) it.next();
List<Attribute> attrs = book.attributes();
for (Attribute attribute : attrs) {
System.out.println("属性名为:"+attribute.getName()+
"---属性值为:"+attribute.getValue());
if(attribute.getName().equals("id")){
bookEntity.setId(attribute.getValue());
}
}
//根据book节点创建迭代器获取book中的子节点信息
Iterator it2 = book.elementIterator();
while(it2.hasNext()){
Element element2 = (Element) it2.next();
String name = element2.getName();
String value = element2.getStringValue();
System.out.println("节点名为:"+name
+"---节点值为: "+value);
if(name.equals("name")){
bookEntity.setName(value);
}else if(name.equals("author")){
bookEntity.setAuthor(value);
}else if(name.equals("year")){
bookEntity.setYear(value);
}else if(name.equals("price")){
bookEntity.setPrice(value);
}else if(name.equals("language")){
bookEntity.setLanguage(value);
}
}
System.out.println("======结束遍历某一本书");
bookList.add(bookEntity);
bookEntity = null;
}
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
List<Book> list = getBookList();
System.out.println("共有"+list.size()+"本书");
for (Book book : list) {
System.out.println("ID 为:"+book.getId()
+"---书名为:"+book.getName());
}
}
public static ArrayList<Book> getBookList(){
return bookList;
}
5.四种解析方式分析对比
DOM,SAX是基础方法,JDOM,DOM4J是扩展方法只有在java中能够使用
DOM 解析是一次性加载进内存,如果文件大对内存消耗大则效率低。优点易于编码。
SAX 是基于事件的解析,逐条执行,没进入一个开始标签调用startElement方法,进入结束标签调用endElement方法。对内存消耗少,适用于只需要处理xml中数据。缺点不易编码,很难同时访问同一个xml中的多处不同数据。
JDOM 使用具体类不适用接口,API大量使用了collections类。
DOM4J 使用接口和抽象基本类方法,是JDOM的只能分支,合并了许多超出XMl文档表示的功能,性能较好。(hibernate框架中也是使用DOM4J)