XML基础编程解析(DOM SAX Dom4J)

前端之家收集整理的这篇文章主要介绍了XML基础编程解析(DOM SAX Dom4J)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。


XML编程:利用java程序去增删改查(CRUD)xml中的数据


解析思想:
dom解析
sax解析
基于这两种解析思想市面上就有了很多的解析api
sun jaxp既有dom方式也有sax方式,并且这套解析api已经加入到j2se的规范中,意味这不需要导入任何第三方开发包就可以直接使用这种解析方式.但是这种解析方式效率低下,没什么人用.
dom4j 可以使用dom方式高效的解析xml.
pull

!!dom4j

导入开发包,通常只需要导入核心包就可以了,如果在使用的过程中提示少什么包到lib目录下在导入缺少的包即可



先看看两种解析思想的比较:



对于Sax解析: 我们先看一个列子

book.xml
  1. <?xml version="1.0" encoding="UTF-8"?>
  2.  
  3. <书架>
  4. <书>
  5. <书名>Java就业培训教程</书名>
  6. <作者>张孝祥</作者>
  7. <售价>39.00元</售价>
  8. </书>
  9. <书>
  10. <书名>JavaScript网页开发</书名>
  11. <作者>张孝祥</作者>
  12. <售价>28.00元</售价>
  13. </书>
  14. </书架>



现在要解析出来: JavaScript网页开发
用SAX解析:
  1. package com.itheima.sax;
  2.  
  3. import javax.xml.parsers.SAXParser;
  4. import javax.xml.parsers.SAXParserFactory;
  5.  
  6. import org.xml.sax.Attributes;
  7. import org.xml.sax.ContentHandler;
  8. import org.xml.sax.Locator;
  9. import org.xml.sax.SAXException;
  10. import org.xml.sax.XMLReader;
  11. import org.xml.sax.helpers.DefaultHandler;
  12.  
  13.  
  14. public class SaxDemo1 {
  15. public static void main(String[] args) throws Exception {
  16. //1.获取解析器工厂
  17. SAXParserFactory factory = SAXParserFactory.newInstance();
  18. //2.通过工厂获取sax解析器
  19. SAXParser parser = factory.newSAXParser();
  20. //3.获取读取器
  21. XMLReader reader = parser.getXMLReader();
  22. //4.注册事件处理器
  23. reader.setContentHandler(new MyContentHandler2() );
  24. //5.解析xml
  25. reader.parse("book.xml");
  26. }
  27. }
  28.  
  29. //适配器设计模式
  30. class MyContentHandler2 extends DefaultHandler{
  31. private String eleName = null;
  32. private int count = 0;
  33. @Override
  34. public void startElement(String uri,String localName,String name,Attributes attributes) throws SAXException {
  35. this.eleName = name;
  36. }
  37. @Override
  38. public void characters(char[] ch,int start,int length)
  39. throws SAXException {
  40. if("书名".equals(eleName) && ++count==2){
  41. System.out.println(new String(ch,start,length));
  42. }
  43. }
  44. @Override
  45. public void endElement(String uri,String name)
  46. throws SAXException {
  47. eleName = null;
  48. }
  49. }
  50.  
  51.  
  52.  
  53.  
  54. class MyContentHandler implements ContentHandler{
  55.  
  56. public void startDocument() throws SAXException {
  57. System.out.println("文档解析开始了.......");
  58. }
  59. public void startElement(String uri,Attributes atts) throws SAXException {
  60. System.out.println("发现了开始标签,"+name);
  61. }
  62. public void characters(char[] ch,int length)
  63. throws SAXException {
  64. System.out.println(new String(ch,length));
  65. }
  66. public void endElement(String uri,String name)
  67. throws SAXException {
  68. System.out.println("发现结束标签,"+name);
  69. }
  70.  
  71. public void endDocument() throws SAXException {
  72. System.out.println("文档解析结束了.......");
  73. }
  74. public void endPrefixMapping(String prefix) throws SAXException {
  75. // TODO Auto-generated method stub
  76. }
  77.  
  78. public void ignorableWhitespace(char[] ch,int length)
  79. throws SAXException {
  80. // TODO Auto-generated method stub
  81. }
  82.  
  83. public void processingInstruction(String target,String data)
  84. throws SAXException {
  85. // TODO Auto-generated method stub
  86. }
  87.  
  88. public void setDocumentLocator(Locator locator) {
  89. // TODO Auto-generated method stub
  90. }
  91.  
  92. public void skippedEntity(String name) throws SAXException {
  93. // TODO Auto-generated method stub
  94. }
  95.  
  96.  
  97.  
  98. public void startPrefixMapping(String prefix,String uri)
  99. throws SAXException {
  100. // TODO Auto-generated method stub
  101. }
  102. }

这里要了解适配器模式,Sax解析的两大步骤:解析器 事件处理器
下面详解解析器步骤:
  1. //1.获取解析器工厂
  2. SAXParserFactory factory = SAXParserFactory.newInstance();
  3. //2.通过工厂获取sax解析器
  4. SAXParser parser = factory.newSAXParser();
  5. //3.获取读取器
  6. XMLReader reader = parser.getXMLReader();
  7. //4.注册事件处理器
  8. reader.setContentHandler(new MyContentHandler2() );
  9. //5.解析xml
  10. reader.parse("book.xml");




理解适配器模式://4.注册事件处理器
我们注册解析处理器的时候用的是:MyContentHandler2而不是MyContentHandler
原因:我们可以看到用MyContentHandler的时候,解析的是整个文档,基于每个标签都会触发事件,这个我们并不需要这样的功能,但是我们要实现特定的标签触发特定的事件,我们就需要一个适配器了,这个适配器MyContentHandler2继承了默认的处理器:extends DefaultHandler
然后我们队需要的处理器中的方法重写即可,为什么用继承,这样在DefaultHandler中已经实现了所有的处理器的方法,知识其它方法在默认处理其中返回的都是null,什么也不做。



对于Dom4J
dom4J是基于dom解析的方式解析的,只是更加的高效。
先了解一下 它的用法
  1. package com.itheima.dom4j;
  2.  
  3. import org.dom4j.Document;
  4. import org.dom4j.Element;
  5. import org.dom4j.io.SAXReader;
  6.  
  7. public class Dom4jDemo1 {
  8. public static void main(String[] args) throws Exception {
  9. //1.获取解析器
  10. SAXReader reader = new SAXReader();
  11. //2.解析xml获取代表整个文档的dom对象
  12. Document dom = reader.read("book.xml");
  13. //3.获取根节点
  14. Element root = dom.getRootElement();
  15. //4.获取书名进行打印
  16. String bookName = root.element("书").element("书名").getText();
  17. System.out.println(bookName);
  18. }
  19. }

这个例子要了解Sax即系的基本步骤:分为那几步
这三部不管是CRUD都是不可少的
  1. SAXReader reader = new SAXReader();
  2. Document dom = reader.read("book.xml");
  3. Element root = dom.getRootElement();



Dom4J的CRUD操作:
  1. package com.itheima.dom4j;
  2.  
  3. import java.io.FileOutputStream;
  4. import java.util.List;
  5.  
  6. import org.dom4j.Attribute;
  7. import org.dom4j.Document;
  8. import org.dom4j.DocumentHelper;
  9. import org.dom4j.Element;
  10. import org.dom4j.io.OutputFormat;
  11. import org.dom4j.io.SAXReader;
  12. import org.dom4j.io.XMLWriter;
  13. import org.junit.Test;
  14.  
  15. public class Demo4jDemo2 {
  16. @Test
  17. public void attr() throws Exception{
  18. SAXReader reader = new SAXReader();
  19. Document dom = reader.read("book.xml");
  20. Element root = dom.getRootElement();
  21. Element bookEle = root.element("书");
  22. //bookEle.addAttribute("出版社","传智出版社");
  23. //String str = bookEle.attributeValue("出版社");
  24. //System.out.println(str);
  25. Attribute attr = bookEle.attribute("出版社");
  26. attr.getParent().remove(attr);
  27. XMLWriter writer = new XMLWriter(new FileOutputStream("book.xml"),OutputFormat.createPrettyPrint());
  28. writer.write(dom);
  29. writer.close();
  30. }
  31. @Test
  32. public void del() throws Exception{
  33. SAXReader reader = new SAXReader();
  34. Document dom = reader.read("book.xml");
  35. Element root = dom.getRootElement();
  36. Element price2Ele = root.element("书").element("特价");
  37. price2Ele.getParent().remove(price2Ele);
  38.  
  39. XMLWriter writer = new XMLWriter(new FileOutputStream("book.xml"),OutputFormat.createPrettyPrint());
  40. writer.write(dom);
  41. writer.close();
  42. }
  43. @Test
  44. public void update()throws Exception{
  45. SAXReader reader = new SAXReader();
  46. Document dom = reader.read("book.xml");
  47. Element root = dom.getRootElement();
  48. root.element("书").element("特价").setText("4.0元");
  49. XMLWriter writer = new XMLWriter(new FileOutputStream("book.xml"),OutputFormat.createPrettyPrint());
  50. writer.write(dom);
  51. writer.close();
  52. }
  53. @Test
  54. public void add()throws Exception{
  55. SAXReader reader = new SAXReader();
  56. Document dom = reader.read("book.xml");
  57. Element root = dom.getRootElement();
  58. //凭空创建<特价>节点,设置标签
  59. Element price2Ele = DocumentHelper.createElement("特价");
  60. price2Ele.setText("40.0元");
  61. //获取标签<书>将特价节点挂载上去
  62. Element bookEle = root.element("书");
  63. bookEle.add(price2Ele);
  64. //将内存中的dom树会写到xml文件中,从而使xml中的数据进行更新
  65. // FileWriter writer = new FileWriter("book.xml");
  66. // dom.write(writer);
  67. // writer.flush();
  68. // writer.close();
  69. //加了一个OutputFormat.createPrettyPrint()格式转化器,作用是让让新增节点对齐
  70. XMLWriter writer = new XMLWriter(new FileOutputStream("book.xml"),OutputFormat.createPrettyPrint());
  71. writer.write(dom);
  72. writer.close();
  73. }
  74. @Test
  75. public void find() throws Exception{
  76. SAXReader reader = new SAXReader();
  77. Document dom = reader.read("book.xml");
  78. Element root = dom.getRootElement();
  79. List<Element> list = root.elements();
  80. Element book2Ele = list.get(1);
  81. System.out.println(book2Ele.element("书名").getText());
  82. }
  83. }





关于一些资料的学习:
Dom4J全而好的文章:http://download.csdn.net/detail/itjavawfc/8075049
Dom4J.1.6.1下载:http://download.csdn.net/detail/itjavawfc/8075067



你所应该知道的Dom4J

创建解析器:

SAXReaderreader=newSAXReader();

利用解析器读入xml文档:
Documentdocument=reader.read(newFile("input.xml"));

获取文档的根节点:

Elementroot=document.getRootElement();

接口继承结构:

Node ---

Branch

--Document

--Element

----

Attribute

Node接口

String

asXML()
asXMLreturnsthetextualXMLrepresentationofthisnode.

将一个节点转换为字符串

String

getName()
getNamereturnsthenameofthisnode.

获取节点的名称,如果是元素则获取到元素名,如果是属性获取属性

short

getNodeType()
Returnsthecodeaccordingtothetypeofnode.

获取节点类型,Node接口上定义了一些静态short类型的常量用来表示各种类型

Element

getParent()
getParentreturnstheparentElementifthisnodesupportstheparentrelationshipornullifitistherootelementordoesnotsupporttheparentrelationship.

获取父节点,如果是根元素调用则返回null,如果是其他元素调用则返回父元素,如果是属性调用则返回属性所依附的元素。

String

getText()
Returnsthetextofthisnode.

返回节点文本,如果是元素则返回标签体,如果是属性则返回属性

List

selectNodes(StringxpathExpression)
selectNodesevaluatesanXPathexpressionandreturnstheresultasaListofNodeinstancesorStringinstancesdependingontheXPathexpression.

利用xpath表达式,选择节点

void

setName(Stringname)
SetsthetextdataofthisnodeorthismethodwillthrowanUnsupportedOperationExceptionifitisread-only.

设置节点的名称,元素可以更改名称属性则不可以,会抛出UnsupportedOperationException异常

void

setText(Stringtext)
SetsthetextdataofthisnodeorthismethodwillthrowanUnsupportedOperationExceptionifitisread-only.

设置节点内容,如果是元素则设置标签体,如果是属性则设置属性的值

void

write(Writerwriter)
writewritesthisnodeasthedefaultXMLnotationforthisnode.

将节点写出到一个输出流中,元素、属性支持

Branch接口(实现了Node接口)

void

add(Elementelement)
AddsthegivenElementtothisbranch.

增加一个子节点

Element

addElement(QNameqname)
AddsanewElementnodewiththegivenQNametothisbranchandreturnsareferencetothenewnode.

增加一个给定名字的子节点,并且返回这个新创建的节点的引用

int

indexOf(Nodenode)
Returnstheindexofthegivennodeifitisachildnodeofthisbranchor-1ifthegivennodeisnotachildnode.

获取给定节点在所有直接点中的位置号,如果该节点不是此分支的子节点,则返回-1

boolean

remove(Elementelement)
RemovesthegivenElementifthenodeisanimmediatechildofthisbranch.

删除给定子元素,返回布尔值表明是否删除成功。

Element接口(实现了Branch,接口)

void

add(Attributeattribute)
AddsthegivenAttributetothiselement.

增加一个属性

Element

addAttribute(QNameqName,Stringvalue)
Addstheattributevalueofthegivenfullyqualifiedname.

为元素增加属性,用给定的属性名和属性值,并返回该元素

Element

addAttribute(Stringname,Stringvalue)
Addstheattributevalueofthegivenlocalname.

为元素增加属性

Attribute

attribute(intindex)
ReturnstheattributeatthespecifiedindexGetsthe

获取指定位置的属性

Attribute

attribute(QNameqName)
DOCUMENTME!

获取指定名称属性

Iterator

attributeIterator()
DOCUMENTME!

获取属性迭代器

List

attributes()
ReturnstheAttributeinstancesthiselementcontainsasabackedListsothattheattributesmaybemodifieddirectlyusingtheListinterface.

获取该元素的所有属性,以一个list返回

String

attributeValue(QNameqName)
Thisreturnstheattributevaluefortheattributewiththegivenfullyqualifiednameornullifthereisnosuchattributeortheemptystringiftheattributevalueisempty.

获取指定名称属性的值,如果不存在该属性返回null,如果存在该属性但是属性值为空,则返回空字符串

Element

element(QNameqName)
Returnsthefirstelementforthegivenfullyqualifiedname.

获取指定名称的子元素,如果有多个该名称的子元素,则返回第一个

Element

element(Stringname)
Returnsthefirstelementforthegivenfullyqualifiedname.

获取指定名称的子元素,如果有多个该名称的子元素,则返回第一个

Iterator

elementIterator()
Returnsaniteratoroverallthiselementschildelements.

获取子元素迭代器

Iterator

elementIterator(QNameqName)
Returnsaniteratorovertheelementscontainedinthiselementwhichmatchthegivenfullyqualifiedname.

获取指定名称的子元素的迭代器

List

elements()
Returnstheelementscontainedinthiselement.

获取所有子元素,并用一个list返回

List

elements(QNameqName)
Returnstheelementscontainedinthiselementwiththegivenfullyqualifiedname.

获取所有指定名称的子元素,并用一个list返回

String

getText()
Returnsthetextvalueofthiselementwithoutrecursingthroughchildelements.

获取元素标签

boolean

remove(Attributeattribute)
RemovesthegivenAttributefromthiselement.

移除元素上的属性

void

setAttributes(Listattributes)
Setstheattributesthatthiselementcontains

将list中的所有属性设置到该元素上

Attribute接口(实现了接口)

QName

getQName()
ReturnstheQNameofthisattributewhichrepresentsthelocalname,thequalifiednameandtheNamespace.

获取属性名称

String

getValue()
Returnsthevalueoftheattribute.

获取属性的值

void

setValue(Stringvalue)
SetsthevalueofthisattributeorthismethodwillthrowanUnsupportedOperationExceptionifitisread-only.

设置属性的值

DocumentHelper

staticAttribute

createAttribute(Elementowner,QNameqname,Stringvalue)

创建一个Attribute

staticDocument

createDocument()

创建一个Document

staticDocument

createDocument(ElementrootElement)

以给定元素作为根元素创建Document

staticElement

createElement(QNameqname)

以给定名称创建一个Element

staticDocument

parseText(Stringtext)
parseTextparsesthegiventextasanXMLdocumentandreturnsthenewlycreatedDocument.

将一段字符串转化为Document

将节点写出到XML文件中去

方法1

调用Node提供的write(Writerwriter)方法,使用默认方式将节点输出到流中:

node.write(newFileWriter("book.xml"));

乱码问题:

Dom4j在将文档载入内存时使用的是文档声明中encoding属性声明的编码集进行编码, 如果在此时使用writer输出时writer使用的内部编码集与encoding不同则会有乱码问题。

FileWriter默认使用操作系统本地码表即gb2312编码,并且无法更改。

此时可以使用OutputStreamWriter(FileOutputStream("filePath"),"utf-8");的方式自己封装 一个指定码表的Writer使用,从而解决乱码问题。

方式2:

利用XMLWriter写出Node:
XMLWriterwriter=newXMLWriter(newFileWriter("output.xml"));
writer.write(node);
writer.close();

乱码问题:

1)使用这种方式输出时,XMLWriter首先会将内存中的docuemnt翻译成UTF-8 格式的document,在进行输出,这时有可能出现乱码问题。

可以使用OutputFormat指定XMLWriter转换的编码为其他编码。

OutputFormatformat=OutputFormat.createPrettyPrint();

format.setEncoding("GBK");
XMLWriterwriter=newXMLWriter(newFileWriter("output.xml"),format);

2Writer使用的编码集与文档载入内存时使用的编码集不同导致乱码,使用字节流 或自己封装指定编码的字符流即可(参照方法1)。

猜你在找的XML相关文章