解析xml,几种方式
市面上解析xml分两种方式,1.dom 2.sax ,xml解析常见的一共有三种开发包,1.jaxp 2.jdom 3.dom4j,这三种方式最常用的是dom4j,jaxp和jdom很少有人用,jaxp是sun公司开发的,对于这个sun公司老是我就不知道怎么说他,被收购后我就没法叫,是叫甲骨文还叫原sun公司,别扭,书归正传,jaxp虽然使用起来很烂,但是它是标准,这个我们必须得懂,没准那天对jaxp二次开始开发,它就好用了,还是只得期待的,所以,首先我们来说下jaxp的用法,
jaxp是开发包是j2SE的一部分,它由javax.xml, org.w3c.dom, org.xml.sax,还有其自包组成
在javax.xml.parse包中定义了几个工厂类,程序员可以调用这些工厂类,得到xml的dom和sax解析器,从而实现对xml的解析。
要用jaxp的dom解析xml需要按三步走,
第一步:创建工厂
第二步:拿到一个dom解析器
第三步:得到Document对象
看代码:
1 //创建工厂 2 DocumentBuilderFactory factor = DocumentBuilderFactory.newInstance(); 3 //得到dom解析器 4 DocumentBuilder builder = factor.newDocumentBuilder(); 5 //得到Docuemnt 6 Document document = builder.parse("src/student.xml");
注意DocumentBuilderFactory是一个抽象方类,它向外界提供了一个得到实例的方法,通过工厂在得到dom解析器,dom解析器在加载一个xml让后返回一个文档对象,然后我们就能对文档进行读取了。
得到了Document,然后写几个简单的查询,
我们先读取一下xml文档的所有信息
1 public void read1() throws Exception{ 2 //创建工厂 3 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 4 //得到dom解析器 5 DocumentBuilder builder = factory.newDocumentBuilder(); 6 //得到Document文档对象 7 Document document = builder.parse("src/student.xml"); 8 Node node = document.getElementsByTagName("学校").item(0);//学校是xml的文档根节点 9 list(node);//循环显示 10 } 11 private void list(Node node) { 12 //用于判断node是否为一个节点 13 if(node instanceof Element){ 14 System.out.println(node.getNodeName()); 15 } 16 NodeList childs = node.getChildNodes(); 17 for(int i = 0;i<childs.getLength();i++){ 18 list(childs.item(i)); 19 } 20 }
我们先获取一个节点的值,
1 //创建工厂 2 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 3 //得到一个dom解析器 4 DocumentBuilder builder = factory.newDocumentBuilder(); 5 //得到一个Document对象 6 Document document = builder.parse("src/student.xml"); 7 NodeList list = doc.getElementsByTagName("名字"); 8 //这里我只想得到第一个学生的名字 9 Node node = list.item(0); 10 System.out.println(node.getTextContent());
获取一个节点的Attribute属性的值
1 //创建dom工厂 2 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 3 //得到dom解析器 4 DocumentBuilder builder = factory.newDocumentBuilder(); 5 //得到doc文档 6 Document doc = builder.parse("src/student.xml"); 7 //元素 8 Element bookName = (Element) doc.getElementsByTagName("书名").item(0); 9 String value = bookName.getAttribute("name"); 10 System.out.println(value);
对于xml而言,查询无非就是差标签的值,和标签属性的值,如果大家想深学,想探究jaxp的话,去看帮助文档吧
下面往xml里添加节点
这里我写一个比较难的添加,就是给特定的位置添加节点,这个你会了,正常的添加你也就回了
1 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 2 DocumentBuilder builder = factory.newDocumentBuilder(); 3 Document doc = builder.parse("src/book.xml"); 4 //创建一个新节点 5 Element e = doc.createElement("售价"); 6 e.setTextContent("59.0"); 7 //得到一个参考节点 8 Element refChild =(Element) doc.getElementsByTagName("价格").item(0); 9 //得到要插入的节点 10 Element element = (Element) doc.getElementsByTagName("书").item(0); 11 //添加节点 12 element.insertBefore(e, refChild); 13 14 //把内存里的xml,写回到本地的xml文件 15 TransformerFactory transformerFactory = TransformerFactory.newInstance(); 16 Transformer transformer = transformerFactory.newTransformer(); 17 transformer.transform(new DOMSource(doc), new StreamResult(new FileOutputStream("src/book.xml")));
这里要注意,我们添加完了节点element.insertBefore(e, refChild);之后,没有后面的代码的话我们本地的xml不会增加,为什么呢,那我们加到哪去了。我们这个是添加到了内存里,内存里的xml肯定对了,所以我们要把内存里的xml写回到我们本地。这里用到一个类,就是Transform,这个类能帮助我把内存中的xml写回本地。
添加一个属性
1 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 2 DocumentBuilder builder = factory.newDocumentBuilder(); 3 Document doc = builder.parse("src/book.xml"); 4 5 Element e = (Element) doc.getElementsByTagName("书名").item(0); 6 e.setAttribute("name", "添加的新属性"); 7 8 //把内存里的xml,写回到本地的xml文件 9 TransformerFactory transformerFactory = TransformerFactory.newInstance(); 10 Transformer transformer = transformerFactory.newTransformer(); 11 transformer.transform(new DOMSource(doc), new StreamResult(new FileOutputStream("src/book.xml")));
注意一定要从内存中,写回本地。
删除,删除一定要用父节点来删子节点。
1 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 2 DocumentBuilder builder = factory.newDocumentBuilder(); 3 Document doc = builder.parse("src/book.xml"); 4 5 Element e = (Element) doc.getElementsByTagName("价格").item(0); 6 e.getParentNode().removeChild(e); 7 8 9 TransformerFactory transformerFactory = TransformerFactory.newInstance(); 10 Transformer transformer = transformerFactory.newTransformer(); 11 transformer.transform(new DOMSource(doc), new StreamResult(new FileOutputStream("src/book.xml")));
以上是jaxp对xml的crud。
下面说一下jaxp的sax解析器,对xml的解析,dom解析xml文档时,会把整个读取后的xml放在内存中,在内存中dom树代表Document,这样会有一个问题,如果xml比较大,就会消耗大量的内存,而且很容易造成内存溢出。对于sax解析的话,那么它允许你在读取的时候进行操作,不需要等整个文档加载完成。
sax采用事件处理方式解析xml,一共两个部分 1.解析器 2.事件处理器
解析器可以使用jaxp的api来创建,创建完成,就可以指定解析器去解析某个xml文档。这个解析器解析到xml文档的一个组成部分,都会调用一个事件处理器方法,解析器在调用事件处理器的时,会把当前解析到的xml文件内容作为方法的参数传递给事件处理器。
事件处理器由我们自己编写,我们通过事件处理器总方法的参数,就可以获取到sax解析xml的内容。
一张图,让你更理解sax
想要了解更过,去看ContentHandler 的api
来看一个简单的sax解析,这个一共分5部
1.创建工厂
2.得到解析器
3.得到读取器
4.设置内容处理器
5.读取xml文档内容
看一段代码
//1.创建工厂 SAXParserFactory factory = SAXParserFactory.newInstance(); //2.得到解析器 SAXParser parser = factory.newSAXParser(); //3.得到读取器 XMLReader reader = parser.getXMLReader(); //4.设置内容处理器 //这个内容处理器是我们自己写的,我们自己写的这个类要实现 reader.setContentHandler(null); //5.读取xml文档内容 reader.parse("src/book.xml");
下面我们自己写一个处理器,四个处理器,我们对内容修改,那就要写一个内容处理器ContentHandler,这里实现ContentHandler,常用的方法有startElement(),endElement()
characters()
1 class ListXML implements ContentHandler{ 2 @Override 3 public void startElement(String uri, String localName, String qName, 4 Attributes atts) throws SAXException { 5 } 6 @Override 7 public void endElement(String uri, String localName, String qName) 8 throws SAXException { 9 } 10 @Override 11 public void characters(char[] ch, int start, int length) 12 throws SAXException { 13 } 14 15 @Override 16 public void endDocument() throws SAXException { 17 // TODO Auto-generated method stub 18 19 } 20 21 22 23 @Override 24 public void endPrefixMapping(String prefix) throws SAXException { 25 // TODO Auto-generated method stub 26 27 } 28 29 @Override 30 public void ignorableWhitespace(char[] ch, int start, int length) 31 throws SAXException { 32 // TODO Auto-generated method stub 33 34 } 35 36 @Override 37 public void processingInstruction(String target, String data) 38 throws SAXException { 39 // TODO Auto-generated method stub 40 41 } 42 43 @Override 44 public void setDocumentLocator(Locator locator) { 45 // TODO Auto-generated method stub 46 47 } 48 49 @Override 50 public void skippedEntity(String name) throws SAXException { 51 // TODO Auto-generated method stub 52 53 } 54 55 @Override 56 public void startDocument() throws SAXException { 57 // TODO Auto-generated method stub 58 59 } 60 61 62 63 @Override 64 public void startPrefixMapping(String prefix, String uri) 65 throws SAXException { 66 // TODO Auto-generated method stub 67 68 } 69 70 }
然后我们去查帮助文档,我们会看到一个DefaultHandler,原来人家都给我们写好了,这个我们就可以把多余的方法去掉,
写一个完整的sax读取xml,这个读取xml全部内容,
1 //1.创建工厂 2 SAXParserFactory factory = SAXParserFactory.newInstance(); 3 4 //2.得到解析器 5 SAXParser parser = factory.newSAXParser(); 6 7 //3.得到读取器 8 XMLReader reader = parser.getXMLReader(); 9 10 //4.设置内容处理器 11 reader.setContentHandler(new GetXML()); 12 //5.读取xml文档内容 13 reader.parse("src/book.xml"); 14 15 //下面是一个内容处理器 16 class GetXML extends DefaultHandler{ 17 @Override 18 public void startElement(String uri, String localName, String qName, 19 Attributes attributes) throws SAXException { 20 for(int i = 0 ; atts != null && i < atts.getLength(); i++){ 21 String attrName = atts.getQName(i); 22 String attrVlaue = atts.getValue(i); 23 System.out.println(attrName + "=" + attrVlaue); 24 } 25 System.out.println("<"+qName+">"); } 26 27 @Override 28 public void characters(char[] ch, int start, int length) 29 throws SAXException { 30 System.out.println(new String(ch,start,length)); 31 } 32 33 @Override 34 public void endElement(String uri, String localName, String qName) 35 throws SAXException { 36 System.out.println("<"+qName+"/>"); } 37 }
我觉得sax解析能做到这样就行了。
下面是dom4j,dom4j好用是公认的,曾经也有人做过实验,dom4j,最快,jdom第二,jaxp最慢,第二的就不用学了。
我认为dom4j不用任何人交,不需要交,看文档就可以,提醒大家,看dom4j的xpath的时候找好地方,xpath的文档官方有中文,这一点就很爽,需要什么直接
看文档,养成这个好习惯。
推荐文章
http://xhy0422.javaeye.com/blog/50235