XML现在已经成为一种通用的数据交换格式,它的平台无关性,语言无关性,系统无关性,给数据集成与交互带来了极大的方便。
XML解析方式分为两种:dom和sax dom:(Document Object Model, 即文档对象模型) 是 W3C 组织推荐的处理 XML 的一种方式。 sax: (Simple API for XML) 不是官方标准,但它是 XML 社区事实上的标准,几乎所有的 XML 解析器都支持它。 XML解析器 Crimson、Xerces 、Aelfred2 XML解析开发包 Jaxp、Jdom、dom4j
JAXP 开发包是J2SE的一部分,它由javax.xml、org.w3c.dom 、org.xml.sax 包及其子包组成,在javax.xml.parsers 包中,定义了几个工厂类,程序员调用这些工厂类,可以得到对xml文档进行解析的 DOM 或 SAX 的解析器对象。
代码实现:
package com.itheima.dom.jdk; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Document; public class JdkDomParserUtil { /** * 将XML文件转化为Document对象到内存 * @param path * @return document * @throws Exception */ public static Document getDocument(String path) throws Exception{ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder=factory.newDocumentBuilder(); Document document = builder.parse(path); return document; } /** * 将内存中Document写入文件 * @param document * @param path * @throws Exception */ public static void writeDocument2Xml(Document document,String path) throws Exception { Transformer transformer=TransformerFactory.newInstance().newTransformer(); transformer.transform(new DOMSource(document), new StreamResult(path)); } }
实现操作代码:
package com.itheima.dom.jdk; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class JdkDomParser { /** * 获取文档节点中第二个书中作者的文本内容 * @param document * @return Node * @throws Exception */ public static String findXmlInfo(String path) throws Exception{ Document document=JdkDomParserUtil.getDocument(path); NodeList nodes=document.getElementsByTagName("作者"); Node node=nodes.item(1); return node.getFirstChild().getNodeValue(); } /** * 在第二个书中添加一个节点,如: * <市场价>5000</市场价> * @param document * @throws Exception */ public static void addNode2Xml(String path) throws Exception{ Document document=JdkDomParserUtil.getDocument(path); Element element=document.createElement("市场价"); element.setTextContent("5000"); Element elementParent=(Element) document.getElementsByTagName("书").item(1); elementParent.appendChild(element); JdkDomParserUtil.writeDocument2Xml(document, path); } /** * 将第二本书<市场价>5000</市场价>修改成<批发价格>300</批发价格> * @throws Exception */ public static void modifyNode2Xml(String path) throws Exception{ Document document=JdkDomParserUtil.getDocument(path); Element newElement=document.createElement("批发价格"); newElement.setTextContent("300"); Element olderElement = (Element) document.getElementsByTagName("市场价").item(0); document.getElementsByTagName("书").item(1).replaceChild(newElement, olderElement); JdkDomParserUtil.writeDocument2Xml(document, path); } /** * 将第二本书<批发价格>300</批发价格>节点删除 * @throws Exception */ public static void deleteNode2Xml(String path) throws Exception{ Document document=JdkDomParserUtil.getDocument(path); Element element = (Element) document.getElementsByTagName("批发价格").item(0); document.getElementsByTagName("书").item(1).removeChild(element); JdkDomParserUtil.writeDocument2Xml(document, path); } }
实验数据:books.xml
<?xml version="1.0" encoding="UTF-8"?> <书架> <书> <书名>葵花宝典</书名> <作者>宋美成</作者> <售价>200</售价> </书> <书> <书名>菊花宝典</书名> <作者>黑马程序员</作者> <售价>400</售价> </书> <书> <书名>菜花宝典</书名> <作者>宋美成3</作者> <售价>800</售价> </书> </书架>
测试代码:
package com.itheima.junit; import org.junit.Test; import com.itheima.dom.jdk.JdkDomParser; public class DomParserJDKTest { private static String path="src//books.xml"; @Test public void testFindDocumentInfo() { try { String info=JdkDomParser.findXmlInfo(path); System.out.println(info); } catch (Exception e) { e.printStackTrace(); } } @Test public void testAddNode2Document() { try { JdkDomParser.addNode2Xml(path); } catch (Exception e) { e.printStackTrace(); } } @Test public void testModifyNode2Xml(){ try { JdkDomParser.modifyNode2Xml(path); } catch (Exception e) { e.printStackTrace(); } } @Test public void testDeleteNode2Xml(){ try { JdkDomParser.deleteNode2Xml(path); } catch (Exception e) { e.printStackTrace(); } } }
测试结果省略......
核心代码: 使用SAXParserFactory创建SAX解析工厂 SAXParserFactory spf = SAXParserFactory.newInstance(); 通过SAX解析工厂得到解析器对象 SAXParser sp = spf.newSAXParser(); 通过解析器对象得到一个XML的读取器 XMLReader xmlReader = sp.getXMLReader(); 设置读取器的事件处理器 xmlReader.setContentHandler(new BookParserHandler());
通过Sax解析XML文档,然后将数据填充到相对应的JavaBean中.
package com.itheima.sax; import java.util.ArrayList; import java.util.List; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; import com.itheima.domain.Book; public class SaxParserTest2 { public static void main(String[] args) throws Exception { SAXParser parser=SAXParserFactory.newInstance().newSAXParser(); XMLReader reader=parser.getXMLReader(); final List<Book> books = new ArrayList<Book>(); reader.setContentHandler(new DefaultHandler(){ Book book = null; String name = null; //记住不同的标签 public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if("书".equals(qName)){ book = new Book(); } name = qName; } public void endElement(String uri, String localName, String qName) throws SAXException { if("书".equals(qName)){ books.add(book); } name = null; } public void characters(char[] ch, int start, int length) throws SAXException { if("书名".equalsIgnoreCase(name)){ book.setName(new String(ch,start,length)); } if("作者".equalsIgnoreCase(name)){ book.setAuthor(new String(ch,start,length)); } if("售价".equalsIgnoreCase(name)){ book.setPrice(Double.parseDouble(new String(ch,start,length))); } } }); reader.parse("src//books.xml"); for(Book b:books){ System.out.println(b); } } }
虽然DOM4J代表了完全独立的开发结果,但最初,它是JDOM的一种智能分支。它合并了许多超出基本XML文档表示的功能,包括集成的XPath支持、XML Schema支持以及用于大文档或流化文档的基于事件的处理。它还提供了构建文档表示的选项,它通过DOM4J API和标准DOM接口具有并行访问功能。从2000下半年开始,它就一直处于开发之中。 为支持所有这些功能,DOM4J使用接口和抽象基本类方法。DOM4J大量使用了API中的Collections类,但是在许多情况下,它还提供一些替代方法以允许更好的性能或更直接的编码方法。直接好处是,虽然DOM4J付出了更复杂的API的代价,但是它提供了比JDOM大得多的灵活性。 在添加灵活性、XPath集成和对大文档处理的目标时,DOM4J的目标与JDOM是一样的:针对Java开发者的易用性和直观操作。它还致力于成为比JDOM更完整的解决方案,实现在本质上处理所有Java/XML问题的目标。在完成该目标时,它比JDOM更少强调防止不正确的应用程序行为。 DOM4J是一个非常非常优秀的Java XML API,具有性能优异、功能强大和极端易用使用的特点,同时它也是一个开放源代码的软件。如今你可以看到越来越多的Java软件都在使用DOM4J来读写XML,特别值得一提的是连Sun的JAXM也在用DOM4J.
代码实现(根据参考官方文档Quick Start----由于dom4j为第三方开发工具,记得导入相关架包):
package com.itheima.util; import java.io.FileOutputStream; import org.dom4j.Document; import org.dom4j.io.OutputFormat; import org.dom4j.io.SAXReader; import org.dom4j.io.XMLWriter; public class Dom4jParserUtil { public static Document getDocument(String url) { SAXReader reader = null; Document document = null; try { reader = new SAXReader(); document = reader.read(url); } catch (Exception e) { e.printStackTrace(); } return document; } public static void writeDocument2Xml(Document document, String url) { try { // Pretty print the document to System.out OutputFormat format = OutputFormat.createPrettyPrint(); XMLWriter writer = new XMLWriter(new FileOutputStream(url), format); writer.write(document); writer.close(); } catch (Exception e) { e.printStackTrace(); } } }
结合XPathTutorial结合使用
package com.itheima.junit; import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.dom4j.Node; import org.junit.Test; import com.itheima.util.Dom4jParserUtil; public class Dom4jParserXPath { /* * 1、得到某个具体的节点内容 * 2、遍历所有元素节点 * 3、修改某个元素节点的主体内容 * 4、向指定元素节点中增加子元素节点 * 5、向指定元素节点上增加同级元素节点(父结点.insertBefore(new,old)) * 6、删除指定元素节点 * 7、操作XML文件属性 */ //1、得到某个具体的节点内容 获取第二个本的作者 private static String url = "src//books.xml"; @Test public void test1(){ Document document=Dom4jParserUtil.getDocument(url); //Element root = document.getRootElement(); //Element secondBookEle = (Element) root.elements("书").get(1); //String text=secondBookEle.element("作者").getText(); Element authorEle=(Element) document.selectSingleNode("/书架/书[2]/作者"); System.out.println(authorEle.getText()); } //2、遍历所有元素节点 @Test public void test2(){ Document document=Dom4jParserUtil.getDocument(url); Element root = document.getRootElement(); walkTree(root); } private void walkTree(Element element){ System.out.println(element.getName()); for(int i=0;i<element.nodeCount();i++){ Node node = element.node(i); if(node instanceof Element){ walkTree((Element) node); } } } //3、修改某个元素节点的主体内容 将第二本书的售价改为500 @Test public void test3(){ Document document=Dom4jParserUtil.getDocument(url); //Element root = document.getRootElement(); Element salePriceEle = (Element) document.selectSingleNode("/书架/书[2]/售价"); salePriceEle.setText("500"); Dom4jParserUtil.writeDocument2Xml(document, url); } //4、向指定元素节点中增加子元素节点 在第二本书中售价之后添加<批发价>600</批发价> @Test public void test4(){ Document document=Dom4jParserUtil.getDocument(url); // Element root = document.getRootElement(); Element secondBookEle = (Element) document.selectSingleNode("/书架/书[2]"); Element priceEle = DocumentHelper.createElement("批发价"); priceEle.setText("600"); secondBookEle.add(priceEle); Dom4jParserUtil.writeDocument2Xml(document, url); } //5、向指定元素节点上增加同级元素节点 在第二本中售价之前添加<内部价>714</内部价> @SuppressWarnings("unchecked") @Test public void test5(){ Document document=Dom4jParserUtil.getDocument(url); // Element root = document.getRootElement(); Element secondBookEle = (Element) document.selectSingleNode("/书架/书[2]"); Element innerpriceEle = DocumentHelper.createElement("内部价"); innerpriceEle.setText("714"); secondBookEle.elements().add(2, innerpriceEle); Dom4jParserUtil.writeDocument2Xml(document, url); } //6、删除指定元素节点 在第二本书中删除<批发价>标签 @Test public void test6(){ Document document=Dom4jParserUtil.getDocument(url); // Element root = document.getRootElement(); Element secondBookEle = (Element) document.selectSingleNode("/书架/书[2]"); // Element price = secondBookEle.element("批发价"); Element price = (Element) document.selectSingleNode("/书架/书[2]/批发价"); secondBookEle.remove(price); Dom4jParserUtil.writeDocument2Xml(document, url); } //7、操作XML文件属性 在 第一本书添加id属性,如<书 id="l7814"> @Test public void test7(){ Document document=Dom4jParserUtil.getDocument(url); // Element root = document.getRootElement(); Element firstBookEle = (Element) document.selectSingleNode("/书架/书[1]"); firstBookEle.addAttribute("id","y11"); Dom4jParserUtil.writeDocument2Xml(document, url); } }
为 XML 文档的已解析版本定义了一组接口。解析器读入整个文档,然后构建一个驻留内存的树结构,然后代码就可以使用 DOM 接口来操作这个树结构。优点:整个文档树在内存中,便于操作;支持删除、修改、重新排列等多种功能;缺点:将整个文档调入内存(包括无用的节点),浪费时间和空间;使用场合:一旦解析了文档还需多次访问这些数据;硬件资源充足(内存、CPU)。
为解决DOM的问题,出现了SAX。SAX ,事件驱动。当解析器发现元素开始、元素结束、文本、文档的开始或结束等时,发送事件,程序员编写响应这些事件的代码,保存数据。优点:不用事先调入整个文档,占用资源少;SAX解析器代码比DOM解析器代码小,适于Applet,下载。缺点:不是持久的;事件过后,若没保存数据,那么数据就丢了;无状态性;从事件中只能得到文本,但不知该文本属于哪个元素;使用场合:Applet;只需XML文档的少量内容,很少回头访问;机器内存少;
相关参考链接:1.解析XML常用技术分析(各种方式优劣之处)
2.android解析XML文档的各种方式