(四)使用dom4j方式操作xml
dom4j是解析XML的一种开源API,是jdom的升级品,用来读写XML文档。它具有性能优异、功能强大和极易使用的特点,它的性能超过sun公司官方的dom技术。dom4j对Xpath有良好的支持(使用xpath时需要导入jaxen的jar包),dom4j最大的特色使用大量的接口。使用dom4j时需要导入dom4j-xxx.jar包。
Attribute ——Attribute定义了XML的属性
Branch ——Branch为能够包含子节点的节点如XML元素(Element)和文档(Docuemnts)定义了一个公共的行为,
CDATA ——CDATA 定义了XML CDATA 区域
CharacterData——CharacterData是一个标识接口,标识基于字符的节点。如CDATA,Comment, Text.
Comment—— Comment 定义了XML注释的行为
Document—— 定义了XML文档
DocumentType—— DocumentType 定义XML DOCTYPE声明
Element—— Element定义XML 元素
ElementHandler ——ElementHandler定义了 Element 对象的处理器
ElementPath 被 ElementHandler 使用,用于取得当前正在处理的路径层次信息
Entity ——Entity定义 XML entity
Node ——Node为所有的dom4j中XML节点定义了多态行为
NodeFilter ——NodeFilter 定义了在dom4j节点中产生的一个滤镜或谓词的行为(predicate)
ProcessingInstruction ——ProcessingInstruction 定义 XML 处理指令.
Text ——Text 定义XML文本节点.
Visitor—— Visitor 用于实现Visitor模式.
XPath ——XPath 在分析一个字符串后会提供一个Xpath表达式
测试类代码:
1 public class Dom4jTest { 2 private Document doc; 3 4 @Before 5 public void setUp() throws Exception { 6 // 获得xml文档的输入流对象 7 InputStream is = Dom4jTest.class.getClassLoader().getResourceAsStream("books.xml"); 8 // 创建SAXReader对象 9 SAXReader reader = new SAXReader(); 10 // 通过流对象解析xml文档为Document对象 11 doc = reader.read(is); 12 } 13 14 /** 15 * 使用节点迭代器查询元素 16 * @throws Exception 17 */ 18 @Test 19 public void testRetrieve() throws Exception { 20 //获得文档的根节点 21 Element rootElement = doc.getRootElement(); 22 Iterator iterator = rootElement.elementIterator(); 23 while(iterator.hasNext()){ 24 //获得子节点,先转换为Element,有更多的方法 25 Element element = (Element) iterator.next(); 26 String value = element.attributeValue("category"); 27 //获得属性为CHILDREN的book节点 28 if("CHILDREN".equals(value)){ 29 //获得book节点的迭代器 30 Iterator childIterator = element.elementIterator(); 31 while(childIterator.hasNext()){ 32 Node node = (Node) childIterator.next(); 33 //获取子节点的名称 34 String name = node.getName(); 35 if("price".equals(name)){ 36 //获取节点的文本 37 String text = node.getText(); 38 System.out.println(text); 39 } 40 } 41 } 42 } 43 } 44 45 /** 46 * 使用访问器来读取xml文档节点 47 * @throws Exception 48 */ 49 @Test 50 public void testRetrieveByVisitor() throws Exception{ 51 //获得xml文档的输入流对象 52 InputStream is = Dom4jTest.class.getClassLoader().getResourceAsStream("books.xml"); 53 // 创建SAXReader对象 54 SAXReader reader = new SAXReader(); 55 // 通过流对象解析xml文档为Document对象 56 Document doc = reader.read(is); 57 // 获得文档的根节点 58 Element rootElement = doc.getRootElement(); 59 //创建自定义的Visitor对象 60 Visitor visitor = new DomVisitor(); 61 //使用visitor查询文档 62 rootElement.accept(visitor); 63 } 64 65 /** 66 * 创建新的xml文档 67 * @throws Exception 68 */ 69 @Test 70 public void testCreate() throws Exception{ 71 //第一种,创建Document的方法(org.dom4j.Document) 72 //第一种创建方式是对第二种创建方式的封装 73 Document document = DocumentHelper.createDocument(); 74 //第二种,创建Document的方法(org.dom4j.Document) 75 //Document doc = DocumentFactory.getInstance().createDocument(); 76 77 //创建根元素节点 78 Element rootElement = document.addElement("bookstore"); 79 //创建book节点及其子节点 80 Element bookElement = rootElement.addElement("book"); 81 bookElement.addAttribute("CATEGORY", "CODING"); 82 Element title=bookElement.addElement("title"); 83 title.setText("JAVA CODING"); 84 Element author=bookElement.addElement("author"); 85 author.setText("zs"); 86 Element year=bookElement.addElement("year"); 87 year.setText("2010"); 88 Element price=bookElement.addElement("price"); 89 price.setText("69"); 90 //打印到控制台 91 writeToConsole(document); 92 //输出到文件 93 writeToFile(document); 94 } 95 96 //输出到文件 97 private void writeToFile(Document document) throws IOException { 98 //创建美化格式 99 OutputFormat format=OutputFormat.createPrettyPrint(); 100 XMLWriter writer=new XMLWriter 101 (new FileWriter(new File("abook.xml")),format); 102 writer.write(document); 103 //关闭writer就会清空缓存 104 writer.close(); 105 } 106 107 //打印到控制台 108 private void writeToConsole(Document document) throws IOException { 109 //创建输出字符流 110 PrintWriter writer=new PrintWriter(System.out); 111 document.write(writer); 112 //关闭writer就会清空缓存,才会输出来 113 writer.close(); 114 } 115 116 /** 117 * 使用XPath查找节点,xpath序号从1开始 118 * 要使用dom4j的xpath支持,需要导入jaxen包 119 */ 120 @Test 121 public void testXPath() throws Exception{ 122 //获得属性web的book节点 123 Node node = doc.selectSingleNode("//book[@category='WEB']"); 124 //获得所有的book节点 125 List nodes = doc.selectNodes("//book"); 126 //获得第2个book节点 127 Node secondNode = doc.selectSingleNode("//book[2]"); 128 //将xml片段转换为字符串 129 String xml = secondNode.asXML(); 130 System.out.println(xml); 131 } 132 133 @Test 134 public void testStringToXML() throws Exception{ 135 String xmlString="<book category='CHILDREN'><title lang='en'>Harry Potter</title>"+ 136 "<author>J K. Rowling</author><year>2005</year><price>29.99</price></book>"; 137 //转换字符串为xml片段 138 Document document = DocumentHelper.parseText(xmlString); 139 //打印到控制台 140 writeToConsole(document); 141 } 142 143 /** 144 * 删除指定的节点 145 * @throws Exception 146 */ 147 @Test 148 public void testDelete() throws Exception{ 149 //获得最后一个book节点 150 Node node = doc.selectSingleNode("//book[4]"); 151 //获得最后一个book节点的父节点 152 Element parent = node.getParent(); 153 //删除最后一个book节点,删除需要使用父节点来删除,删除成功则返回true 154 Boolean flag=parent.remove(node); 155 System.out.println(flag); 156 //打印到控制台 157 writeToConsole(doc); 158 } 159 160 /** 161 * 修改指定的节点 162 * @throws Exception 163 */ 164 @Test 165 public void testUpdate() throws Exception{ 166 //获得第一个book节点的price和year 167 Node yearNode = doc.selectSingleNode("//book[1]/year"); 168 yearNode.setText("2015"); 169 Node priceNode = doc.selectSingleNode("//book[1]/price"); 170 priceNode.setText("59.00"); 171 //修改后的xml文档打印到控制台 172 writeToConsole(doc); 173 } 174 }
Visitor子类代码:
1 public class DomVisitor extends VisitorSupport { 2 // 使用栈这个数据结构来保存 3 private Stack<String> stack = new Stack<String>(); 4 5 // 数据 6 private String attr; 7 private String title; 8 private String author; 9 private String year; 10 private double price; 11 12 @Override 13 public void visit(Document document) { 14 } 15 16 @Override 17 public void visit(Element node) { 18 // System.out.println("element node-----------"); 19 20 //获得节点的名称 21 String name = node.getName(); 22 if("book".equals(name)){ 23 if(!stack.isEmpty()){ 24 stack.clear(); 25 } 26 stack.push(name); 27 }else if("title".equals(node.getName())){ 28 stack.push(name); 29 }else if("author".equals(name)){ 30 stack.push(name); 31 }else if("year".equals(name)){ 32 stack.push(name); 33 }else if("price".equals(name)){ 34 stack.push(name); 35 } 36 } 37 38 @Override 39 public void visit(Attribute node) { 40 // System.out.println("attribute node-----"); 41 42 String peek = stack.peek(); 43 if("book".equals(peek)){ 44 String value = node.getValue(); 45 if("CHILDREN".equals(value)){ 46 attr=value; 47 } 48 } 49 } 50 51 @Override 52 public void visit(Text node) { 53 // System.out.println("text node--------"); 54 //注意:一个标签元素前后都有一个文本节点 55 if("CHILDREN".equals(attr)){ 56 String tag = stack.peek(); 57 if ("title".equals(tag) && null==title) 58 { 59 title = node.getText(); 60 } 61 else if ("author".equals(tag) && null==author) 62 { 63 author = node.getText(); 64 } 65 else if ("year".equals(tag) && null==year) 66 { 67 year = node.getText(); 68 } 69 else if ("price".equals(tag) && price==0) 70 { 71 price = Double.parseDouble(node.getText()); 72 System.out.println(this.toString()); 73 } 74 } 75 } 76 77 @Override 78 public String toString() { 79 StringBuilder sb=new StringBuilder(); 80 sb.append("book attribute:"+attr); 81 sb.append(" "); 82 sb.append("title:"+title); 83 sb.append(" "); 84 sb.append("author:"+author); 85 sb.append(" "); 86 sb.append("year:"+year); 87 sb.append(" "); 88 sb.append("price:"+price); 89 sb.append(" "); 90 return sb.toString(); 91 } 92 }
使用Visitor子类读取文档结果:
book attribute:CHILDREN
title:Harry Potter
author:J K. Rowling
year:2005