XML编程CRUD(包括JDK自带的DOM和SAX解析以及DOM4J第三方解析)和Schema的使用

 CRUD:

C:create   R:retrieve U:update  D:delete

XML解析技术概述

XML解析方式分为两种:DOM方式和SAX方式

  • DOM:Document Object Model,文档对象模型。这种方式是W3C推荐的处理XML的一种方式。
  • SAX:Simple API for XML。这种方式不是官方标准,属于开源社区XML-DEV,几乎所有的XML解析器都支持它。

两种解析方式的优缺点:

首先DOM解析XML也是在内存中形成一个树状结构。
DOM解析:

把整个XML文档先加载到内存中,形成树状结构。
缺点:如果文档非常大,加载到内存中容易产生内存溢出的问题。
优点:因为节点与节点之间有关系,进行增删改非常方便。
SAX解析:

基于事件驱动的,边读边解析。
缺点:不能进行增删改的操作。
优点:文档大也不会有内存溢出的问题,

XML解析开发包

  • JAXP:是SUN公司推出的解析标准实现。
  • Dom4J:是开源组织推出的解析开发包。(牛,大家都在用,包括SUN公司的一些技术的实现都在用)
  • JDom:是开源组织推出的解析开发包。

JAXP

JAXP:(JAVA API for XML Processing)开发包是JavaSE的一部分,它由以下几个包及其子包组成:

  • org.w3c.dom:提供DOM方式解析XML的标准接口。
  • org.xml.sax:提供SAX方式解析XML的标准接口。
  • javax.xml:提供了解析XML文档的类。
javax.xml.parsers包中,定义了几个工厂类。我们可以通过调用这些工厂类,得到对XML文档进行解析的DOM和SAX解析器对象。

  • DocumentBuilderFactory
  • SAXParserFactory
javax.xml.parsers包中的DocumentBuilderFactory用于创建DOM模式的解析器对象,DocumentBuilderFactory是一个抽象工具类,它不能直接实例化,但该类提供了一个newInstance方法,这个方法会根据本地平台默认安装的解析器,自动创建一个工厂的对象并返回。


获得JAXP中的DOM解析器

  • 调用DocumentBuilderFactory.newInstance()  方法得到创建DOM解析器的工厂。
  • 调用工厂对象的newDocumentBuilder方法得到DOM解析器对象。
  • 调用DOM解析器对象的parse() 方法解析XML文档,得到代表整个文档的Document对象,进而可以利用Document对象对XML文档进行操作了。
JAXP的DOM编程

     DOM解析器在解析XML文档时,会把文档中的所有元素,按照其出现的层次关系,解析成一个个Node对象(节点)

    在DOM中,节点之间的关系如下:

  • 位于一个节点之上的节点是该节点的父节点(parent)
  • 一个节点之下的节点是该节点的子节点(children) 
  • 同一层次,具有相同父节点的节点是兄弟节点(sibling) 
  • 一个节点的下一个层次的节点集合是节点后代(descendant)
  • 父、祖父节点及所有位于节点上面的,都是节点的祖先(ancestor) 
    Node对象:

  • Node对象提供了一系列常量来代表节点的类型,当获取某个Node类型后,就可以把Node节点转换成相应的节点对象(Node的子类对象),以便于调用其特有的方法(查看JDK文档)
  • Node对象提供了相应的方法去获得它的父节点或子节点通过这些方法可以读取整个XML文档的内容、或添加、修改、删除XML文档的内容了。
    DOM方式解析XML文件

  • 获取指定节点的集合。
  • 查找某一个节点。
  • 删除节点。
  • 更新节点内容。
  • 添加节点。
  • 获取所有的节点的名称(递归遍历)。
  • 指定的节点之前插入新节点。
  • 获取标签的属性值。

     具体步骤如下:

  • 通过document.getElementsByTagName(" ") 可以获取节点集合,返回NodeList
  • 通过Document.createElement(" ") 可以创建元素对象。
  • Node对象中可以设置文本内容setTextContent()
  • 通过Node的appendChild() 方法加入子节点
  • 需要把内存中的DOM树形结构回写到XML文件中
  • TransformerFactory工厂类创建Transformer回写类,通过transform(Source,Result)方法回写XML。
  • NEW DOMSource(document) 和new StreamResult(xml)回写。
  • 递归方法就是自己调用自己
<span style="font-size:18px;"><span style="font-size:18px;">public static void getNodeName(Node node){
if(node.getNodeType() == Node.ELEMENT_NODE){
System.out.println(node.getNodeName());
}
NodeList nodeList = node.getChildNodes();
for(int i=0;i<nodeList.getLength();i++){
Node child = nodeList.item(i);
getNodeName(child);
}
}

</span></span>
  JAXP的DOM方式更新XML文档

    javax.xml.transform包中的Transformer类用于把代表XML文件的Document对象转换成某种格式后进行输出,例如把XML文件应用样式表后转成一个HTML文档。利用这个对象,当然也可以把Document对象又重新写入到一个XML文件中。
   Transformer类通过transform方法完成转换操作,该方法接收一个源和一个目的地。我们可以通过:

  • javax.xml.transform.dom.DOMSource 类来关联要转换的document对象。
  • 用javax.xml.transform.stream.StreamResult对象来表示数据的目的地。
   Transformer对象通过TransformerFactory获得。

示例如下:

book2.xml

<span style="font-size:18px;"><span style="font-size:18px;"><?xml version="1.0" encoding="UTF-8" standalone="no"?><书架>
	<书 编号="b2">
		<书名>javaweb开发大全</书名>
		<作者>班长</作者>
		<售价>99.8元</售价>
		<简介>这是不错啊</简介>
	</书>
	<书>
		<书名>葵花宝典</书名>
		<作者>岳不群</作者>
		<售价>99.8两</售价>
		<简介>欲练此功...</简介>
	<猫>我是猫</猫></书>
</书架></span></span>

JaxpDomTest.java

<span style="font-size:18px;"><span style="font-size:18px;">package cn.itcast.jaxp;

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;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import cn.itcast.utils.JaxpDomUtil;

/**
 * JAXP的DOM解析XML
 * @author Administrator
 *
 */
public class JaxpDomTest {
	
	public static void main(String[] args) {
		try {
			run2();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 获取作者的文本内容
	 * @throws Exception 
	 */
	public static void run1() throws Exception{
		// 获取解析器工厂类
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		// 获取解析器对象
		DocumentBuilder builder = factory.newDocumentBuilder();
		// 解析XML的文档,返回document对象
		Document document = builder.parse("src/book2.xml");
		// 获取作者元素对象的集合,返回NodeList
		NodeList nodeList = document.getElementsByTagName("作者");
		// 循环遍历,拿到每一个作者,打印文本的内容,getTextContent()
		for(int i=0;i<nodeList.getLength();i++){
			Node node = nodeList.item(i);
			System.out.println(node.getTextContent());
		}
	}
	
	
	/**
	 * 需求:在第二本下,在末尾添加子节点
	 * @throws Exception
	 */
	public static void run2() throws Exception{
		// 获取工厂类
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		// 获取解析器
		DocumentBuilder builder = factory.newDocumentBuilder();
		// 解析xml,返回document对象
		Document document = builder.parse("src/book2.xml");
		// 获取第二本书
		Node book2 = document.getElementsByTagName("书").item(1);
		// 创建元素对象
		Element cat = document.createElement("猫");
		// 设置文本内容
		cat.setTextContent("我是猫");
		// 把元素对象添加到第二本书下
		book2.appendChild(cat);
		// 回写
		// 创建回写类的工厂
		TransformerFactory transformerFactory =  TransformerFactory.newInstance();
		// 获取回写类
		Transformer transformer = transformerFactory.newTransformer();
		// 调用回写的方法
		transformer.transform(new DOMSource(document), new StreamResult("src/book2.xml"));
	}
	
	/**
	 * 删除节点
	 * @throws Exception 
	 */
	public static void run3() throws Exception{
		String path = "src/book2.xml";
		// 获取文档对象
		Document document = JaxpDomUtil.getDocument(path);
		// 获取猫
		Node cat = document.getElementsByTagName("猫").item(0);
		// 获取书(猫的父节点)
		Node book2 = cat.getParentNode();
		// 通过书删除猫
		book2.removeChild(cat);
		// 回写
		JaxpDomUtil.writeXML(document, path);
	}
	
}</span></span>
封装回写和获取Document的工具类:JAXPDOMUtil.java

<span style="font-size:18px;"><span style="font-size:18px;">package cn.itcast.utils;

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;

/**
 * JAPTDOM解析的工具类
 * @author Administrator
 *
 */
public class JaxpDomUtil {
	
	/**
	 * 通过path获取document对象
	 * @param path
	 * @return
	 * @throws Exception 
	 */
	public static Document getDocument(String path) throws Exception{
		// 获取工厂类
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		// 获取解析器对象
		DocumentBuilder builder = factory.newDocumentBuilder();
		// 解析xml
		return builder.parse(path);
	}
	
	/**
	 * 回写方法
	 * @param document
	 * @param path
	 * @throws Exception
	 */
	public static void writeXML(Document document,String path) throws Exception{
		// 获取回写类的工厂
		TransformerFactory factory = TransformerFactory.newInstance();
		// 获取回写类
		Transformer transformer = factory.newTransformer();
		// 回写
		transformer.transform(new DOMSource(document), new StreamResult(path));
	}

}
</span></span>

SAX解析(JAVA中的JAXP有SAX解析)

  • 在使用DOM解析XML文档时,需要读取整个XML文件,在内存中架构代表整个DOM树的Document对象,从而再对XML文档进行操作。此种情况下,如果XML文档特别大就会消耗计算机的大量内存,并且容易导致内存溢出。
  • SAX解析允许在读取文档时,即时对文档进行处理,而不必等到整个文档装载完才会对文档进行操作。
  • SAX采用事件处理的方式解析XML文件,利用 SAX 解析 XML 文档,涉及两个部分:解析器和事件处理器(通过API和图)
    解析器可以使用JAXP的API创建,创建出SAX解析器后,就可以指定解析器去解析某个XML文档。
    解析器采用SAX方式在解析某个XML文档时,它只要解析到XML文档的一个组成部分,都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,会把当前解析到的xml文件内容作为方法的参数传递给事件处理器。
    事件处理器由程序员编写,程序员通过事件处理器中方法的参数,就可以很轻松地得到sax解析器解析到的数据,从而可以决定如何对数据进行处理。
SAX解析原理

SAX 是事件驱动的 XML 处理方法

  • 它是基于事件驱动的
  • startElement() 回调在每次 SAX 解析器遇到元素的起始标记时被调用
  • characters() 回调为字符数据所调用 
  • endElement() 为元素的结束标记所调用  
  • DefaultHandler类(在 org.xml.sax.helpers 软件包中)来实现所有这些回调,并提供所有回调方法默认的空实现

SAX的事件驱动模型


SAX DocumentHandler示例

SAX 解析器采用了基于事件的模型,它在解析XML文档的时候可以触发一系列的事件
发生相应事件时,将调用一个回调方法

  • Start document
  • Start element (config)            <?xml version=“1.0” encoding=“utf-8”?>
  • Characters (whitespace)       <config>
  • Start element (server)           <server>UNIX</server>
  • Characters (UNIX)                </config>      
  • End element (server)
  • Characters (whitespace)
  • End element (config)
  • End document

使用SAX方式解析XML

(1)使用SAXParserFactory创建SAX解析工厂

         SAXParserFactory   spf = SAXParserFactory.newInstance();

(2)通过SAX解析工厂得到解析器对象

         SAXParser sp = spf.newSAXParser();

(3)通过解析器对象解析XML文件

         xmlReader.parse("book.xml", new XMLContentHandler());

        注意这里的XMLContentHandler继承DefaultHandler

SAX举例说明

 public class XMLContentHandler extends DefaultHandler{
   //当前元素中的数据
   private String currentData;
   //取得元素数据
   public void characters(char[] ch, int start, int length)
  throws SAXException {
      currentData=new String(ch,start,length);
    }
 //在解析整个文档结束时调用
  public void endDocument() throws SAXException {
        System.out.println("结束文档");
  }
   //在解析元素结束时调用
  public void endElement(String uri, String localName, String name)
   throws SAXException {
      System.out.println("节点数据 *************************"+this.currentData);
      System.out.println("结束元素 ************"+name);
   }

  //在解析整个文档开始时调用
  public void startDocument() throws SAXException {
     System.out.println("开始文档");
   }
   //在解析元素开始时调用
  public void startElement(String uri, String localName, String name,
   Attributes attributes) throws SAXException {
      System.out.println("开始元素 ************"+name);
  }
}

   JAXP的SAX解析XML文档示例如下:

<span style="font-size:18px;"><span style="font-size:18px;">package cn.itcast.jaxp.sax;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
 * SAX的入门
 * @author Administrator
 *
 */
public class JaxpSaxTest {
	
	public static void main(String[] args) {
		try {
			run1();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 获取所有的解析的内容
	 * @throws Exception 
	 * @throws ParserConfigurationException 
	 */
	public static void run1() throws Exception{
		// 获取SAX的解析器工厂
		SAXParserFactory factory = SAXParserFactory.newInstance();
		// 获取解析器
		SAXParser parser =  factory.newSAXParser();
		// 解析
		parser.parse("src/book2.xml", new MyHandler2());
	}
}


/**
 * 获取作者标签的文本内容
 * 	
 */
class MyHandler2 extends DefaultHandler{
	// 如果解析到作者标签的时候,flag设置成true
	private boolean flag = false;
	private int count = 0;
	
	/**
	 * 默认解析开始标签,默认调用该方法
	 */
	public void startElement(String uri, String localName, String qName,
			Attributes attributes) throws SAXException {
		// 如果要是作者标签,flag设置成true
		if("作者".equals(qName)){
			flag = true;
			count++;
		}
	}

	/**
	 * 能控制characters的输出,我只在解析作者标签的时候,才打印
	 */
	public void characters(char[] ch, int start, int length)
			throws SAXException {
		// 如果flag是true,就打印
		// 每一次都打印
		if(flag && count == 1){
			String str = new String(ch,start,length);
			System.out.println(str);
		}
	}
	
	/**
	 * 
	 */
	public void endElement(String uri, String localName, String qName)
			throws SAXException {
		// flag恢复成false
		flag = false;
	}
}


/**
 * 自己事件处理器
 * 重写三方法
 * @author Administrator
 *
 */
class MyHandler extends DefaultHandler{
	
	/**
	 * 只要一解析到开始标签的时候,默认调用该方法,把解析的内容赋值给参数。
	 */
	public void startElement(String uri, String localName, String qName,
			Attributes attributes) throws SAXException {
		System.out.println("开始标签:"+qName);
	}
	
	/**
	 * 只要解析到文本的内容,默认调用该方法
	 */
	public void characters(char[] ch, int start, int length)
			throws SAXException {
		String str = new String(ch,start,length);
		System.out.println(str);
	}

	/**
	 * 解析到结束标签的时候,默认调用方法,把解析的内容赋值给参数。
	 */
	public void endElement(String uri, String localName, String qName)
			throws SAXException {
		System.out.println("结束标签:"+qName);
	}
	
</span><h2><span style="font-size:18px;">}</span></h2></span>

DOM4J解析XML文档

  • Dom4j是一个简单、灵活的开放源代码的库。Dom4j是由早期开发JDOM的人分离出来而后独立开发的。与JDOM不同的是,dom4j使用接口和抽象基类,虽然Dom4j的API相对要复杂一些,但它提供了比JDOM更好的灵活性。 
  • Dom4j是一个非常优秀的Java XML API,具有性能优异、功能强大和极易使用的特点。现在很多软件采用的Dom4j,例如Hibernate,包括sun公司自己的JAXM也用了Dom4j。
  • 使用Dom4j开发,需下载dom4j相应的jar文件。

DOM4J的使用技巧一:查找标签文本

查找节点的文本内容(想要查找内容,需要一层一层的去查找内容,通过根节点去查找子节点,再查找子节点的子节点)查找方法如下:
  • 创建解析器 new SAXReader()
  • 解析xml   read()
  • 获取根节点  getRootElement()
  • 获取所有的一级目录下指定标签的集合   root.elements(标签名)
  • 返回List集合,可以遍历集合或者getIndex()获取Element对象
  • 获取文本getText()

DOM4J使用技巧二:在指定的节点中添加子节点

  • 创建解析器 new SAXReader()
  • 解析xml    read()
  • 获取根节点   getRootElement()
  • 获取所有的指定标签的集合   root.elements(标签名)
  • 直接调用addElement()设置子节点。
  • 使用setText()设置文本
  • 回写xml文件
  OutputFormat format = OutputFormat.createPrettyPrint();
  format.setEncoding("UTF-8");
  XMLWriter writer = new XMLWriter(new FileOutputStream("src/book2.xml"),format);
  writer.write(document);
  writer.close();

DOM4J使用技巧三:在指定的位置新增节点

  • 创建元素标签节点 DocumentHelper.createElement()
  • 设置文本 setText()
  • 获取某个标签下的所有子节点elements(),返回List集合
  • 通过list.add(index, element) 方法在内存中加入子元素
  • 回写XML

DOM4J使用技巧四:修改节点文本和删除节点

(1)修改指定节点的文本内容  
  • 找到指定的节点elements()
  • 修改文本内容  setText()
(2)删除节点
  • 找到要删除的节点
  • 通过父节点调用remove()方法删除

DOM4J使用技巧五:DOM4J对XPATH的支持

提供了一种书写方式,可以很方便的找到XML标签(xpath属于第三方包可以通过xpath文档学习XPATH的语法)

(1)DOM4J使用XPATH有两种方法

  • selectNodes()。
  • selectSingleNode() 可以直接使用document.selectNodes(xpath),不再需要先获取根节点了。非常的方便
(2)DOM4J使用XPATH还需要引入jar包

      jaxen-1.1-beta-6.jar

关于XPATH的语法实例如下(常用的有如下三个实例,具体的可以查询文档):

  实例1:基本的XPath语法类似于在一个文件系统中定位文件,如果路径以斜线 / 开始, 那么该路径就表示到一个元素的绝对路径



实例二:如果路径以双斜线 // 开头, 则表示选择文档中所有满足双斜线//之后规则的元素(无论层级关系)


实例三:星号 * 表示选择所有由星号之前的路径所定位的元素




DOM4J使用技巧六:DOM4J获取Document对象

DOM4J中获得Document对象的方式有三种:
(1)读取XML文件,获得document对象
    SAXReader reader = new SAXReader();
    Document document = reader.read(new File("input.xml"));
(2)解析XML形式的文本,得到document对象
    String text = "<member></member>"
    Document document = DocumentHelper.parseText(text);
(3)主动创建document对象
   Document document = DocumentHelper.createDocument();
   // 创建根节点
   Element root = document.addElement("members");

DOM4J使用技巧七:节点对象

(1)获取文档的根节点:Element  root = document.getRootElement();
(2)获取某个节点的子节点 Element element = node.element("书名");
(3)取得节点的文字   String text = node.getText();
(4)取得某节点下所有名为"member"的子节点,并进行遍历
    List nodes = rootElm.elements("member");
    for(Iterator it=nodes.iterator; it.hasNext();){
    Element eLm = (Element)it.next();
   // do someing
    }
(5)对某节点下的所有子节点进行遍历
    for(Iterator it=root.elementIterator();it.hasNext();){       
     Element element = (Element) it.next();
       // do something  
    }
(6)在某节点下添加子节点 Element ageElm = newMemberElm.addElement("age");
(7)设置节点文字   element.setText("XXXYYY");
(8)删除某节点 
     // childElm 是待删除的节点,parentElm是其父节点
    parentElm.remove(childElm)
(9)添加一个CDATA节点
   Element contentELm = infoElm.addElement("content");
   contentElm.addCDATA(diary.getContent())

DOM4J使用技巧七:节点对象属性

(1)取得某节点下的某属性
     Element root = document.getRootElement();
    // 属性名name
   Attribute attribute = root.attribute("size");
(2)取得属性的文字
   String text = attribute.getText();
(3)删除某属性
    Attribute attribute = root.attribute("size");
    root.remove(attribute);
(4)遍历某节点的所有属性
    Element root=document.getRootElement();
    for(Iterator it=root.attributeIterator();it.hasNext();){
       Attribute attribute = (Attribute)it.next();
       String text = attribute.getText();
       System.out.println(text);
    }
(5)设置某节点的属性和文字
   newMemberElm.addAttribute("name", "sitinspring");
(6)设置属性的文字
   Attribute attribute = root.attribute("name");
   attribute.setText("sitinspring");

DOM4J使用技巧八:将文档写入XML文件

(1)文档中全为英文,不设置编码,直接写入的形式
  XMLWriter wriyer = new XMLWriter(new FileWriter("output.xml"));
  writer.write(document);
  writer.close();
(2)文档中含有中文,设置编码格式写入的形式
  OutputFormat format=OutputFormat.createPrettyPrint();
  //指定XML编码
  format.setEncoding("GBK");
  XMLWriter writer=new XMLWriter(new FileWriter("output.xml"));
  writer.write(document);
  writer.close();

DOM4J使用技九:在指定位置插入节点

(1)得到插入位置的节点列表(list)
(2)调用list.add(index,element), 由index决定element的插入位置。
   Element元素可以通过DocumentHelper对象得到。示例代码:
   Element aaa=DocumentHelper.createElement("aaa");
   aaa.setText("aaa");
   List list = root.element("书").elements();
   list.add(1,aaa);
   // 更新Document

DOM4J使用技十:字符串与XML转换

(1)将字符串转为XML
  String text ="<members> <member>sitinspring</member></members>";
  Document document=DocumentHelper.parseText(text);
(2)将文档或节点的XML转为字符串
  SAXReader reader=new SAXReader();
  Document document=reader.read(new File("input.xml"));
  Element root=document.getRootElement();
  String docXMLText = document.asXML();
  Element memberElm = root.element("member");
  String memberXmlText = memberElm.asXML();

Dom4J示例如下:
src/book2.xml
<?xml version="1.0" encoding="UTF-8"?>

<书架> 
  <书> 
    <书名>javaweb开发大全</书名>  
    <作者>班长</作者>  
    <售价>99.8元</售价>  
    <简介>这是不错啊</简介> 
  </书>  
  <书> 
    <书名>葵花宝典</书名>  
    <狗>小狗</狗>  
    <作者>岳不群</作者>  
    <售价>99.8两</售价>  
    <简介>欲练此功...</简介> 
  </书> 
</书架>

测试代码如下:
package cn.itcast.dom4j;

import java.io.FileOutputStream;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

/**
 * DOM4J的解析XML
 * @author Administrator
 *
 */
public class Dom4jTest {
	
	public static void main(String[] args) {
		try {
			run1();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 对XPATH的支持
	 * @throws Exception
	 */
	public static void run6() throws Exception{
		// 获取解析器对象
		SAXReader reader = new SAXReader();
		// 解析XML
		Document document = reader.read("src/book2.xml");
		// List<Node> list = document.selectNodes("/书架/书/作者");
		List<Node> list = document.selectNodes("//作者");
		Node author2 = list.get(1);
		System.out.println(author2.getText());
	}
	
	/**
	 * 修改文本内容
	 * @throws Exception
	 */
	public static void run5() throws Exception{
		// 获取解析器对象
		SAXReader reader = new SAXReader();
		// 解析XML
		Document document = reader.read("src/book2.xml");
		// 获取根节点
		Element root = document.getRootElement();
		// 获取狗的节点
		Element book2 = (Element) root.elements("书").get(1);
		Element dog = book2.element("狗");
		dog.setText("小狗");
		// 回写
		// 回写
		OutputFormat format = OutputFormat.createPrettyPrint();
		// 回写
		XMLWriter writer = new XMLWriter(new FileOutputStream("src/book2.xml"),format);
		writer.write(document);
		writer.close();
	}
	
	/**
	 * 删除子节点
	 * 	删除第二本书下的猫节点
	 */
	public static void run4() throws Exception{
		// 获取解析器对象
		SAXReader reader = new SAXReader();
		// 解析XML
		Document document = reader.read("src/book2.xml");
		// 获取根节点
		Element root = document.getRootElement();
		// 获取猫
		Element book2 = (Element) root.elements("书").get(1);
		Element cat = book2.element("猫");
		// 通过猫获取猫的父节点
		// cat.getParent();
		// 通过父节点删除猫
		book2.remove(cat);
		// 回写
		OutputFormat format = OutputFormat.createPrettyPrint();
		// 回写
		XMLWriter writer = new XMLWriter(new FileOutputStream("src/book2.xml"),format);
		writer.write(document);
		writer.close();
	}
	
	/**
	 * 在第二本书的作者标签之前添加团购价的标签
	 * @throws Exception
	 */
	public static void run3() throws Exception{
		// List
		// 获取解析器对象
		SAXReader reader = new SAXReader();
		// 解析XML
		Document document = reader.read("src/book2.xml");
		// 获取根节点
		Element root = document.getRootElement();
		// 获取第二本书
		Element book2 = (Element) root.elements("书").get(1);
		// 获取书下的所有子节点,返回List集合
		List<Element> list = book2.elements();
		// 创建元素对象	DocumentHelper.createElement("狗")
		Element dog = DocumentHelper.createElement("狗");
		dog.setText("大狗");
		// list.add(index,Element);
		list.add(1, dog);
		
		OutputFormat format = OutputFormat.createPrettyPrint();
		// 回写
		XMLWriter writer = new XMLWriter(new FileOutputStream("src/book2.xml"),format);
		writer.write(document);
		writer.close();
	}
	
	
	/**
	 * 在第二本书下添加子节点
	 */
	public static void run2() throws Exception{
		// 获取解析器对象
		SAXReader reader = new SAXReader();
		// 解析XML,返回Document对象
		Document document = reader.read("src/book2.xml");
		// 获取根节点
		Element root = document.getRootElement();
		// 获取第二本书
		Element book2 = (Element) root.elements("书").get(1);
		// 可以直接在第二本书下添加子节点,设置文本内容
		book2.addElement("猫").setText("我是猫");
		// 回写
		
		// 创建漂亮的格式
		OutputFormat format = OutputFormat.createPrettyPrint();
		//OutputFormat format = OutputFormat.createCompactFormat();
		
		// 设置编码
		format.setEncoding("UTF-8");
		
		// 回写类
		XMLWriter writer = new XMLWriter(new FileOutputStream("src/book2.xml"),format);
		// 回写了文档对象
		writer.write(document);
		// 关闭流
		writer.close();
	}
	
	/**
	 * 获取第二本书作者的文本内容
	 * @throws Exception 
	 */
	public static void run1() throws Exception{
		// 获取解析器对象
		SAXReader reader = new SAXReader();
		// 解析XML,返回Document对象
		Document document = reader.read("src/book2.xml");
		// 获取根节点(书架标签)
		Element root = document.getRootElement();
		// 获取书的节点,获取第二本书
		List<Element> books = root.elements("书");
		Element book2 = books.get(1);
		// 获取作者的标签
		Element author2 = book2.element("作者");
		// 获取文本内容
		System.out.println(author2.getText());
	}

}



XML 约束之Schema

XML Schema也是一种用于定义和描述XML文档结构与内容的模式语言,其出现是为了克服DTD的局限性。
XML Schema VS DTD:
(1)XML Schema语法符合XML语法结构。
(2)DOM、SAX等XML API很容易解析出XML Schema文档中的内容。
(3)XML Schema 对名称空间支持的非常好。
(4)XML Schema比XML DTD支持更多的数据类型,并支持用户自定义新的数据类型。
(5)XML Schema定义约束的能力非常强大,可以对XML实例文档作出细致的语义限制。
(6)XML Schema不能像DTD一样定义实体,比DTD更复杂,但XML Schema现在已经是W3C组织的标准,它在逐步替代DTD。
(7)XML Schema使用一套预先的XML元素和属性创建的,这些元素和属性定义了XML文档的结构和内容模式。XML Schema规定XML文档实例的结构和每个元素/属性的数据类型。
(8)Schema相对于DTD的明显好处是,XML Schema文档本身也是XML文档,而不是像DTD一样使用自成一体的语法。
Schema与DTD的区别:
XML从SGML中继承了DTD,并用它来定义内容的模型,验证和组织元素。同时它也有很多局限:
(1)DTD不可扩展。
(2)DTD不遵循XML语法。
(3)DTD不支持命名空间的应用。
(4)DTD没有提供强大的数据类型支持,只能表示很简单的数据类型。
Schema完全克服了这些弱点,使得基于web的应用系统交换XML数据更为容易。下面是它所展现的一些新特性:
(1)Schema完全基于XML语法,不需要再学习特殊的语法。
(2)Schema能用处理XML文档的工具处理,而不需要特殊的工具。
(3)Schema大大扩充了数据类型,支持booleans、numbers、dates and times、URIs、integers、decimal numbers 和real numbers等。
(4)Schema支持原型,也就是元素的继承。如:我们定义了一个"联系人" 数据类型,然后可以根据它产生“朋友联系人”和“客户联系人”两种数据类型。
(5)Schema支持属性组。我们一般声明一些公共属性,然后可以然后可以应用于所有元素,属性组允许把元素、属性关系放在外部定义、组合。
(6)开放性。原来的DTD只能有一个DTD应用于一个XML文档,现在可以有多个Schema运用于一个XML文档。
Schema的一些概念:
(1)XML Schema文件自身就是一个XML文件,但它的扩展名通常为.xsd
(2)和XML文件一样,一个XML Schema文档也必须有一个根节点,但是这个根结点的名称为schema
(3)应用schema约束开发XML过程
    W3C预先定义元素和属性——>Schema文档(模式文档:约束文档)——>XML文档(实例文档)
(4)编写了一个XML Schema约束文档后,通常需要把这个文件中声明的元素绑定到一个URI地址上,把这个URI地址叫namespace名称空间,以后XML文件就可以通过这个URL(即名称空间)引用绑定指定名称空间的元素。
XMLSchema文档的基本结构:
(1)在W3CXML schema规范中规定:所有的Schema文档都使用<schema>作为根元素
   <?xml version="1.0">
   <xsd:schema>
     ......
   </xsd:schema>
(2)<schema>元素可以包含一些属性。一个XML  Schema声明看起来经常以如下的形式出现:

schema入门案例:book.xsd
<?xml version="1.0" encoding="UTF-8" ?> 
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
					  targetNamespace="http://www. itcast.cn"
					  elementFormDefault="qualified">
	<xs:element name='书架' >
		<xs:complexType>
			<xs:sequence maxOccurs='unbounded' >
				<xs:element name='书' >
					<xs:complexType>
						<xs:sequence>
							<xs:element name='书名' type='xs:string' />
							<xs:element name='作者' type='xs:string' />
							<xs:element name='售价' type='xs:string' />
						</xs:sequence>
					</xs:complexType>
				</xs:element>
			</xs:sequence>
		</xs:complexType>
	</xs:element>
</xs:schema>

<?xml version="1.0" encoding="UTF-8"?>

<itcast:书架 xmlns:itcast="http://www.itcast.cn"
				xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
				xsi:schemaLocation=“http://www.itcast.cn book.xsd">

	<itcast:书>
		<itcast:书名>九阴真经</itcast:书名>
		<itcast:作者>郭靖</itcast:作者>
		<itcast:售价>28.00元</itcast:售价>
	</itcast:书>
</itcast:书架>
在XML Schema文档中声明名称空间。
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
      targetNamespace="http://www. itcast.cn"
      elementFormDefault="qualified"
      attributeFormDefault="qualified"
>
<xs:schema>
  • targetNamespace元素用于指定schema文档中声明的元素属于哪个名称空间
  • elementFormDefault元素用于指定局部元素是否受到该schema指定的targetNamespace所指定的名称空间限定。
  • attributeFormDefault元素用于指定局部属性是否受到该Schema指定targetNamespace

你可能感兴趣的:(XML编程CRUD(包括JDK自带的DOM和SAX解析以及DOM4J第三方解析)和Schema的使用)