根据一个CRUD的案例,对JAXP解析xml技术,进行详细的解释:
首先,已知一个xml文件中的数据如下:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <书架> <书 出版社="深圳出版社1"><!-- 出版社="深圳出版社1"属性名和属性值 --> <书名>Java</书名> <作者>张泽华</作者> <售价>39.00元</售价> </书> <书 出版社="深圳出版社2"> <书名>JavaScript网页开发</书名> <作者>李红蕾</作者> <售价>28.00元</售价> </书> </书架>
package com.itheima.dom; import java.io.IOException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import junit.framework.Assert; import org.junit.Test; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; /* * * 使用 xml dom 对xml 文件进行 CRUD操作 * 1.读取节点的文本内容 2.读取属性值 3.添加节点 4.删除节点 5.更新节点 6.打印所有元素节点的名称. protected的方法,不让new对象 * */ public class TestDomExercises { // 读取节点的文本内容 : Java就业培训教程 @Test public void testReadContent() throws Exception {// 测试框架异常需要抛出 // 获得代表xml 文件的document 对象 Document document = getDocument(); // 根据标签名 获得 名的标签的 节点 列表 NodeList nl= document.getElementsByTagName("书名"); int length = nl.getLength(); System.out.println("长度 : " + length); // 返回第一个 书名 节点 Node firstBookNameNode = nl.item(0); String result = firstBookNameNode.getTextContent();//String getTextContent() 此属性返回此节点及其后代的文本内容。 Assert.assertEquals("Java", result); } // 2.读取属性值 : 出版社="深圳出版社1" @Test public void testReadAttribute() throws Exception { // 获得document 对象 Document document = getDocument(); NodeList nl = document.getElementsByTagName("书"); // 拿到 第一本书的 节点 对象 // Node firstBookNode = nl.item(0); // 注意:这里查看api 之后, 发现Node里面没有【根据 属性名获得属性值】的方法,而 元素 element 有 直接【根据 属性名获得属性值】的方法, 而这里 拿到的 实际上就是 // 一个 元素 Node节点, 所以 这里 想到了强制类型 转换 , 转换为 元素Element , 然后 根据他的方法的属性名获得属性的值 // 拿到 第一本书 //nl.item(0)返回Node对象,向下转型成Element对象。因为Element里面有直接根据元素找值得方法:getAttribute("出版社");根据名称获取属性的值 Element firstBookElement = (Element) nl.item(0); //String getAttribute(String name) 通过名称获得属性值。 String result = firstBookElement.getAttribute("出版社");//根据属性名获取属性值 Assert.assertEquals("深圳出版社1", result); } // 3.添加节点 : <售价>79.00元</售价> @Test public void testAddPrice() throws Exception, SAXException, IOException { // 获得document 对象 Document document = getDocument(); // 获得第一本书 节点 Node firstBookNode = document.getElementsByTagName("书").item(0); // 创建 售价 节点, 并且将 文本设置为 79.00元 //Element org.w3c.dom.Document.createElement(String tagName) //Element createElement(String tagName) 创建指定类型的元素。 Element createPriceElement = document.createElement("售价"); // createPriceElement.setTextContent("79.00元");//<售价>79.00元</售价> //Node org.w3c.dom.Node.appendChild(Node newChild) firstBookNode.appendChild(createPriceElement);//将节点 newChild 添加到此节点的子节点列表的末尾。如果 newChild 已经存在于树中,则首先移除它。 writeBack2Xml(document); } /* * 回去写代码时, 如果碰到这个 异常 : * * initializationError(org.junit.runner.manipulation.Filter) * * 就是 你 没有 加 @Test 注解 */ // 4.删除节点: <售价>39.00元</售价> @Test public void testDelete() throws Exception, SAXException, IOException { // 获得 document 对象 Document document = getDocument(); // 获得 售价 39.00元的 节点 NodeList priceNodeList = document.getElementsByTagName("售价"); for (int i = 0; i < priceNodeList.getLength(); i++) { // 拿到 每个售价节点 Node node = priceNodeList.item(i); if ("39.00元".equals(node.getTextContent())) { // 如果进来, 则说明找到 39.00元的售价节点 // 拿到当前节点的父节点, 然后 删除 这个 节点 node.getParentNode().removeChild(node); } } // 更新 到 xml 文件 writeBack2Xml(document); } // 5.更新节点 : <售价>79.00元</售价> ---------->> <售价>9.9元</售价> public void testUpdatePrice() { } // 6.打印所有元素节点的名称. @Test public void testPrintAllElementsName() throws Exception, SAXException, IOException { // 获得document 对象 Document document = getDocument(); printAllElementsName(document); } public void printAllElementsName(Node node) { if (Node.ELEMENT_NODE == node.getNodeType()) { // 说明 就是 元素 节点 System.out.println(node.getNodeName()); } NodeList childNodes = node.getChildNodes(); for (int i = 0; i < childNodes.getLength(); i++) { // 拿到 遍历过程中的 每一个 node Node item = childNodes.item(i); printAllElementsName(item); } } // 需要将内存中的document 对象 重新写回到 xml 文件中去 private void writeBack2Xml(Document document) throws TransformerFactoryConfigurationError, TransformerConfigurationException, TransformerException { // 如何弄? // 查看 文档, transformerFacotry --->> Transformer实例 TransformerFactory factory = TransformerFactory.newInstance(); // 获得转换器的 实例对象 Transformer transformer = factory.newTransformer(); // 调用 转换方法 将 内存中document 对象 写到 xml 文件中 去 //abstract void transform(Source xmlSource, Result outputTarget) 将 XML Source 转换为 Result。 //DOMSource正好是Source实现类。而且它有构造方法DOMSource(Node n) 正好接收一个Node //Result实现类有一个StreamResult他的构造方法StreamResult.StreamResult(String systemId) // systemId:Must be a String that conforms to the URI syntax //因此源Source,和结果Result都解决了 transformer.transform(new DOMSource(document), new StreamResult( "src/book.xml")); } // 抽取 方法 (右键——>>refactor--->>rctract method)--->> 重构 -- 抽取 方法 private Document getDocument() throws ParserConfigurationException, SAXException, IOException { // 1. 获得工厂 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); // 2. 获得 builder 对象 DocumentBuilder builder = factory.newDocumentBuilder(); // 3. 拿到 代表xml 文件的document 对象 Document document = builder.parse("src/book.xml"); return document; } }