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.apache.xerces.internal.parsers.AbstractSAXParser$AttributesProxy@1db9742
文档内容: 

uri:、localName:、qName:书 标签开始了、attributes:com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser$AttributesProxy@1db9742
文档内容: 

uri:、localName:、qName:书名 标签开始了、attributes:com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser$AttributesProxy@1db9742
文档内容: 葵花宝典
uri:、localName:、qName:书名解析结束了
文档内容: 

uri:、localName:、qName:作者 标签开始了、attributes:com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser$AttributesProxy@1db9742
文档内容: 陈冠希
uri:、localName:、qName:作者解析结束了
文档内容: 

uri:、localName:、qName:售价 标签开始了、attributes:com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser$AttributesProxy@1db9742
uri:、localName:、qName:会员价 标签开始了、attributes:com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser$AttributesProxy@1db9742
文档内容: 50
uri:、localName:、qName:会员价解析结束了
uri:、localName:、qName:售价解析结束了
文档内容: 

uri:、localName:、qName:批发价 标签开始了、attributes:com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser$AttributesProxy@1db9742
文档内容: 60
uri:、localName:、qName:批发价解析结束了
文档内容: 

uri:、localName:、qName:批发价 标签开始了、attributes:com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser$AttributesProxy@1db9742
文档内容: 60
uri:、localName:、qName:批发价解析结束了
uri:、localName:、qName:批发价 标签开始了、attributes:com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser$AttributesProxy@1db9742
文档内容: 60
uri:、localName:、qName:批发价解析结束了
uri:、localName:、qName:书解析结束了
文档内容: 

uri:、localName:、qName:书 标签开始了、attributes:com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser$AttributesProxy@1db9742
文档内容: 

uri:、localName:、qName:书名 标签开始了、attributes:com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser$AttributesProxy@1db9742
文档内容: 金瓶梅
uri:、localName:、qName:书名解析结束了
文档内容: 

uri:、localName:、qName:作者 标签开始了、attributes:com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser$AttributesProxy@1db9742
文档内容: 阿娇
uri:、localName:、qName:作者解析结束了
文档内容: 

uri:、localName:、qName:售价 标签开始了、attributes:com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser$AttributesProxy@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) ;
    }

}



资料下载

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值