XML的读(解析)和写
在学习XML(eXtensible Markup Language)可扩展标记语言时,我们就了解到XML文件可以用来配置文件,可以进行数据交换,能实现异构语言之间的通信,异构平台之间的交互。而实现这些功能就需要对XML进行读和写操作,下面就列出一些常见的XML解析(读)方法:DOM解析、SAX解析、DOM4J解析、JDOM解析,DOM和SAX解析是Java官方给我们的解析方式,而DOM4J和JDOM解析是其他组织提供的方式,我们需要下载相应的jar包并导进我们的项目中。
一、使用DOM方式解析和写XML文件(基于简单工厂模式的解析方式)
在解析XML之前,首先要了解一下简单工厂模式:
简单工厂模式是类的创建模式,又叫静态工厂方法(Static Factory Method)模式。简单工厂模式是由一个工厂对象决定创建出那一个产品类的实例。通常它根据变量的不同返回不同的类的实例。简单工厂模式实质是由一个工厂类根据传入的参数,动态决定应该生成那个产品类的实例对象
构成:工厂类角色(Creator):担任这个角色的是简单工厂模式的核心,含有与应用紧密相关的商业逻辑。工厂类在客户端的直接调用下创建产品对象,它往往由一个具体类实现。
抽象产品角色(Product):担任这个角色的类是简单工厂模式所创建的对象的父类,或它们共同拥有的接口。抽象产品角色可以用一个接口或抽象类实现。
具体产品角色(Concrete Product):简单工厂模式所创建的任何对象都是这个角色的实例,具体产品角色由一个具体类实现。
DOM解析是将整个XML文件加载到内存当中进行解析,又由于DOM的树型结构占用内存较多,这种解析方式在解析大文件时其性能会很低。
利用递归的方式解析XML文件并将结果输出到控制台上。
1 import org.w3c.dom.*; 2 import org.xml.sax.SAXException; 3 4 import javax.xml.parsers.DocumentBuilder; 5 import javax.xml.parsers.DocumentBuilderFactory; 6 import javax.xml.parsers.ParserConfigurationException; 7 import java.io.File; 8 import java.io.IOException; 9 10 public class Domrxml { 11 private static void parseXML(Element element){ 12 String nodeName = element.getNodeName(); 13 NodeList childNodes = element.getChildNodes(); 14 System.out.println("<"+nodeName); 15 // element元素的所有属性构成的NamedNodeMap对象,需要对其进行判断 16 NamedNodeMap attrs = element.getAttributes(); 17 // 如果该元素存在属性 18 if(null!=attrs && attrs.getLength()>0){ 19 for(int i = 0;i < attrs.getLength();i++){ 20 Attr item = (Attr) attrs.item(i); 21 String name = item.getName(); 22 String value = item.getValue(); 23 System.out.print(" "+name+"=\""+value+"\""); 24 } 25 } 26 System.out.println(">"); 27 if(null!=childNodes && childNodes.getLength()>0){ 28 for (int i = 0; i < childNodes.getLength(); i++) { 29 Node node = childNodes.item(i); 30 // 获得节点类型 31 short nodeType = node.getNodeType(); 32 // 是元素节点,继续递归 33 if(Node.ELEMENT_NODE == nodeType){ 34 parseXML((Element)node); 35 }else if (Node.TEXT_NODE == nodeType){ 36 System.out.println(node.getNodeValue()); 37 }else if(Node.COMMENT_NODE == nodeType){ 38 System.out.print("<--"); 39 Comment comment = (Comment) node; 40 // 获得注释内容 41 String commentData = comment.getData(); 42 System.out.print(commentData); 43 System.out.println("-->"); 44 } 45 } 46 System.out.println("</"+nodeName+">"); 47 } 48 } 49 50 public static void main(String[] args) { 51 // 获得dom解析器工厂(作用是用于创建具体的解析器) 52 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 53 try { 54 // 获得具体的dom解析器 55 DocumentBuilder db = dbf.newDocumentBuilder(); 56 // 利用DocumentBuilder对象的parse方法加载xml文件 57 Document parse = db.parse(new File("C:\\Users\\ztf\\Desktop\\xml\\5264.xml")); 58 // 获得文档的根元素 59 Element root = parse.getDocumentElement(); 60 parseXML(root); 61 } catch (ParserConfigurationException e) { 62 e.printStackTrace(); 63 } catch (SAXException e) { 64 e.printStackTrace(); 65 } catch (IOException e) { 66 e.printStackTrace(); 67 } 68 } 69 }
使用DOM方式写一个XML文件:
1 import org.w3c.dom.Document; 2 import org.w3c.dom.Element; 3 4 import javax.xml.parsers.DocumentBuilder; 5 import javax.xml.parsers.DocumentBuilderFactory; 6 import javax.xml.parsers.ParserConfigurationException; 7 import javax.xml.transform.*; 8 import javax.xml.transform.dom.DOMSource; 9 import javax.xml.transform.stream.StreamResult; 10 import java.io.File; 11 12 public class Domwxml { 13 public DocumentBuilder getDocumentBuilder(){ 14 DocumentBuilder db = null; 15 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 16 try { 17 db = dbf.newDocumentBuilder(); 18 } catch (ParserConfigurationException e) { 19 e.printStackTrace(); 20 } 21 return db; 22 } 23 24 public void createXml(){ 25 DocumentBuilder db = getDocumentBuilder(); 26 // 创建一个新文档 27 Document document = db.newDocument(); 28 // 设置standlone的属性为yes,其默认为不显示 29 document.setXmlStandalone(true); 30 // 创建节点 31 Element bookstore = document.createElement("bookstore"); 32 // 向文档中添加节点 33 document.appendChild(bookstore); 34 Element book = document.createElement("book"); 35 bookstore.appendChild(book); 36 book.setAttribute("id","1"); 37 Element name = document.createElement("name"); 38 book.appendChild(name); 39 name.setTextContent("小学生"); 40 // 将文档树生成xml文件 41 TransformerFactory tf = TransformerFactory.newInstance(); 42 try { 43 Transformer transformer = tf.newTransformer(); 44 // 设置输出属性是否自动换行 45 transformer.setOutputProperty(OutputKeys.INDENT,"yes"); 46 transformer.transform(new DOMSource(document),new StreamResult(new File("C:\\Users\\ztf\\Desktop\\xml\\book.xml"))); 47 } catch (TransformerConfigurationException e) { 48 e.printStackTrace(); 49 } catch (TransformerException e) { 50 e.printStackTrace(); 51 } 52 } 53 }
二、使用SAX方式解析和写XML文件(基于事件驱动的方式)
SAX解析方式是采用事件驱动的方式来解析XML文件,它不必将整个文档加载到内存中,对内存耗费小,在解析文档时每执行一行XML文件,就会调用SAX特有的Handler处理类去逐个分析遇到的每个节点,适合对XML文件进行顺序访问。
首先需要创建一个类来继承DefaultHandler类,在其中来写解析XML文件的逻辑。
1 //创建Handler类 2 3 import com.water.entity.Book; 4 import org.xml.sax.Attributes; 5 import org.xml.sax.SAXException; 6 import org.xml.sax.helpers.DefaultHandler; 7 8 import java.util.ArrayList; 9 10 public class SaxParserHandler extends DefaultHandler { 11 // 设置全部变量 12 String value = null; 13 Book book = null; 14 15 public ArrayList<Book> getBookArrayList() { 16 return bookArrayList; 17 } 18 19 private ArrayList<Book> bookArrayList = new ArrayList<>(); 20 int bookIndex = 0; 21 // 用来遍历xml文件的开始标签 22 @Override 23 public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { 24 // 调用DefaultHandler类的startElement方法 25 super.startElement(uri, localName, qName, attributes); 26 // 开始解析元素属性 27 if(qName.equals("book")){ 28 bookIndex++; 29 book = new Book(); 30 // 已知属性名的情况下获取值 31 // String id = attributes.getValue("id"); 32 // 不知属性名及个数情况下,获取属性名及个数 33 for (int i = 0; i < attributes.getLength(); i++) { 34 // 获取属性名和属性值 35 System.out.println(attributes.getQName(i)+attributes.getValue(i)); 36 if(attributes.getQName(i).equals("id")){ 37 book.setId(attributes.getValue(i)); 38 } 39 } 40 }else if (!qName.equals("book")&&!qName.equals("bookstore")){ 41 System.out.println("节点名"+qName); 42 } 43 } 44 45 // 用来遍历xml文件的结束标签 46 @Override 47 public void endElement(String uri, String localName, String qName) throws SAXException { 48 super.endElement(uri, localName, qName); 49 if(qName.equals("book")){ 50 bookArrayList.add(book); 51 book = null; 52 System.out.println("第"+bookIndex+"个节点解析结束"); 53 }else if (qName.equals("name")){ 54 book.setName(value); 55 } 56 } 57 58 // 用来标识解析开始 59 @Override 60 public void startDocument() throws SAXException { 61 super.startDocument(); 62 } 63 64 // 用来标识解析结束 65 @Override 66 public void endDocument() throws SAXException { 67 super.endDocument(); 68 } 69 70 @Override 71 public void characters(char[] ch, int start, int length) throws SAXException { 72 super.characters(ch, start, length); 73 value = new String(ch, start, length); 74 if (value.trim().equals("")){ 75 System.out.println(value); 76 } 77 } 78 }
解析XML文件是在Handler的基础上进行的,
1 import com.water.entity.Book; 2 import com.water.handler.SaxParserHandler; 3 import org.xml.sax.SAXException; 4 import org.xml.sax.helpers.AttributesImpl; 5 6 import javax.xml.parsers.ParserConfigurationException; 7 import javax.xml.parsers.SAXParser; 8 import javax.xml.parsers.SAXParserFactory; 9 import javax.xml.transform.OutputKeys; 10 import javax.xml.transform.Transformer; 11 import javax.xml.transform.TransformerConfigurationException; 12 import javax.xml.transform.TransformerFactory; 13 import javax.xml.transform.sax.SAXTransformerFactory; 14 import javax.xml.transform.sax.TransformerHandler; 15 import javax.xml.transform.stream.StreamResult; 16 import java.io.File; 17 import java.io.FileNotFoundException; 18 import java.io.FileOutputStream; 19 import java.io.IOException; 20 import java.util.ArrayList; 21 22 public class Saxxml { 23 public ArrayList<Book> parseXml(){ 24 // 获取一个SAXParserFactory的实例 25 SAXParserFactory spf = SAXParserFactory.newInstance(); 26 SaxParserHandler sph = null; 27 28 try { 29 // 获取SAXParser的实例 30 SAXParser sp = spf.newSAXParser(); 31 // 创建一个SAXParserHandler对象 32 sph = new SaxParserHandler(); 33 sp.parse("C:\\Users\\ztf\\Desktop\\xml\\5264.xml",sph); 34 35 } catch (ParserConfigurationException e) { 36 e.printStackTrace(); 37 } catch (SAXException e) { 38 e.printStackTrace(); 39 } catch (IOException e) { 40 e.printStackTrace(); 41 } 42 return sph.getBookArrayList(); 43 } 44 45 46 // 生成xml文件 47 public void createXml(){ 48 ArrayList<Book> books = parseXml(); 49 // 创建一个TransformerFactory类的对象,返回的是一个TransformerFactory类型,需强制类型转换 50 SAXTransformerFactory tf = (SAXTransformerFactory)SAXTransformerFactory.newInstance(); 51 52 try { 53 // 获取一个TransformerHandler对象 54 TransformerHandler tfh = tf.newTransformerHandler(); 55 // 获取一个transformer对象,用于对xml的设置 56 Transformer transformer = tfh.getTransformer(); 57 transformer.setOutputProperty(OutputKeys.ENCODING,"utf-8"); 58 transformer.setOutputProperty(OutputKeys.INDENT,"yes"); 59 // 创建一个result对象 60 StreamResult streamResult = new StreamResult(new FileOutputStream(new File("C:\\Users\\ztf\\Desktop\\xml\\book.xml"))); 61 tfh.setResult(streamResult); 62 // 打开文档 63 tfh.startDocument(); 64 // 创建一个属性对象 65 AttributesImpl attrs = new AttributesImpl(); 66 tfh.startElement("","","bookstore",attrs); 67 for(Book book:books){ 68 // 清空attrs里的属性 69 attrs.clear(); 70 attrs.addAttribute("","","id","int",book.getId()); 71 // 创建book节点 72 tfh.startElement("","","book",attrs); 73 attrs.clear(); 74 // 创建name节点 75 if(book.getName()!=null && !book.getName().trim().equals("")){ 76 tfh.startElement("","","name",attrs); 77 tfh.characters(book.getName().toCharArray(),0,book.getName().length()); 78 tfh.endElement("","","name"); 79 } 80 tfh.endElement("","","book"); 81 } 82 tfh.endElement("","","bookstore"); 83 // 关闭文档 84 tfh.endDocument(); 85 } catch (TransformerConfigurationException e) { 86 e.printStackTrace(); 87 } catch (FileNotFoundException e) { 88 e.printStackTrace(); 89 } catch (SAXException e) { 90 e.printStackTrace(); 91 } 92 93 } 94 95 public static void main(String[] args) { 96 97 } 98 }
三、使用JDOM的方式来解析和写XML文件
JDOM中仅使用具体类而不使用接口,API大量使用了Collection类,容易理解。
1 import com.water.entity.Book; 2 import org.jdom2.Attribute; 3 import org.jdom2.Document; 4 import org.jdom2.Element; 5 import org.jdom2.JDOMException; 6 import org.jdom2.input.SAXBuilder; 7 import org.jdom2.output.EscapeStrategy; 8 import org.jdom2.output.Format; 9 import org.jdom2.output.XMLOutputter; 10 11 import java.io.File; 12 import java.io.FileInputStream; 13 import java.io.FileOutputStream; 14 import java.io.IOException; 15 import java.util.ArrayList; 16 import java.util.List; 17 18 public class Jdomxml { 19 private static ArrayList<Book> booklist = new ArrayList(); 20 21 public static ArrayList<Book> getBooklist() { 22 return booklist; 23 } 24 25 private void parseXml(){ 26 Book book; 27 // 创建一个SAXBuileder的对象 28 SAXBuilder saxBuilder = new SAXBuilder(); 29 try { 30 // 创建一个输入流,将xml文件加载到输入流中来 31 FileInputStream fis = new FileInputStream("5264.xml"); 32 // 利用build方法将输入流加载到saxBuilder中 33 Document document = saxBuilder.build(fis); 34 // 通过document对象获取根节点 35 Element rootElement = document.getRootElement(); 36 // 通过根节点来获取子节点的list集合 37 List<Element> childrenList = rootElement.getChildren(); 38 // 对子节点集合进行遍历解析 39 for(Element bk :childrenList){ 40 book = new Book(); 41 System.out.println("现在解析第"+(childrenList.indexOf(bk)+1)+"本书"); 42 // 已知属性名及数量 43 // String id = book.getAttributeValue("ID"); 44 // 解析属性(不知道属性值及数量) 45 List<Attribute> attrs = bk.getAttributes(); 46 for(Attribute attr:attrs){ 47 // 遍历的属性不同于dom和sax方式,它解析出来不包含空白节点和空格 48 String name = attr.getName(); 49 String value = attr.getValue(); 50 if("id".equals(attr.getName())){ 51 book.setId(attr.getValue()); 52 } 53 } 54 // 对book子节点名及内容进行解析 55 List<Element> children = bk.getChildren(); 56 for(Element e :children){ 57 System.out.println(e.getName()+e.getValue()); 58 if("name".equals(e.getName())){ 59 book.setName(e.getValue()); 60 } 61 } 62 booklist.add(book); 63 book = null; 64 System.out.println("结束解析第"+(childrenList.indexOf(bk)+1)+"本书"); 65 } 66 } catch (JDOMException e) { 67 e.printStackTrace(); 68 } catch (IOException e) { 69 e.printStackTrace(); 70 } 71 } 72 73 private void createXml(){ 74 // 生成一个根节点 75 Element rss = new Element("rss"); 76 rss.setAttribute("version","2.0"); 77 // 生成一个document 78 Document document = new Document(rss); 79 Element channel = new Element("channel"); 80 rss.addContent(channel); 81 // 创建节点及添加内容 82 Element title = new Element("title"); 83 title.setText("\"<\"标题名字>"); 84 channel.addContent(title); 85 // 设置格式 86 Format prettyFormat = Format.getPrettyFormat(); 87 prettyFormat.setEncoding("utf-8"); 88 // 设置换行 89 prettyFormat.setIndent(""); 90 91 // 利用xmlOutputter将document转换成xml文件 92 XMLOutputter xmlOutputter = new XMLOutputter(prettyFormat); 93 try { 94 xmlOutputter.output(document,new FileOutputStream(new File("book.xml"))); 95 } catch (IOException e) { 96 e.printStackTrace(); 97 } 98 99 } 100 101 public static void main(String[] args) { 102 103 } 104 }
四、 使用DOM4J的方式来解析和写XML文件
DOM4J是JDOM的一种智能分支,它合并了很多超出基本XML文档表示的功能。它使用了接口和抽象基本类方法,是一个优秀的java XML API,具有性能优异,灵活性好,功能强大和极易使用的特点。
1 import org.dom4j.*; 2 import org.dom4j.io.OutputFormat; 3 import org.dom4j.io.SAXReader; 4 import org.dom4j.io.XMLWriter; 5 6 import java.io.*; 7 import java.util.Iterator; 8 import java.util.List; 9 10 public class Dom4jxml { 11 private void parseXml(){ 12 // 创建SAXReader对象 13 SAXReader sr = new SAXReader(); 14 try { 15 // 通过sr的reader方法加载xml文件,并获取document对象 16 Document read = sr.read(new File("5264.xml")); 17 // 通过read对象获取根节点 18 Element rootElement = read.getRootElement(); 19 // 通过rootElement获取节点迭代器 20 Iterator it = rootElement.elementIterator(); 21 // 遍历迭代器 22 while(it.hasNext()){ 23 Element book = (Element)it.next(); 24 // 获取book的属性名及属性值 25 List<Attribute> attrs = book.attributes(); 26 for(Attribute attr:attrs){ 27 attr.getName(); 28 attr.getValue(); 29 } 30 Iterator its = book.elementIterator(); 31 while(its.hasNext()){ 32 Element bookChild = (Element)its.next(); 33 System.out.println(bookChild.getName()+bookChild.getStringValue()); 34 } 35 } 36 } catch (DocumentException e) { 37 e.printStackTrace(); 38 } 39 } 40 41 private void createXml(){ 42 // 创建document对象,代表整个xml文档 43 Document document = DocumentHelper.createDocument(); 44 // 创建根节点 45 Element rss = document.addElement("rss"); 46 // 向rss节点中添加version属性 47 Element versiion = rss.addAttribute("version", "2.0"); 48 // 生成子节点及子节点内容 49 Element channel = rss.addElement("channel"); 50 Element title = channel.addElement("title"); 51 title.setText("新闻"); 52 // 设置生成xml的格式 53 OutputFormat prettyPrint = OutputFormat.createPrettyPrint(); 54 prettyPrint.setEncoding("gbk"); 55 // 生成xml文件 56 XMLWriter xmlWriter = null; 57 try { 58 xmlWriter = new XMLWriter(new FileOutputStream(new File("book.xml")),prettyPrint); 59 // 设置是否转义,默认值为true,代表转义 60 xmlWriter.setEscapeText(false); 61 xmlWriter.write(document); 62 xmlWriter.close(); 63 } catch (UnsupportedEncodingException e) { 64 e.printStackTrace(); 65 } catch (FileNotFoundException e) { 66 e.printStackTrace(); 67 } catch (IOException e) { 68 e.printStackTrace(); 69 } 70 71 72 } 73 74 public static void main(String[] args) { 75 76 } 77 }