Java解析XML与创建
一、什么是 XML?
- XML 指可扩展标记语言(EXtensible Markup Language)
- XML 是一种标记语言,很类似 HTML
- XML 的设计宗旨是传输数据,而非显示数据
- XML 标签没有被预定义。您需要自行定义标签。
- XML 被设计为具有自我描述性。
- XML 是 W3C 的推荐标准
一个xml文档,用于描述传输图书信息
<?xml version="1.0" encoding="UTF-8"?> <books> <book id="1"> <name>射雕英雄传</name> <author>金庸</author> <publisher>三联出版社</publisher> <price>200</price> </book> <book id="2"> <name>神雕侠侣</name> <author>金庸</author> <publisher>三联出版社</publisher> <price>200</price> </book> <book id="3"> <name>倚天屠龙记</name> <author>金庸</author> <publisher>三联出版社</publisher> <price>200</price> </book> <book id="4"> <name>鹿鼎记</name> <author>金庸</author> <publisher>三联出版社</publisher> <price>500</price> </book> <book id="5"> <name>天龙八部</name> <author>金庸</author> <publisher>三联出版社</publisher> <price>500</price> </book> </books>
二、xml解析
JAVA 解析 XML 通常有两种方式,DOM 和 SAX。
1、dom解析
package edu.cduestc.xml.domain; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class DOMParseXml { public static List<Book> parseXml(InputStream is){ List<Book> list = new ArrayList<Book>(); try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document document = builder.parse(is); Element root = document.getDocumentElement(); NodeList nodes = root.getElementsByTagName("book"); for(int i = 0; i < nodes.getLength(); i++) { Book book = new Book(); Element node = (Element)nodes.item(i); Integer id = Integer.valueOf(node.getAttribute("id")); book.setId(id); NodeList childNodes = node.getChildNodes(); for(int j = 0; j < childNodes.getLength(); j++) { //Element childNode = (Element)childNodes.item(j); if(childNodes.item(j).getNodeType() == Node.ELEMENT_NODE){ Element childNode = (Element)childNodes.item(j); if("name".equals(childNode.getTagName())) book.setName(childNode.getTextContent()); if("author".equals(childNode.getTagName())) book.setAuthor(childNode.getTextContent()); if("publisher".equals(childNode.getTagName())) book.setPublisher(childNode.getTextContent()); if("price".equals(childNode.getTagName())) book.setPrice(Float.parseFloat(childNode.getTextContent())); } } list.add(book); } is.close(); } catch (Exception e) { e.printStackTrace(); } return list; } public static void main(String[] args) throws FileNotFoundException { BufferedInputStream is = new BufferedInputStream(new FileInputStream("books.xml")); parseXml(is).forEach(System.out::println);; } }
DOM 虽然是 W3C 的标准,提供了标准的解析方式,但它的解析效率一直不尽如人意,因为使用DOM解析XML时,解析器读入整个文档并构建一个驻留内存的树结构(节点树),然后您的代码才可以使用 DOM 的标准接口来操作这个树结构。但大部分情况下我们只对文档的部分内容感兴趣,根本就不用先解析整个文档,并且从节点树的根节点来索引一些我们需要的数据也是非常耗时的。
SAX是一种XML解析的替代方法。相比于文档对象模型DOM,SAX 是读取和操作 XML 数据的更快速、更轻量的方法。SAX 允许您在读取文档时处理它,从而不必等待整个文档被存储之后才采取操作。它不涉及 DOM 所必需的开销和概念跳跃。 SAX API是一个基于事件的API ,适用于处理数据流,即随着数据的流动而依次处理数据。SAX API 在其解析您的文档时发生一定事件的时候会通知您。在您对其响应时,您不作保存的数据将会 被抛弃。
package edu.cduestc.xml.domain; import java.io.BufferedInputStream; import java.io.FileInputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; public class SAXParseXml { public static List<Book> parseXml(InputStream is) throws Exception, SAXException{ SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); BookHandler handler = new BookHandler(); parser.parse(is, handler); return handler.getBooks(); } private static class BookHandler extends DefaultHandler{ private List<Book> books; private Book book; private String tag; @Override public void startDocument() throws SAXException { books = new ArrayList<Book>(); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if("book".equals(qName)) { book = new Book(); book.setId(Integer.valueOf(attributes.getValue("id"))); } tag = qName; } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if("book".equals(qName)) { books.add(book); } tag = null; } @Override public void characters(char[] ch, int start, int length) throws SAXException { if(tag != null) { String data = new String(ch,start,length); if("name".equals(tag))book.setName(data); else if("author".equals(tag))book.setAuthor(data); else if("publisher".equals(tag))book.setPublisher(data); else if("price".equals(tag))book.setPrice(Float.parseFloat(data)); } } public List<Book> getBooks() { return books; } } public static void main(String[] args) throws Exception { BufferedInputStream is = new BufferedInputStream(new FileInputStream("books.xml")); parseXml(is).forEach(System.out::println); } }
PULL解析类似于SAX解析,都采用事件驱动(利用getEventType()方法)方式进行解析,当PULL解析器开始解析之后,可以不断地调用PULL解析器的next()方法获取下一个解析事件(开始文档START_DOCUMENT、结束文档END_DOCUMENT、开始标签START_TAG、结束标签END_TAG等),当处于某个元素时,可调用XmlPullParser的getAttributeValue()方法来获取该元素的属性值(可以利用属性索引和属性名皆可),也可调用XmlPullParser的nextText()方法来获取文本节点的值。
package edu.cduestc.xml.domain; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.Reader; import java.util.ArrayList; import java.util.List; import org.xml.sax.SAXException; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserFactory; public class PullParseXml { public static List<Book> parseXml(Reader reader) throws Exception, SAXException { List<Book> books = new ArrayList<Book>(); Book book = null; XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); XmlPullParser parser = factory.newPullParser(); parser.setInput(reader); int event = parser.getEventType();// 触发第一个事件 while (event != XmlPullParser.END_DOCUMENT) { switch (event) { case XmlPullParser.START_TAG: if ("book".equals(parser.getName())) { book = new Book(); book.setId(Integer.valueOf(parser.getAttributeValue(0))); } if (book != null) { if ("name".equals(parser.getName())) book.setName(parser.nextText()); if ("author".equals(parser.getName())) book.setAuthor(parser.nextText()); if ("publisher".equals(parser.getName())) book.setPublisher(parser.nextText()); if ("price".equals(parser.getName())) book.setPrice(Float.parseFloat(parser.nextText())); } break; case XmlPullParser.END_TAG: if ("book".equals(parser.getName())) { books.add(book); book = null; } } event = parser.next();// 继续下一次事件 } return books; } public static void main(String[] args) throws FileNotFoundException, SAXException, Exception { parseXml(new FileReader("books.xml")).forEach(System.out::println); } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
2020-06-24 泛型