JavaWeb-05 XML基础(Dom解析和Sax解析)

JavaWeb-05

JavaWeb-XML基础(Dom解析和Sax解析)

一、XML的概述(了解)

  • eXtensible Markup Language 可扩展标记语言
  • 宗旨是传输数据,而非显示数据。
  • XML标签没有被预定义,需要用户自行定义标签。
  • XML技术是W3C组织(WorldWideWeConsortium万维网联盟)发布的,目前遵循的是W3C组织于2000年发布的XML1.0规范。
  • 作用:
    a. 传输数据
    b. 配置文件(主要用途)
    
  • XML技术用于解决什么问题?

a. XML语言出现的根本目的在于描述向上图那种有关系的数据。
b. XML是一种通用的数据交换格式。
c. 在XML语言中,它允许用户自定义标签。一个标签用于描述一段数据;一个标签可分为开始标签和结束标签,在起始标签之间,又可以使用其它标签描述其它数据,以此来实现数据关系的描述。
d. XML中的数据必须通过软件程序来解析执行或显示,如IE;这样的解析程序称之为Parser(解析器)。
  • XML常见应用:

    a. 在Java开发中,传统的配置文件是*.properties属性文件(key=value),而XML表示的数据更为丰富。
    b. XML技术除用于描述有关系的数据外,还经常用作软件配置文件,以描述程序模块之间的关系。(如后面将要学习到的Struts、Spring和Hibernate都是基于XML作为配置文件的)
    
    c. 在一个软件系统中,通过XML配置文件可以提高系统的灵活性。即程序的行为是通过XML文件来配置的,而不是硬编码。
    

二、XML的语法(掌握)

1、<?xml version=“1.0”?> 文档声明必须出现在第一句

2、用encoding属性说明文档所使用的字符编码,默认为UTF-8。保存在磁盘上的文件编码要与声明的编码一致。

如:<?xml version=“1.0” encoding=“GB2312”?>

3、用standalone属性说明文档是否独立,即是否依赖其他文档。

如:<?xml version=“1.0” standalone=“yes”?>

4、一个标签有如下两种书写形式:

    包含标签主体:<mytag>some content</mytag>
    不含标签主体:<mytag/>

5、一个XML文档必须有且仅有一个根标签,但所有标签必须合理的嵌套,不允许有交叉嵌套。

如:<mytag1><mytag2></mytag1></mytag2>   WRONG

6、XML中不会忽略主体内容中出现的空格和换行。

7、严格区分大小写

8、注释

<!--这是注释-->

9、CDATA : 把标签当做普通文本内容;

<![CDATA[
    <itcast>www.itcast.cn</itcast>
]]>

Demo

<?xml version = "1.0"  ?>
<!DOCTYPE 书架 SYSTEM "book.dtd">
<书架>
   <书>
    <书名>葵花宝典</书名>
    <作者>陈冠希</作者>
    <售价>100</售价>
   </书>
   <书>
    <书名>金瓶梅</书名>
    <作者>阿娇</作者>
    <售价>80</售价>
   </书>
</书架>

三、XML的约束(看懂即可,掌握引入外部约束文件的语句)

1、为什么需要约束和什么叫做约束?

XML都是用户自定义的标签,若出现小小的错误,软件程序将不能正确地获取文件中的内容而报错。(如:Tomcat)。XML技术中,可以编写一个文档来约束一个XML的书写规范,这个文档称之为约束。总之:约束文档定义了在XML中允许出现的元素名称、属性及元素出现的顺序等等。

2、常见约束:XML DTD、XDR、SOX、XML Schema。

DTD:
<!ELEMENT 书架 (书+)>
<!ELEMENT 书 (书名,作者,售价)>
<!ELEMENT 书名 (#PCDATA)>
<!ELEMENT 作者 (#PCDATA)>
<!ELEMENT 售价 (#PCDATA)>

3、分类:

格式良好的XML:遵循XML语法的XML
有效的XML:遵循约束文档的XML

约束文档定义了在XML中允许出现的元素名称、属性及元素出现的顺序等等。
注意:dtd文档必须用utf-8编码格式保存

4、校验XML的有效性(如何根据DTD中定义的内容来验证XML书写是否正确呢?答:需要软件程序,即解析器)

非校验解析器:

<script type="text/javascript">
<!--
    var xmldoc = new ActiveXObject("Microsoft.XMLDOM");
    xmldoc.validateOnParse = "true" ;
    xmldoc.load("book.xml");
    var reason = xmldoc.parseError.reason;
    var line = xmldoc.parseError.line ;
    document.write(line + ":" + reason) ;

//-->
</script>

校验解析器

a. DTD 文件的引入:
    当引用的DTD文档在本地时,采用如下方式:<!DOCTYPE 根元素 SYSTEM “DTD文档路径”>
    当引用的DTD文档在公共网络上时,采用如下方式:
            <!DOCTYPE 根元素 PUBLIC “DTD名称” “DTD文档的URL”>
            eg : <!DOCTYPE web-app PUBLIC
                    "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
                    "http://java.sun.com/dtd/web-app_2_3.dtd">
b. DTD文件的语法(定义元素、定义属性、定义实体)
    在DTD文档中使用ELEMENT关键字来声明一个XML元素。
    如果子元素用逗号分开,说明必须按照声明顺序去编写XML文档。
    如果子元素用“|”分开,说明任选其一
    用+、*、?来表示元素出现的次数
    定义属性:

        <!ATTLIST 元素名
                属性名1 属性值类型 设置说明
                属性名2 属性值类型 设置说明
                …
        >
                    例如:
        <!ATTLIST 商品
                类别 CDATA #REQUIRED
                颜色 CDATA #IMPLIED

        对应的XML为:<商品 类别=“服装” 颜=色=“黄色”/>
c. Schema(难)

四、XML的解析(掌握)

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

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

XML解析开发包:

JAXP:是SUN公司推出的解析标准实现。
    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

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

解析的方式(使用JAXP)

1、DOM 解析(Java解析) : 利用DOM树来解析

book.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?><书架>
    <书 ISBN="黑马程序员">
        <书名>葵花宝典</书名>
        <作者>陈冠希</作者>
        <售价><会员价>50</会员价></售价>
        <批发价>60</批发价>
    <批发价>60</批发价><批发价>60</批发价></书>
    <书>
        <书名>金瓶梅</书名>
        <作者>阿娇</作者>
        <售价>70</售价>
    </书>
</书架>

Book.java

public class Book {
    private String bookName ;
    private String author ;
    private float price ;
    public String getBookName() {
        return bookName;
    }
    public void setBookName(String bookName) {
        this.bookName = bookName;
    }
    public String getAuthor() {
        return author;
    }
    public void setAuthor(String author) {
        this.author = author;
    }
    public float getPrice() {
        return price;
    }
    public void setPrice(float price) {
        this.price = price;
    }
    @Override
    public String toString() {
        return "Book [bookName=" + bookName + ", author=" + author + ", price="
                + price + "]";
    }
}

DOM_parseXML.java

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;

//演示DOM方式解析XML文件
public class DOM_parseXML {

    public static void main(String[] args) throws Exception {
        //创建一个DOM解析器
        DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder() ;
        //加载文档
        Document document = db.parse("src/book.xml") ; 

//      test1(document) ;
        test2(document) ;
//      test3(document) ;
//      test4(document) ;
//      test5(document) ;
//      test6(document) ;
//      test7(document) ;
    }

//  1、得到某个具体的节点内容 eg:获得金瓶梅的售价
    public static void test1(Document document){

        //获取售价节点的集合
        NodeList nl = document.getElementsByTagName("售价") ;
        //获取金瓶梅的售价节点
        Node node = nl.item(1) ;
        //拿到售价节点的主体内容
        String price = node.getTextContent() ;
        System.out.println(price);

    }
//  2、遍历所有元素节点
    public static void test2(Node node){

        //先拿到node的节点的所有儿子
        NodeList nl = node.getChildNodes() ;
        //循环判断
        for (int i = 0; i < nl.getLength(); i++) {
            Node n = nl.item(i) ;
            if(n.getNodeType() == Node.ELEMENT_NODE){
                //说明节点是标签节点
                System.out.println(n.getNodeName());
                test2(n) ;
            }
        }

    }
//  3、修改某个元素节点的主体内容 eg:修改金瓶梅的价格为70
    public static void test3(Document document) throws Exception{

        //获取售价节点的集合
        NodeList nl = document.getElementsByTagName("售价") ;
        //获取金瓶梅的售价节点
        Node node = nl.item(1) ;
        //修改售价节点的主体内容
        ((Element)node).setTextContent("70") ;

        //将结果写回到硬盘
        Transformer tf = TransformerFactory.newInstance().newTransformer() ;
        tf.transform(new DOMSource(document), new StreamResult("src/book.xml")) ;
    }

//  4、向指定元素节点中增加子元素节点  eg: 给葵花宝典的售价增加一个子节点: 会员价:50
    public static void test4(Document document) throws Exception{
        //获取售价节点的集合
        NodeList nl = document.getElementsByTagName("售价") ;
        //获取葵花宝典的售价节点
        Node node = nl.item(0) ;

        //创建一个新的标签节点: 会员价
        Element el = document.createElement("会员价") ;
        el.setTextContent("50") ;

        //将会员价节点附加到葵花宝典节点后
        node.appendChild(el) ;

        //将结果写回到硬盘
        Transformer tf = TransformerFactory.newInstance().newTransformer() ;
        tf.transform(new DOMSource(document), new StreamResult("src/book.xml")) ;

    }
//  5、向指定元素节点上增加同级元素节点 eg: 给葵花宝典的售价增加一个兄弟节点: 批发价:60
    public static void test5(Document document) throws Exception{

        //获取书节点的集合
        NodeList nl = document.getElementsByTagName("书") ;
        //获取葵花宝典的书节点
        Node node = nl.item(0) ;

        //创建一个新的标签节点: 批发价
        Element el = document.createElement("批发价") ;
        el.setTextContent("60") ;

        //将批发价节点附加到葵花宝典节点后
        node.appendChild(el) ;

        //将结果写回到硬盘
        Transformer tf = TransformerFactory.newInstance().newTransformer() ;
        tf.transform(new DOMSource(document), new StreamResult("src/book.xml")) ;

    }
//  6、删除指定元素节点 eg:删除会员价节点
    public static void test6(Document document) throws Exception{

        //获取售价节点的集合
        NodeList nl = document.getElementsByTagName("售价") ;
        //获取葵花宝典的售价节点
        Node node = nl.item(0) ;
        //获得会员价节点
        Node hnode = node.getLastChild().getPreviousSibling() ;
        System.out.println(hnode.getNodeName());
        node.removeChild(hnode) ;

        //将结果写回到硬盘
        Transformer tf = TransformerFactory.newInstance().newTransformer() ;
        tf.transform(new DOMSource(document), new StreamResult("src/book.xml")) ;

    }
//  7、操作XML文件属性 eg: 给葵花宝典的书节点增加属性: ISBN ="黑马程序员"
    public static void test7(Document document) throws Exception{

        //获取书节点的集合
        NodeList nl = document.getElementsByTagName("书") ;
        //获取葵花宝典的书节点
        Node node = nl.item(0) ;

        //增加属性
        ((Element)node).setAttribute("ISBN", "黑马程序员") ;

        //将结果写回到硬盘
        Transformer tf = TransformerFactory.newInstance().newTransformer() ;
        tf.transform(new DOMSource(document), new StreamResult("src/book.xml")) ;

    }
}

2、SAX 解析 : 边加载边解析

在使用 DOM 解析 XML 文档时,需要读取整个 XML 文档,在内存中构架代表整个 DOM 树的Doucment对象,从而再对XML文档进行操作。此种情况下,如果 XML 文档特别大,就会消耗计算机的大量内存,并且容易导致内存溢出。SAX解析允许在读取文档的时候,即对文档进行处理,而不必等到整个文档装载完才会文档进行操作。

Sax_parser1.java

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

import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

//演示sax解析各个方法调用的时机
public class Sax_parser1 {

    public static void main(String[] args) throws Exception {
        //创建一个Sax解析器
        SAXParser sax = SAXParserFactory.newInstance().newSAXParser() ;
        //获取XML文档的读取器
        XMLReader reader = sax.getXMLReader() ;
        //注册内容处理器
        reader.setContentHandler(new DefaultHandler(){
            //是在加载文档开始的时候执行
            @Override
            public void startDocument() throws SAXException {
                System.out.println("文档解析开始了");
            }
            //文档解析结束时执行
            @Override
            public void endDocument() throws SAXException {
                System.out.println("文档解析结束了");
            }

            //在读取到开始标签的时候执行
            @Override
            public void startElement(String uri, String localName,
                    String qName, Attributes attributes) throws SAXException {
                System.out.println("uri:"+uri+"、localName:"+localName+"、qName:"+qName + " 标签开始了、"+"attributes:"+attributes);
            }
            //是在读取到结束标签的时候执行
            @Override
            public void endElement(String uri, String localName, String qName)
                    throws SAXException {
                System.out.println("uri:"+uri+"、localName:"+localName+"、qName:"+qName +"解析结束了");
            }

            //读取到文本节点的时候执行
            @Override
            public void characters(char[] ch, int start, int length)
                    throws SAXException {
                System.out.println("文档内容: " + new String(ch,start,length));
            }

        }) ;

        //加载文档
        reader.parse("src/book.xml") ;
    }
}

输出结果:

文档解析开始了
uri:、localName:、qName:书架 标签开始了、attributes:com.sun.org.a[email protected]1db9742
文档内容: 

uri:、localName:、qName:书 标签开始了、attributes:com.sun.org.a[email protected]1db9742
文档内容: 

uri:、localName:、qName:书名 标签开始了、attributes:com.sun.org.a[email protected]1db9742
文档内容: 葵花宝典
uri:、localName:、qName:书名解析结束了
文档内容: 

uri:、localName:、qName:作者 标签开始了、attributes:com.sun.org.a[email protected]1db9742
文档内容: 陈冠希
uri:、localName:、qName:作者解析结束了
文档内容: 

uri:、localName:、qName:售价 标签开始了、attributes:com.sun.org.a[email protected]1db9742
uri:、localName:、qName:会员价 标签开始了、attributes:com.sun.org.a[email protected]1db9742
文档内容: 50
uri:、localName:、qName:会员价解析结束了
uri:、localName:、qName:售价解析结束了
文档内容: 

uri:、localName:、qName:批发价 标签开始了、attributes:com.sun.org.a[email protected]1db9742
文档内容: 60
uri:、localName:、qName:批发价解析结束了
文档内容: 

uri:、localName:、qName:批发价 标签开始了、attributes:com.sun.org.a[email protected]1db9742
文档内容: 60
uri:、localName:、qName:批发价解析结束了
uri:、localName:、qName:批发价 标签开始了、attributes:com.sun.org.a[email protected]1db9742
文档内容: 60
uri:、localName:、qName:批发价解析结束了
uri:、localName:、qName:书解析结束了
文档内容: 

uri:、localName:、qName:书 标签开始了、attributes:com.sun.org.a[email protected]1db9742
文档内容: 

uri:、localName:、qName:书名 标签开始了、attributes:com.sun.org.a[email protected]1db9742
文档内容: 金瓶梅
uri:、localName:、qName:书名解析结束了
文档内容: 

uri:、localName:、qName:作者 标签开始了、attributes:com.sun.org.a[email protected]1db9742
文档内容: 阿娇
uri:、localName:、qName:作者解析结束了
文档内容: 

uri:、localName:、qName:售价 标签开始了、attributes:com.sun.org.a[email protected]1db9742
文档内容: 70
uri:、localName:、qName:售价解析结束了
文档内容: 

uri:、localName:、qName:书解析结束了
文档内容: 

uri:、localName:、qName:书架解析结束了
文档解析结束了

Sax_parser2.java

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

import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

//演示获取XML的数据 eg: 读取金瓶梅的作者: 阿娇
public class Sax_parser2 {

    public static void main(String[] args) throws Exception {
        //创建一个Sax解析器
        SAXParser sax = SAXParserFactory.newInstance().newSAXParser() ;
        //获取XML文档的读取器
        XMLReader reader = sax.getXMLReader() ;
        //注册内容处理器
        reader.setContentHandler(new DefaultHandler(){
            int index = 0 ; //记录是第几个作者
            String curName ; //记录当前标签的名字
            @Override
            public void startElement(String uri, String localName,
                    String qName, Attributes attributes) throws SAXException {
                if(qName.equals("作者")){
                    curName = "作者" ;
                    index++ ;
                }
            }
            @Override
            public void endElement(String uri, String localName, String qName)
                    throws SAXException {
                curName = null ;
            }

            @Override
            public void characters(char[] ch, int start, int length)
                    throws SAXException {

                if("作者".equals(curName) && index == 2 ){
                    System.out.println(new String(ch,start,length));
                }
            }
        }) ;

        //加载文档
        reader.parse("src/book.xml") ;
    }
}

输出结果:阿娇

Sax_parser3.java

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.heima.bean.Book;

//演示将XML文档的数据包装成bean
public class Sax_parser3 {

    public static void main(String[] args) throws Exception {
        //创建一个Sax解析器
        SAXParser sax = SAXParserFactory.newInstance().newSAXParser() ;
        //获取XML文档的读取器
        XMLReader reader = sax.getXMLReader() ;
        final List<Book> list = new ArrayList<Book>() ;
        //注册内容处理器
        reader.setContentHandler(new DefaultHandler(){
            Book book = null ;
            String curName ; //记录当前标签的名字
            @Override
            public void startElement(String uri, String localName,
                    String qName, Attributes attributes) throws SAXException {
                curName = qName ;
                if(qName.equals("书"))
                    book = new Book() ;
            }
            @Override
            public void endElement(String uri, String localName, String qName)
                    throws SAXException {
                if("书".equals(qName))
                    list.add(book) ;

                curName = null ;
            }

            @Override
            public void characters(char[] ch, int start, int length)
                    throws SAXException {

                if("书名".equals(curName))
                    book.setBookName(new String(ch,start,length)) ;
                if("作者".equals(curName))
                    book.setAuthor(new String(ch,start,length)) ;
                if("售价".equals(curName))
                    book.setPrice(Float.parseFloat(new String(ch,start,length))) ;

            }
        }) ;

        //加载文档
        reader.parse("src/book.xml") ;

        for (Book book : list) {
            System.out.println(book);
        }
        System.out.println(".....");
        System.out.println(list);
    }
}

a、解析包

* JAXP (sun 公司提供)
* DOM4j (第三方)

b、单元测试

* 搭建环境: 在工程中引入junit包

MyMath.java

public class MyMath {

    public int add(int a ,int b){
        return a + b ;
    }

    public int devide(int a ,int b){
        return a / b ;
    }
}

MyMathTest.java

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

public class MyMathTest {

    /*
     *  测试方法的要求:
     *          1. 方法必须是公有的
     *          2. 返回值必须是void
     *          3. 不能有任何形参
     *          4. 必须有@Test注解
     *
     *     @Before : 是在每个测试方法执行之前先调用的方法
     *     @After: 是在每个测试方法执行之后先调用的方法
     *
     *     @BeforeClass: 是在测试方法执行之前先调用的方法(只会调用一次)
     *     @AfterClass: 是在测试方法执行之前后调用的方法(只会调用一次)
     *
     *     参数: timeout: 用来定义方法执行的最大时间 (毫秒)
     *           expected: 指定预期出现的异常元类
     * */

    static MyMath my ;

//  @Before
//  public void before(){
//      System.out.println("初始化了");
//      my = new MyMath() ;
//  }

    @BeforeClass
    public static  void before(){
        System.out.println("初始化了");
        my = new MyMath() ;
    }

    @Test(timeout=200)
    public void testAdd(){
        Assert.assertEquals(7, my.add(3, 4) ) ;
    }

    @Test(expected=ArithmeticException.class)
    public void testDevide(){

        Assert.assertEquals(2, my.devide(10, 0)) ;
    }

//  @After
//  public void after(){
//      System.out.println("结束了");
//  }

    @AfterClass
    public static void after(){
        System.out.println("结束了");
    }
}

c、测试方法:

1. 测试方法必须是公有的
2. 测试方法必须返回值是void
3. 测试方法必须加@Test
4. 测试方法没有形参

@Test : 代表测试方法
    参数timeout: 指定执行方法所需最多时间(毫秒)
    expected: 指定方法会出现的异常类型(用元类表示)
@Before : 执行每个测试方法之前都要执行的方法
@After  : 执行每个测试方法之后都要执行的方法
@BeforeClass : 执行测试方法之前要执行的方法(静态的,只会执行一次)
@AfterClass  : 执行测试方法之后要执行的方法(静态的,只会执行一次)

五、XML练习案例

1、以如下格式的exam.xml文件为例

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<exam>
    <student idcard="111" examid="222">
        <name>张三</name>
        <location>沈阳</location>
        <grade>89</grade>
    </student>

    <student idcard="333" examid="444">
        <name>李四</name>
        <location>大连</location>
        <grade>97</grade>
    </student>

</exam>

2、编程实现如下功能

3、实现学生信息的添加

4、实现学生信息的查询

5、实现学生的删除功能

练习逻辑图:

<?xml version="1.0" encoding="UTF-8" standalone="no"?><exam>
    <student examid="222" idcard="111">
        <name>张三</name>
        <location>沈阳</location>
        <grade>89</grade>
    </student>
</exam>

Student.java

public class Student {

    private String name ;

    private String location ;

    private int grade ;

    private String examid ;

    private String idcard ;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }

    public int getGrade() {
        return grade;
    }

    public void setGrade(int grade) {
        this.grade = grade;
    }

    public String getExamid() {
        return examid;
    }

    public void setExamid(String examid) {
        this.examid = examid;
    }

    public String getIdcard() {
        return idcard;
    }

    public void setIdcard(String idcard) {
        this.idcard = idcard;
    }

    @Override
    public String toString() {
        return "Student [name=" + name + ", location=" + location + ", grade="
                + grade + ", examid=" + examid + ", idcard=" + idcard + "]";
    }

}

JaxpUtils.java

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 org.w3c.dom.Document;

//工具类
public class JaxpUtils {

    /**
     * 获取文档树
     * @return
     */
    public static Document getDocument(){
        //获取DOM解析器
        try {
            DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder() ;
            Document document = db.parse("src/exam.xml") ;
            return document ;
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null ;
    }
    /**
     * 将内存中的dom树写入硬盘
     * @param document 内存中的dom树
     */
    public static void write2xml(Document document){
        try {
            Transformer tf = TransformerFactory.newInstance().newTransformer() ;
            tf.transform(new DOMSource(document), new StreamResult("src/exam.xml")) ;
        } catch (TransformerConfigurationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (TransformerFactoryConfigurationError e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (TransformerException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

StudentDao.java

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.heima.bean.Student;
import com.heima.utils.JaxpUtils;

public class StudentDao {

    /**
     * 添加学生
     * @param student 要添加的学生
     * @return
     */
    public boolean addStudent(Student student){
        //加载DOM树
        Document document = JaxpUtils.getDocument() ;
        //创建student节点,依次组合
        Element el = document.createElement("student") ;//新建标签
        el.setAttribute("examid", student.getExamid()) ;//给标签添加属性
        el.setAttribute("idcard", student.getIdcard()) ;//同上

        Element nameEl = document.createElement("name") ;
        nameEl.setTextContent(student.getName()) ;
        Element locationEl = document.createElement("location") ;
        locationEl.setTextContent(student.getLocation()) ;
        Element gradeEl = document.createElement("grade") ;
        gradeEl.setTextContent(student.getGrade() + "") ;

        //组合节点
        el.appendChild(nameEl) ;
        el.appendChild(locationEl) ;
        el.appendChild(gradeEl) ;

        //将student节点附加到根节点上
        document.getDocumentElement().appendChild(el) ;

        //写回到硬盘
        JaxpUtils.write2xml(document) ;

        return true ;
    }

    /**
     * 通过准考证号查询学生
     * @param examid 准考证号
     * @return
     */
    public Student findStudentByExamId(String examid){
        //加载DOM树
        Document document = JaxpUtils.getDocument() ;
        //拿到所有的student节点
        NodeList nl = document.getElementsByTagName("student") ;
        //循环判断
        for (int i = 0; i < nl.getLength(); i++) {
            Element n = (Element)nl.item(i) ;
            if(n.getAttribute("examid").equals(examid)){
                //说明找到了需要的节点
                //封装数据
                Student s = new Student() ;
                s.setExamid(examid) ;
                s.setIdcard(n.getAttribute("idcard")) ;
                s.setName(n.getElementsByTagName("name").item(0).getTextContent()) ;
                s.setLocation(n.getElementsByTagName("location").item(0).getTextContent()) ;
                s.setGrade(Integer.parseInt(n.getElementsByTagName("grade").item(0).getTextContent())) ;

                return s ;
            }
        }
        return null ;
    }
    /**
     * 通过姓名删除学生
     * @param name 学生的姓名
     * @return
     */
    public boolean deleteStudentByName(String name){
        //加载DOM树
        Document document = JaxpUtils.getDocument() ;
        //拿到所有的name节点
        NodeList nl = document.getElementsByTagName("name") ;
        //循环判断
        for (int i = 0; i < nl.getLength() ; i++) {
            Element el = (Element) nl.item(i) ;
            if(el.getTextContent().equals(name)){
                //找到了需要删除的学生
                //爷爷干掉父亲
                el.getParentNode().getParentNode().removeChild(el.getParentNode()) ;

                //写回到硬盘
                JaxpUtils.write2xml(document) ;
                return true ;
            }
        }
        return false ;
    }

}

StudentView.java

import java.util.Scanner;

import com.heima.bean.Student;
import com.heima.dao.StudentDao;

public class StudentView {

    static Scanner scan = new Scanner(System.in) ;
    static StudentDao dao = new StudentDao() ;

    public static void main(String[] args) {
        System.out.println(" 添加学生 (a) 查询学生 (b) 删除学生 (c) ");
        System.out.println("请选择操作:");
        String op = scan.next() ;

        if("a".equalsIgnoreCase(op)){
            //添加学生
            boolean flag = addStudent() ;
            if(flag)
                System.out.println("添加成功");
            else
                System.out.println("添加失败");
        }else if("b".equalsIgnoreCase(op)){
            //查询学生
            Student s = findStudentByExamId() ;
            if(s != null)
                System.out.println(s);
            else
                System.out.println("查无此人");
        }else if("c".equalsIgnoreCase(op)){
            //删除学生
            boolean flag = deleteStudentByName() ;
            if(flag)
                System.out.println("删除成功");
            else
                System.out.println("删除失败");
        }
    }

    private static boolean deleteStudentByName() {
        System.out.println("请输入学生姓名: ");
        String name = scan.next() ;

        //直接调用dao完成业务逻辑
        return dao.deleteStudentByName(name);
    }

    private static Student findStudentByExamId() {
        System.out.println("请输入准考证号:");
        String examid = scan.next() ;

        //调用dao完成业务逻辑

        return dao.findStudentByExamId(examid);
    }

    private static boolean addStudent() {
        System.out.println("请输入姓名:");
        String name = scan.next() ;
        System.out.println("请输入身份证号:");
        String idcard = scan.next() ;
        System.out.println("请输入准考证号:");
        String examid = scan.next() ;
        System.out.println("请输入地址:");
        String location = scan.next() ;
        System.out.println("请输入分数:");
        String grade = scan.next() ;

        //封装数据
        Student s = new Student() ;
        s.setExamid(examid) ;
        s.setIdcard(idcard) ;
        s.setName(name) ;
        s.setLocation(location) ;
        s.setGrade(Integer.parseInt(grade));

        //做业务逻辑

        return dao.addStudent(s) ;
    }

}

资料下载

时间: 2024-10-05 19:30:05

JavaWeb-05 XML基础(Dom解析和Sax解析)的相关文章

XML 解析---dom解析和sax解析

目前XML解析的方法主要用两种: 1.dom解析:(Document Object Model,即文档对象模型)是W3C组织推荐的解析XML的一种方式. 使用dom解析XML文档,该解析器会先把XML文档加载到内存中,生成该XML文档对应的document对象,然后把XML文档中的各个标签元素变成相应的Element对象,文本会变成Text对象,属性会变成Attribute对象,并按这些标签.文本.属性在XML文档中的关系保存这些对象的关系. 缺点:消耗内存,所以使用dom解析XML文档时不能解

java解析XML① 之DOM解析和SAX解析(包含CDATA的问题)

Dom解析功能强大,可增删改查,操作时会将XML文档读到内存,因此适用于小文档: SAX解析是从头到尾逐行逐个元素解析,修改较为不便,但适用于只读的大文档:SAX采用事件驱动的方式解析XML.如同在电影院看电影一样,从头到尾看一遍,不能回退(Dom可来来回回读取),在看电影的过程中,每遇到一个情节,都会调用大脑去接收处理这些信息.SAX也是相同的原理,每遇到一个元素节点,都会调用相应的方法来处理.在SAX的解析过程中,读取到文档开头.文档结尾,元素的开头和元素结尾都会调用相应方法,我们可以在这些

DOM解析和SAX解析的对比

SAX & DOM 解析对比 SAX 解析特点 只读 从上向下 速度快 解析的时候相对比较繁琐,有5个代理方法,每个代理方法都要写一定代码 适合大的 XML 文件解析 在计算机领域,针对 XML 解析,还有 DOM 解析方式,在 PC 端和服务器端被广泛使用 背景 主要用在 PC 端或者服务器端 苹果提供了 NSXML 类支持 DOM 方式的解析 不过 NSXML 类只能用在 MAC 开发,在 iOS 中无法直接使用 DOM 特点 DOM 方式不仅能解析 XML 文档,还能够修改: 增加节点/删

非常简单的XML解析(SAX解析、pull解析)

这里只是把解析的数据当日志打出来了 非常简单的xml解析方式 1 package com.example.demo.service; 2 3 import java.io.IOException; 4 import java.io.InputStream; 5 6 import javax.xml.parsers.DocumentBuilder; 7 import javax.xml.parsers.DocumentBuilderFactory; 8 import javax.xml.parse

XML解析(二) SAX解析

XML解析之SAX解析: SAX解析器:SAXParser类同DOM一样也在javax.xml.parsers包下,此类的实例可以从 SAXParserFactory.newSAXParser() 方法获得. 注意SAXParser的parse()方法: parse(String uri, DefaultHandler dh),parse(File f, DefaultHandler dh)等都需要传递一个DefaultHandler的对象. 查看API帮助手册可知,SAX解析是事件驱动的,De

dom解析和sax解析的区别

dom 和 sax 解析方法的区别 1,dom解析的优点是对文档crud比较方便,缺点是占用内存较多2,sax解析的优点是占用内存少,解析速度快,缺点是只适合做文档的读取,不适合做文档的crud 解析方式1 dom是将整个文档加载进内存,所以内存消耗会很大,当文档的太大时,不适合用Dom  dom文档加载进内存后作为一个Document对象,把每个节点当作一个Element对象,如果该元素有内容,就将该内容作为一个Text对象,所以dom对文档的crud很方便2 sax是一行一行的解析,并且不能

XML文件解析DOM解析和SAX解析

解析一个XML文档有哪些内容解析有:dom和sax两种dom:把整个XML文档放入内存,适合XML随机访问,占用内存资源大sax:事件驱动型的XML解析方式,顺序读取,不用一次装载整个文件,遇到标签会触发一个事件,适合对XML的顺序访问,占用内存资源稍小 Node: XML 文档的 documentElement 属性是根节点. nodeName 属性是节点的名称.nodeName 是只读的 元素节点的 nodeName 与标签名相同 属性节点的 nodeName 是属性的名称 文本节点的 no

006_03Java解析XML之DOM方式与SAX方式

XML解析方式分为两种:DOM方式和SAX方式 DOM:Document Object Model,文档对象模型.这种方式是W3C推荐的处理XML的一种方式. SAX:Simple API for XML.这种方式不是官方标准,属于开源社区XML-DEV,几乎所有的XML解析器都支持它. XML解析开发包 JAXP:是SUN公司推出的解析标准实现. Dom4J:是开源组织推出的解析开发包. JDom:是开源组织推出的解析开发包. JAXP: JAXP:(Java API for XML Proc

Java学习总结(21)——XML文档解析:DOM解析,SAX解析

一.XML简介1.可扩展性标记语言(eXtensible Markup Language)2.XML用于描述数据3.应用场合:(1)持久化存储数据(2)数据交换(3)数据配置4.XML语法(1)文档类型:在编写XML文档时,需要先使用文档声明,声明XML文档的类型.最简单的声明语法:<?Xml version="1.0" ?>用encoding属性说明文档的字符编码:<?Xml version="1.0" encoding="GB2312