XML学习笔记

 

时间:2016-11-1 00:57

 

1、XML是指可扩展标记性语言(eXtensible Markup Language),它是一种标记语言,类似于HTML,它被设计的宗旨是传递数据,而非显示数据。
    标记型语言:
        使用标签来操作。
        HTML也是标记型语言。

    可扩展:
        HTML中的标签是固定的,每个标签都有特定的含义。
        XML的标签可以自己定义,也可以写中文的标签。

    XML用途:
        HTML是用于显示数据,XML也可以显示数据。
        XML的主要功能是存储数据。

2、XML技术是W3C组织(World Wide Web Consortium万维网联盟)发布的,目前遵循的是W3C组织于2000年发布的XML1.0规范。
    XML有两个版本:1.0和1.1。
    目前使用的都是1.0版本,因为1.1版本不能向下兼容。

3、XML应用
    (1)不同的系统之间传输数据。
        使用XML保存数据有利于程序的维护。
    (2)用来表示生活中有关系的数据。
        XML语言出现的根本目的在于描述关系型数据。
        XML是一种通用的数据交换格式。
        在XML语言中,它允许用户自定义标签,一个标签用于描述一段数据;一个标签可以分为开始标签和结束标签,在这两个标签之间,又可以使用其他标签来描述其他数据,以此来实现数据关系的描述。
        XML中的数据必须通过软件程序来解析执行或显示,如IE,这样的解析程序称之为Parser(解析器)。
    (3)作为配置文件。
        比如现在连接数据库,可以将数据库的用户名和密码写入配置文件,如果需要修改数据库的信息,则不需要修改源代码,修改配置文件即可,有利于程序的维护。

4、XML的语法
    (1)XML的文档声明
        创建一个文件,扩展名:.xml。
        如果想编写XML文件,第一步必须要有一个文档声明(写了文档声明之后,说明该文档是XML文件的内容)
        格式:
            <?xml version="1.0" encoding="utf-8" ?>(第一个?不允许有空格)
        文档声明必须写在第一行第一列。
        version:表示XML的版本。
        encoding:文档编码,gbk utf-8 iso8859-1(不包含中文)
        standalone:说明文档是否独立,即是否依赖其它文档,如standalone="yes"
            yes:依赖
            no:不依赖

        XML的中文乱码问题:
            编码格式不统一。

    (2)定义元素(标签)
        XML元素指XML文件中出现的标签,一个标签分为起始标签和结束标签(不能省略),一个标签有如下几种书写形式:
            包含标签主体:<mytag> some content </mytag>
            不包含标签主体:<mytag />

        一个标签中可以嵌套若干子标签,但所有标签必须合理的嵌套,不允许有交叉嵌套。
        一个XML文档必须有且仅有一个根标签,其他标签都是这个根标签的子标签或孙标签。

        对于XML标签中出现的所有空格和换行,XML解析程序都会当做标签内容进行处理,例如下面两段内容的意义是不一样的:
            *   <网址>www.baidu.com</网址>
            *   <网址>
                    www.baidu.com
                </网址>
        由于在XML中,空格和换行都作为原始内容(标签)被处理,所以,在编写XML文件时,使用换行和缩进等方式来让源文件中的内容清晰可读的“良好”习惯可能要被迫改变。

        一些XML元素可以包含字母、数字以及其它一些可见字符,但必须遵守下面的一些规范:
            *   区分大小写,例如<P>和<p>是两个不同的标签
            *   不能以数字或下划线开头
            *   不能以XML(或xml Xml)开头
            *   不能包含空格
            *   名字中间不能包含冒号

    (3)定义属性
        一个元素可以有多个属性,每个属性都有他自己的名称和取值,例如:<mytag name="value" />

        属性值一定要用引号(单引号或双引号)括起来。

        属性名称的命名规范与元素的命名规范相同。

        元素中的属性不允许重复。

        在XML技术中,标签属性所代表的信息也可以被改成用子元素的形式来描述,例如:

    (4)注释
        XML的注释和HTML中的注释是相同的。
        在XML声明之前不能有注释,第一行第一列必须是文档声明。
        注释不可以嵌套。

    (5)特殊字符
        对于一些单个字符,若想显示其原始样式,也可以使用转义的形式予以处理:
            特殊字符    替代符号
                &                &amp;
                <                &lt;
                >                &gt;
                "                &quot;
                '                &apos;

    (6)CDATA区
        CDATA是Character Data的缩写,作用是将标签当做普通文本内容。
        可以解决多个字符都需要转义的操作:if (a > b && c < d) { }
        把这些内容放到CDATA区中,就不需要进行转义了。
        语法格式:
            < ! [ CDATA [ 
                if (a > b && c < d) { }    //该内容被当做普通文本,而不是标签。
            ] ] >

    (7)处理指令(PI:Processing Instruction)
        作用:用来指挥软件如何解析XML文档。
        语法:必须以<?作为开头,以?>作为结尾。
        可以在XML中设置样式:
            XML声明:<?xml version="1.0" encoding="utf-8" ?>
            xml-stylesheet指令:
            <?xml-stylesheet type="text/css" href="1.css" ?>
        需要注意的是,对中文命名的标签元素无效。
        XML文件:
            <?xml version="1.0" encoding="UTF-8"?>

            <?xml-stylesheet type="text/css" href="1.css" ?>
            <person>
                <name>zhangsan</name>
                <age>20
                    <sex>aa</sex>
                </age>
            </person>

        CSS文件:
            name {

                
            }
 
            age {
                
            }

5、XML语法规则总结
    所有XML元素都必须关闭标签。
    XML标签区分大小写。
    XML必须正确的嵌套顺序。
    XML文档必须有根元素(只有一个)。
    XML的属性值必须加引号。
    特殊字符必须转义——CDATA区。
    XML中的空格、回车、换行会解析为XML元素。 


6、XML的约束之DTD
    为什么需要约束?
        比如现在定义一个Person的XML文件,只想要这个文件中保存人的信息,比如name、age等,但是如果在XML文件中写了一个标签<cat>,发现也可以正常显示,疑因为符合语法规范,但是cat肯定不是人的信息,XML的标签是自定义的,需要一种约束技术来规定XML中只能出现的元素,这个时候就需要约束。

    XML的约束技术:
        DTD约束
        Schema约束。

7、DTD的快速入门
    DTD(Document Type Definition),全称为文档类型定义。

    步骤:
        (1)创建一个文件,扩展名为:.dtd
        (2)看XML中有多少个元素,有几个元素,在DTD文件中就写几个<!ELEMENT>。
        (3)判断元素是简单元素还是复杂元素。
                复杂元素:有子元素的元素。
                    <!ELEMENT 元素名称 (子元素) >
                简单元素:没有子元素的元素。
                    <!ELEMENT 元素名称 (#PCDATA) >
        (4)在XML文件中引入DTD约束文件
                <!DOCTYPE 根元素名称 SYSTEM "DTD文件URL" >

    当使用浏览器打开XML文件的时候,浏览器只负责校验语法,而不负责校验约束,如果想要校验XML的约束,则需要使用工具。

    使用MyEclipse开发工具:
        创建一个项目
        在src目录中创建一个XML文件和一个dtd文件
        在XML文件中引入dtd文件
        在XML文件中则必须遵循dtd约束

    该约束只是提示语法错误,如果语法没有错误,则依然可以正常显示。

8、DTD的三种引入方式
    (1)引入外部的DTD文件
        <!DOCTYPE 根元素名称 SYSTEM "DTD文件URL" >
    (2)使用内部的DTD文件
        <?xml version="1.0" encoding="UTF-8"?>

        <!-- <!DOCTYPE person SYSTEM "1.dtd" > -->
        <!DOCTYPE person [
            <!ELEMENT person (name, age) >
            <!ELEMENT name (#PCDATA) >
            <!ELEMENT age (#PCDATA) >
        ]>
        <person>
            <name>张三</name>
            <age>21</age>
            <!-- <a>a</a> -->
        </person>
    (3)使用外部的DTD文件(使用网络的DTD文件)
        后面会学到Struts2框架,该框架会使用到外部的DTD文件。

        XML使用DOCTYPE声明语句来指明它所遵循的DTD文档,有两种形式:
            *   当引用的DTD文档在本地时,采用如下方式:
                <!DOCTYPE 根元素 SYSTEM "DTD文件URL" >
            *   当引用的DTD文档在公共网络上时,采用如下方式:
                <!DOCTYPE 根元素 PUBLIC "DTD名称" "DTD文档的URL" >

9、使用DTD定义元素
    在DTD文档中使用ELEMENT关键字来声明一个XML元素。
    语法:<!ELEMENT 元素名称 使用规则>
        使用规则:
            (#PCDATA):只是元素的主体内容只能是普通的文本(Parsed Character Data)
            EMPTY:用于指示元素的主体为空,比如:<br />
            ANY:用于指示元素的主体内容为任意类型。
            (子元素):指示元素中包含的子元素。

        定义子元素及描述它们的关系:
            如果子元素用逗号分开,说明必须按照声明顺序去编写XML文档。
                如:<!ELEMENT FILE (TITLE, AUTHOR, EMAIL) >
            如果子元素用 | 分开,说明任选其一:(类似枚举)
                如:<!ELEMENT FILE (TITLE | AUTHOR | EMAIL) >

            用+、*、?来表示元素出现的次数:
                *   +:表示至少出现一次,或多次。(至少出现1次)
                *   * :表示可有可无,可以出现零次、一次或多次。(0次、1次或多次)
                *   ?:表示可以有也可以无,有的话只能出现一次。(0次或1次)

    简单元素:没有子元素的元素。
        <!ELEMENT name 使用规则 >
            *   (#PCDATA):name只能是字符串类型
            *   EMPTY:name元素的值为空
            *   ANY:可以是任意元素

    复杂元素:
        <!ELEMENT 复杂元素 (子元素) >
            *   <!ELEMENT person (name, age, sex) >
                以上子元素只能出现一次。
            *   <!ELEMENT person (name+, age*, sex?) >
                name可以出现一次或多次,至少出现一次。
                age可以出现任意次数。
                sex可以出现0次或1次。

10、使用DTD定义属性
    语法:
        <!ATTLIST 元素名称
            属性名称 属性类型 属性的约束
        > 

   属性值类型:
        CDATA:表示属性的取值为普通文本。
        ENUMERATED(DTD没有此关键字):表示枚举,只能从枚举列表中任选其一,如(鸡 | 鸭 | 鱼)
        ID:表示属性的取值不能重复,属性的值只能由字母,下划线开始,不能出现空白字符。

    属性约束设置说明:
        #REQUIRED:表示该属性必须出现。
        #IMPLIED:表示该属性可有可无。
        #FIXED:表示属性的取值为一个固定值,语法:#FIXED "固定值"。
        直接值:表示属性的取值为该默认值。

<?xml version="1.0" encoding="UTF-8"?>
<!-- <!DOCTYPE person SYSTEM "1.dtd" >
 -->
//为person定义约束 
<!DOCTYPE person [
    //定义person中只能存在以下五个元素,并且必须按照顺序出现 
    <!ELEMENT person (name, age, sex,school, birthday) >
    //定义name值,name元素的值只能为字符串 
    <!ELEMENT name (#PCDATA) >
    //定义name的属性 
    <!ATTLIST name
        //属性名为ID3,属性类型为ID,约束类型为必须出现 
        ID3 ID #REQUIRED
    >
    //定义age的值,age的值只能为字符串
    <!ELEMENT age (#PCDATA) >
    //定义age的属性 
    <!ATTLIST age
        //属性名为ID2,只能从枚举类型中选择值,约束类型为必须出现 
        ID2 (aa | bb | cc) #REQUIRED
    >
    //定义sex的值,sex的值只能为字符串 
    <!ELEMENT sex (#PCDATA) >
    //定义sex的属性 
    <!ATTLIST sex
        //属性名为ID4,属性类型为字符串,属性约束为可有可无 
        ID4 CDATA #IMPLIED
    >
    //定义school的值,只能是字符串
    <!ELEMENT school (#PCDATA) >
    //定义school属性 
    <!ATTLIST school
        //属性名为ID5,属性值为字符串,固定值为AAAAAA,不能改变
        ID5 CDATA #FIXED "AAAAAA"
        //属性名为ID6,属性类型为字符串,如果不赋值,则默认“清华大学”,如果赋值,则以赋值为准 
        ID6 CDATA "清华大学" 
    >
    //定义birthday值,只能是字符串 
    <!ELEMENT birthday (#PCDATA) >
    //定义birthday属性 
    <!ATTLIST birthday
        //属性名为ID1,属性类型为字符串,属性约束为必须出现 
        ID1 CDATA #REQUIRED
    >
]>
<person>
    <name ID3="aa1">张三</name>
    <age ID2="cc">21</age>
    <sex ID4="aa">男</sex>
    <school ID5="AAAAAA">潍坊学院</school>
    <birthday ID1="11">2016</birthday>
</person>


11、定义引用实体
    概念:在DTD中定义,在XML中使用。
    语法:
        <!ENTITY 实体名称 "实体内容" >
    引用方式(注意是在XML中使用):
        &实体名称;

    注意:
        定义实体需要写在内部DTD中,如果写在外部的DTD中,在某些浏览器中无法获取实体对象。

<!DOCTYPE person [
    <!ELEMENT person (name) >
    <!ELEMENT name (#PCDATA) >
    <!ENTITY haha "哈哈" >
]>

<person>
    <name>&haha;</name>
</person>

12、XML的解析(Java代码)
    如何使用JS解析DOM对象?
        根据HTML的层级结构,在内存中分配一个树形结构,把HTML的标签,属性和文本都封装成对象。
        Document对象、Element对象、属性对象、文本对象、Node节点对象。

    XML的解析方式(技术)分为两种:
        DOM和SAX。

        DOM解析:
            Document Object Model,文档对象模型,这种方式是W3C推荐的处理XML的一种方式。
            使用DOM解析的时候,会有一个问题,当文件过大时,会导致内存溢出。
            优点是方便实现增删改查操作。
 
        SAX解析:
            Simple API for XML,这种方式不是官方标准,属于开源社区XML-DEV,几乎所有的XML解析器都支持它。
            采用事件驱动,边读边解析,从上到下,逐行解析,解析到某一个对象,就把对象的名称返回。
            不会造成内存溢出。
            可以方便的实现查询,无法实现增删改操作。 

    XML解析开发包:
        JAXP:是SUN公司推出的解析标准实现。
        Dom4J:是开源组织推出的解析开发包。
        JDom:是开源组织推出的解析开发包。

13、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:
            定义工厂API,使应用程序能够从XML文档获取生成DOM对象树的解析器。
            这是一个抽象类,可以通过newInstance()方法来获取该类实例。
        SAXParserFactory:
            定义工厂API,使应用程序能够配置和获取基于SAX的解析器以解析XML文档。
    还包含了两个类:
        DocumentBuilder:
            定义API,使其从XML文档获取DOM文档实例。
            这是一个抽象类,其对象可以从DocumentBuilderFactory.newDocumentBuilder()方法获取。
            可以通过Document parse(String URL)方法来获取整个Document文档,返回的Document是一个接口,其父接口是Node,Document中找不到的方法,可以到Node接口中去查找。
        SAXParser:
            定义包装XMLReader实现类的API。
        
    Document中的方法:
        NodeList getElementByTagName(String tagName)
            返回标签集合。
        Element createElement(String tagName)
            创建标签。
        Text createTextNode(String data)
            创建文本。
        Node appendChild(Node newChild)
            添加标签。
        Node removeChild(Node oldNode)
            删除节点,并返回oldNode节点。
        Node replaceChild(Node newNode, Node oldNode)
            替换节点,并返回oldNode节点。
        Node getParentNode()
            返回此节点的父节点。
        String getNodeName()
            返回此节点的名称。
        short getNodeType()
            返回此节点的类型。
        String getNodeValue()
            返回此节点的值。
        Node getFirstChild()
            返回此节点的第一个子节点。
        Node getLastChild()
            返回此节点的最后一个子节点。
        Node cloneNode(boolean deep)
            返回此节点的副本。
        Node getPreviousSibling()
            返回此节点之前的兄弟节点。
        Node getNextSibling()
            返回此节点之后的兄弟节点。
        String getTextContent()
            此方法返回此节点及其后代的文本内容。
        void setTextContent(String content)
            设置此节点的文本内容。
        boolean hasChildNodes()
            返回此节点是否具有任何子节点。
        Node insertBefore(Node newNode, Node oldNode)
            在oldNode节点之前插入newNode节点。
        boolean isEqualNode(Node arg)
            测试两个节点是否相等,该方法不仅判断当前节点,还判断当前节点下的子节点。
        boolean isSameNode(Node arg)
            返回此节点是否是与给定节点相同的节点,例如node1.isSameNode(node1);,则返回true,参数为其他节点则返回false。

    NodeList中的方法:
        int getLength()
            列表中节点的个数。
        Node item(int index)
            返回集合中的第index个元素。

    XML回写类:Transformer类(格式化操作比较弱)
        这是一个抽象类,其实例可以通过TransformerFactory.newInstance().newTransformer()方法获取。
        在多线程同时运行时不能使用此类的对象。
        Transformer可以多次使用,可以在转换之间保留参数和输出属性。

    抽象方法:
        abstract void transform(Source xmlSource, Result outputTarget)
            将XMLSource转换为Result。
            可以理解为将内存中的XML树转换为实体文件。

            Source接口:
                是一个接口,其实现类是DOMSource。

            DOMSource类:
                DOMSource类不是一个抽象类。
                构造方法:
                    DOMSource(Node node)
                        创建带有DOM节点的新输入源。

            Result接口:
                该类是一个接口,其实现类是StreamResult。

            StreamResult类:
                该类不是一个抽象类。
                构造方法:
                    StreamResult(String systemId)
                        根据指定URL构造StreamResult。


===============================================================================
14、使用JAXP查询XML文件

    (1)查询XML文件中所有的name值

/**
    * 1、创建解析器工厂DocumentBuilderFactory
    * 2、根据解析器工厂创建解析器
    * 3、解析XML文件,返回Document对象
    * 4、得到所有的name元素 
    * 5、遍历集合
*/
//1、创建解析器工厂
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
//2、创建解析器
DocumentBuilder db = dbf.newDocumentBuilder();
//3、解析XML文件,返回Document对象
Document doc = db.parse("src/XMLDemo/person.xml");
//4、得到所有的name元素
NodeList list = doc.getElementsByTagName("name");
//5、遍历集合
for(int i = 0, length = list.getLength(); i < length; i++)
{
    Node node = list.item(i);
    //得到name元素中的
    String text = node.getTextContent();
    System.out.println(text);
}

------------------------------------------------------------------------------------------------------------------------------
查询XML中第一个name元素的值

/*
     * 1、创建解析器工厂
     * 2、根据解析器工厂创建解析器
     * 3、解析XML文件,返回Document对象
     * 4、得到所有name元素
     * 5、使用得到的NodeList集合,使用item()方法,通过下标获取具体的元素
     * 6、得到具体的文本值getTextContent()
 */
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse("src/XMLDemo/person.xml");
System.out.println(doc.getElementsByTagName("name").item(0).getTextContent()); 



===============================================================================
15、使用JAXP添加元素
    (1)在第一个p1元素后添加sex元素

/*
     * 1、创建解析器工厂
     * 2、根据解析器工厂创建解析器
     * 3、解析XML文件,得到Document对象
     * 4、得到第一个p1
     *     得到所有的p1,然后使用item()方法获取指定元素
     * 5、创建sex标签
     *     createElement()
     * 6、创建文本
     * createTextNode()
     * 7、将文本添加到sex标签下
     *     appendChild()
     * 8、将sex标签添加到第一个p1下
     * 9、回写XML文件
*/
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse("src/XMLDemo/person.xml");
NodeList list = doc.getElementsByTagName("p1");
Node p1 = list.item(0);
//创建sex节点
Node sex = doc.createElement("sex");
//创建文本
Text txt = doc.createTextNode("男");
//将文本添加到sex节点中
sex.appendChild(txt);
//将sex添加到p1中
p1.appendChild(sex);
//回写XML文件
//1、创建Transformer对象
Transformer tf = TransformerFactory.newInstance().newTransformer();
//2、创建输入源
DOMSource dom = new DOMSource(doc);
//3、创建输出流
StreamResult sr = new StreamResult("src/XMLDemo/person.xml");
tf.transform(dom, sr);


===============================================================================

16、使用JAXP修改节点
    将第一个p1下的sex元素内容修改为“女”。

/*
     * 1、创建解析器工厂
     * 2、创建解析器
     * 3、解析XML文件,获取Document对象
     * 4、得到要修改的sex元素
     * 5、修改sex中的值
     *     setTextContent
     * 6、回写XML文件
 * */
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse("src/XMLDemo/person.xml");
//获取sex元素
Node sex = doc.getElementsByTagName("sex").item(0);
//修改sex元素的值
sex.setTextContent("女");
//回写XMl文件
Transformer ts = TransformerFactory.newInstance().newTransformer();
//获取DOMSource对象
DOMSource doms = new DOMSource(doc);
//获取StreamResult对象
StreamResult sr = new StreamResult("src/XMLDemo/person.xml");
ts.transform(doms, sr);


===============================================================================

17、使用JAXP删除节点
    删除sex节点。

/*
     * 1、创建解析器工厂
     * 2、创建解析器
     * 3、解析XML文件,获取Document对象
     * 4、获取sex元素
     * 5、获取sex的父节点
     * 6、删除sex节点
     *     removeChild(Node node)
     * 7、回写XML文件
     * */
 
//1、获取Document对象
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse("src/XMLDemo/person.xml");
//获取sex元素
Node sex = doc.getElementsByTagName("sex").item(0);
System.out.println(sex.getTextContent());
//获取sex的父节点
Node p1 = sex.getParentNode();
//删除sex节点
System.out.println(p1.removeChild(sex));
//回写XML文件
//获取Transformer对象
Transformer ts = TransformerFactory.newInstance().newTransformer();
//获取DOMSource对象
DOMSource doms = new DOMSource(doc);
//获取StreamResult对象
StreamResult sr = new StreamResult("src/XMLDemo/person.xml");
ts.transform(doms, sr);


===============================================================================

18、使用JAXP遍历节点

public static void main(String[] args) throws Exception
{
    /*
         * 1、创建解析器工厂
         * 2、根据解析器工厂创建解析器
         * 3、解析XML文件,返回Document对象
         * -------------------------------------------------
         * 使用递归实现
         * 4、得到根节点
         * 5、得到根节点的子节点
         * 6、得到根节点子节点的子节点
     */
    //使用JAXP遍历节点
    //获取Document对象
    Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse("src/XMLDemo/person.xml");
    digui(doc,"");
}
 
public static void digui (Node node, String tab)
{
    //判断如果是元素节点则输出,如果是文本节点则不输出
    if(node.getNodeType() == Node.ELEMENT_NODE)
    {
        //打印当前节点名称
        System.out.println(tab + "<" + node.getNodeName() + ">");
    }
    //如果还有子节点,则向后缩进一个制表位
    tab += "\t";
    //获取当前层级所有子节点,如果没有,则length值为0,不进入for循环
    NodeList list = node.getChildNodes();
    for(int i = 0, length = list.getLength(); i < length; i++)
    {
        //将下一层子节点遍历进入递归方法
        digui(list.item(i), tab);
    }
}


——XML第一天总结


1、表单提交方式
    *   button提交
        form对象的submit方法
    *   超链接提交
    *   事件
2、XML文档声明和乱码
    *   文档声明必须写在第一行第一列
    *   乱码需要保持一致
3、XML元素的定义、属性和注释
4、XML的特殊字符
    *   CDATA
    *   PI
5、DTD入门简介
    *   两种约束:DTD和Schema
6、DTD的引入方式
7、DTD定义元素和属性
8、DTD定义实体以及W3C案例
9、XML的解析及简介
    *   DOM和SAX的区别
10、JAXP的DOM方式API文档
11、JAXP操作DOM(CRUD)
    *   查询
            getElementsByTagName()
        遍历集合
            getLength()
            item(index)
        得到具体文本
            getTextContent()
    *   添加
        createElement()
        createTextNode()
        appendChild()
        回写XML文件
    *   修改
        修改文本
            setTextContent
        回写XML文件
    *   删除
        获取父节点
            getParentNode() 
        删除节点
            removeChild()
    *   遍历
        使用递归
        获取所有子节点(不包含孙节点)
            getChildNodes()

——XML第二天

1、Schema约束
    XML Schema也是一种用于定义和描述XML文档结构与内容的模式语言,其出现的目的是为了克服DTD的局限性。

    XML Schema VS DTD:
        XML Schema符合XML语法结构。
        DOM、SAX等XMLAPI很容易解析XML Schema文档中的内容。
        XML Schema对名称空间的支持非常好,所以一个XML文档中可以有多个Schema。
        XML Schema比XML DTD支持更多的数据类型,并且支持用户自定义新的数据类型,在DTD中只能定义#PCDATA类型,而在Schema中可以直接定义整数类型。
        XML Schema定义约束的能力非常强大,可以对XML实例文档做出细致的语意限制。
        XML Schema不能像DTD一样定义实体,Schema比DTD更复杂,已经是W3C组织的标准,正在逐步取代DTD。

2、Schema快速入门
        应用Schema约束开发XML过程:
            W3C预先定义元素和属性  →  Schema文档(模式文档、约束文档)  →  XML文档(实例文档)
        编写了一个XML Schema约束文档后,通常需要把这个文件中声明的元素绑定到一个URI地址上,这个URI地址叫做namespace(名称空间),XML就可以通过这个URI(即名称空间)引用绑定指定名称空间的元素。

3、XML Schema文档基本结构
    在W3C XML Schema规范中规定:所有的Schema文档都必须使用<schema>作为其根元素:
        <?xml version="1.0" ?>
        <schema>
            ......
        </schema>

    <schema>元素可以包含一些属性,一个XML Schema声明看起来经常以如下的形式出现:
        <schema xmlns="http://www.w3.org/2001/XMLSchema"
        targetNamespace="http://www.baidu.com"    //可以是任意值
        elementFormDefault="qualified" >

        xmlns:表示当前XML文件是一个约束文件。
        targetNamespace:使用schema约束文件,直接通过这个地址引入约束文件。
        elementFormDefault="qualified"

4、编写XML Schema文档
    创建一个Schema文件,扩展名是.xsd
        *   和XML文件一样,一个XML Schema文档也必须有一个根节点:<schema>
        (1)XML文件中有多少个元素,就写多少个ELEMENT
        (2)判断是简单元素还是复杂元素
            简单元素:指那些仅包含文本的元素,它不会包含任何其他的元素或属性。
            复杂元素:复杂类型元素是包含子元素或者属性的元素。
            使用<complexType>表示复杂类型元素。
            <sequence>标签表示元素为有序元素。
        (3)简单元素写在复杂元素中,直接写name值和属性类型即可。

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.example.org/1" xmlns:tns="http://www.example.org/1" elementFormDefault="qualified">
    <element name="person">
        <complexType>
            <sequence>
                <element name="name" type="string"></element>
                <element name="age" type="int"></element>
            </sequence>
        </complexType>
    </element>
</schema>

        (4)在被约束XML文件中引入约束文件

<?xml version="1.0" encoding="UTF-8"?>
 
<person xmlns:test1="http://www.w3.org/2001/XMLSchema-instance"
test1:schemaLocation="http://www.example.org/1 1.xsd" >
    <name>张三</name>
    <age>20</age>
    <a></a>    //a元素会出错
</person>

            xmlns:test1="http://www.w3.org/2001/XMLSchema-instance"
                表示该XML文件是一个被约束的XML文件,需要起一个别名。

            xmlns="http://www.example.org/1"
                表示约束文档中的targetNamespace(名称空间)
            test1:schemaLocation="http://www.example.org/1 1.xsd"
                targetNamespage 空格 约束文档的路径

5、XML Schema复杂元素指示器
    All:表示元素只能出现一次
    Choice:表示元素只能出现其中一个。
    Sequence:元素必须按照顺序出现。
    maxOccurs="unbounded":表示出现次数没有限制。
        <element name="name" type="node" maxOccurs="unbounded" />
    定义属性(必须是复杂元素):
        需要写在</complexType>标签的前面。
        <attribute name="p1" type="string" use="required" > </attribute>
        use表示属性是否必须出现。
    <any> </any>:表示任意元素。

6、复杂Schema示例

company.xml

<?xml version="1.0" encoding="utf-8" ?>
<!-- 数文件 引入多个Schema文件 -->
<company xmls = "http://www.example.org/company
    xmls:dept = "http://www.example.org/department"
    xmls:xsi = "http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.example.org/company conpany.xsd http://www.orgexample.org/department department.xsd"
>

    <employee age="30" >
        <!-- 部门名称 -->
        <dept:name>100</dept:name>
        <!-- 员工名称 -->
        <name>王一</name>
    </employee>
<company>


company.xsd

<?xml version="1.0" encoding="utf-8" ?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
    targetNamespace="http://www.example.org/company"
    elementFormDefault="qualified"
>
    <element name="company">
        <complexType>
            <sequence>
                <element name="employee" >
                    <complexType>
                        <sequence>
                            <!-- 引用任何一个元素 -->
                            <any></any>
                            <!-- 员工名称 -->
                            <element name="name"></element>
                        </sequence>
                        <!-- 为employee元素添加属性 -->
                        <attribute name="age" type="int" ></attribute>
                    </complexType>
                </element>
            </sequence>
        </complexType>
    </element>

department.xsd

<?xml version="1.0" encoding="utf-8" ?>
<schema xmls="http://www.w3.org/2001/XMLSchema"
    targetNamespace="http://www.example.org/department"
    elementFormDefault="qualified"
>

</schema>


7、使用默认名称空间
    基本格式:
        xmln="URI";
    举例:
        <书架 xmlns="http://www.baidu.com"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:shcemaLocation="http://www.baidu.com bool.xsd"
        >
            <书>
                <书名>JavaScript网页开发</书名>
                <作者>张孝祥</作者>
                <售价>28.00元</售价>
            </书>
        </书架>

8、SAX解析的原理
    解析XML有两种技术:DOM和SAX。
        DOM解析:
            根据XML的层级结构,在内存中分配一个树形结构。
            把XML中的标签、属性、文本都封装成对象,然后通过对象的方法进行操作。
        SAX解析:
            事件驱动,边读边解析。
            无法对节点实现增删改操作

    在javax.xml.parsers包中:
        *   SAXParser类
            该类是一个抽象类,该类的实例可以通过SAXParserFactory.newSAXParser()方法获得。
            方法:
                void parse(File f, DefaultHandler dh)
                    使用指定的DefaultHandler将指定文件的内容解析为XML。
                    File f:XML文件的路径
                    DefaultHandler:事件处理器
                    把事件处理器当做参数传递之后,相当于在方法中绑定了一个事件。
                    当执行方法后,会自动执行事件。


        *   SAXParserFactory类
            该类是一个抽象类,该类的实例可以通过newInstance()方法获得。


        *    DefaultHandler类
            void startElement(String uri, String localName, String qName, Attributes attributes)
                接收元素开始的通知。
                当使用SAX解析到<开始标签>的时候,会自动执行startElement()方法。
                参数:
                    qName:当方法执行时,会把当前标签名称返回(qName)。
                    attributes:当方法执行时,会把当前标签属性返回(attributes)。

            void endElement(String uri, String localName, String qName)
                接收文档结束的通知。
                当SAX解析到<结束标签>时,会自动执行endElement()方法。
                参数:
                    qName:返回标签名称。

            void characters(char[] ch, int start, int length)
                接收元素中字符数据的通知。
                当SAX解析到文本时,会自动执行characters()方法。
                该方法接收的参数是String构造方法的参数。

            DefaultHandler类中的方法都是自动执行的:
                当解析到开始标签时,会执行startElement()方法,参数qName:返回标签内容。
                当解析到文本内容时,执行characters()方法,通过String的构造方法返回文本内容。
                当解析到结束标签时,会执行endElement()方法,参数qName:返回标签名称。

===============================================================================

9、使用JAXP的SAX方式解析XML文档
    SAX解析方式不能实现增删改操作,只能实现查询操作。

    打印出整个文档的元素:
        执行parse方法,第一个参数是XML文件的路径,第二个参数是事件处理器。
    需要手动创建一个事件处理器:
        继承DefaultHandler类。
        重写三个方法。


class Default extends DefaultHandler{
    public void startElement(String uri, String localName, String qName, Attributes attributes) {
        System.out.println("开始标签:" + qName);
    }
    public void characters(char[] ch, int start, int length)
    {
        System.out.println("文本:" + new String(ch,start, length));
    }
    public void endElement(String uri, String localName, String qName)
    {
        System.out.println("结束标签:" + qName);
    }
}


------------------------------------------------------------------------------------------------------------------------------
实现获取所有name元素的值。
    *   定义一个成员变量 boolean flag = false;
    *   判断开始方法是否是name元素,如果是name元素,则把falg设置为true。
    *   如果flag的值是true,则在characters方法中打印文本内容。
    *   当执行到结束方法时,把flag设置为false,也可以在打印完文本之后设置为false。
    

class Default2 extends DefaultHandler
{
    boolean flag = true;
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        if(qName.equals("name"))
            flag = true;
    }
    public void characters(char[] ch, int start, int length) throws SAXException {
        if(flag == true)
            System.out.println(new String(ch, start, length));
        //flag = false;
    }
    public void endElement(String uri, String localName, String qName) throws SAXException {
        if(qName.equals("name"))
            flag = false;
    }
}






------------------------------------------------------------------------------------------------------------------------------
获取第一个name的值。
    *   定义一个成员变量:int index = 1;
    *   在结束方法时,index++;
    *   想要打印第一个name元素的值,需要在characters方法中进行判断。
        if (flag == true && index == 1)

class Handler2 extends DefaultHandler{
    boolean flag = false;
    int count = 0;
    public void startElement(String uri, String localName, String qName, Attributes attributes)
    {
        if(qName.equals("name") && count == 0)
        {
            flag = true;
            count++;
        }
    }
    public void characters(char[] ch, int start, int length)
    {
        if(flag == true)
        {
            System.out.println(new String(ch, start, length));
            flag = false;
        }
    }
    public void endElement(String uri, String localName, String qName)
    {
 
    }
}

===============================================================================
10、使用dom4j解析XML文档
    dom4j是一个组织,针对XML解析,提供解析器。
    dom4j不是JavaSE的一部分,如果想要使用dom4j中的方法,需要导入dom4j的jar包


    方法:
        得到Dcument对象:
            SAXReader reader = new SAXReader();
            Document doc = reader.read(url);
            Document的父接口是Node接口,如果在Document中找不到想要的方法,可以去Node中去查找。
        Element  getRootElement()
            获取根节点。
            Element是一个接口,它的父接口是Node接口。

    Node接口中的方法:
        Element  addElement(String name)
            添加元素。
        String  getName()
            返回此节点的名称。
        short  getNodeType()
            返回此节点类型。
        Element  getParent()
            返回父节点。
        String  getText()
            返回此节点的文本。
        boolean hasContent()
            判断此节点是否包含子节点或文本节点。
        void  setName(String name)
            设置节点名称。
        void  setText()
            设置节点文本。
        Node  detach()
            自己删除自己,并返回当前节点。

    Element中的方法:
        void  add(Attribute attribute)
            添加属性。
        void  addText(Text text)
            添加文本对象。
        Element  element(QName qName)
            获取标签下的一个子标签。
            参数:qName表示标签的名称。
        Element  element()
            返回第一个子标签。
        boolean  remove(ELement)
            删除节点,成功返回true,失败返回false。
        String attributeValue(属性名称)
            获取属性。

        List  elements()
            获取标签下一级的所有子标签。
        List  elements(QName qName)
            获取标签下一级标签名为qName的所有子标签。
            参数:qName表示标签名称。
        List  elements(String name)


===============================================================================
11、使用dom4j查询XML文档

查询name元素中的值。

public class Dom4j {
    public static void main(String[] args) throws Exception
    {
        /**
         * 1、创建解析器
         * 2、得到Document对象
         * 3、得到根节点
         *     getRootElement(),返回Element对象。 
         * 4、得到所有的p1标签
         *     element("p1"),返回List集合。
         *     遍历List,得到每一个p1标签。 
         * 5、得到p1下的name
         *     在p1中执行element("name")方法。 
         * 6、得到name中的值
         *     getText()得到name元素中的值。 
         */ 
        //创建解析器对象
        SAXReader reader = new SAXReader();
        //得到Document文档对象
        Document doc = reader.read("src/dom4j/person.xml");
        //获取根节点
        Element root =  doc.getRootElement();
        //获取根节点下的所有p1节点
        List<Element> p1s = root.elements("p1");
        //遍历p1节点
        for(Element e : p1s)
        {
            //打印p1节点下的第一个name的文本
            System.out.println(e.element("name").getText());
        }
    }
}

------------------------------------------------------------------------------------------------------------------------------
查询第二个name元素中的值。


    SAXReader reader = new SAXReader();
    Document doc = reader.read("src/dom4j/person.xml");
    Element root = doc.getRootElement();
    Element p12 = (Element) root.elements("p1").get(1);
    System.out.println(p12.element("name").getText());

------------------------------------------------------------------------------------------------------------------------------
获取第一个name元素中的值。

public class Dom4j {
    public static void main(String[] args) throws Exception
    {
        /**
         * 1、创建解析器
         * 2、得到Document文档对象
         * 3、得到根节点
         * 
         * 4、得到第一个p1元素
         *     element("p1"),返回Element 
         * 5、得到p1下的name元素
         *     element("name"),返回Element 
         * 6、得到name元素中的值
         *     getText(),返回文本 
         */
        //创建解析器
        SAXReader reader = new SAXReader();
        //得到Document文档对象
        Document doc = reader.read("src/dom4j/person.xml");
        //得到根节点
        Element root = doc.getRootElement();
        //得到第一个p1
        Element p1 = root.element("p1");
        //得到p1下的name元素
        Element name = p1.element("name");
        //得到name的文本
        String text = name.getText();
        System.out.println(text);
    }


=============================================================================== 


12、使用dom4j实现添加操作
    在第二个p1标签末尾添加一个<sex>男</sex>元素

public class Dom4j {
    //在第二个p2节点之后添加sex元素
    public static void main(String[] args) throws Exception
    {
        /**
         * 1、创建解析器
         * 2、得到Document文档对象
         * 3、得到根节点
         * 4、获取到第二个p1节点
         *         使用element方法
         * 5、在p1下添加元素
         *        在p1中使用addElement("标签名称")方法,返回添加后的Element
         * 6、在添加完成后的元素下添加文本
         * 在sex中使用setText("文本内容")方法
         * 7、回写XML文件
         *         格式化使用OutputFormat类的createPrettyPrint()方法,返回一个OutputFormat类的对象
         *         使用XMLWriter类回写XML文件:new XMLWriter(new OutputStream("URL"), OutputFormat)
         *         第一个参数是XML文件路径(输出流)
         *         第二个参数是格式化类的值
         */
        //创建解析器对象
        SAXReader reader = new SAXReader();
        //创建Document文档对象
        Document doc = reader.read("src/dom4j/person.xml");
        //获取根节点
        Element root = doc.getRootElement();
        //获取第二个p1节点
        Element p1 = (Element)root.elements("p1").get(1);
        //在p1节点的末尾添加sex节点,并返回添加后的sex节点
        Element sex = p1.addElement("sex");
        //给sex节点设置文本内容
        sex.setText("男");
 
        //回写XML文件
        //获取输出格式化对象
        OutputFormat format = OutputFormat.createPrettyPrint();
        //获取XML文件输出流对象
        XMLWriter xmlw = new XMLWriter(new FileOutputStream("src/dom4j/person.xml"), format);
        //写入修改后的Document对象
        xmlw.write(doc);
        //关闭流
        xmlw.close();
    }
}

=============================================================================== 


13、在指定位置添加节点
    在第一个age之前插入<school>清华大学</school>节点。

public class Dom4j {
    //在age之前添加school元素
    public static void main(String[] args) throws Exception
    {
        /**
         * 1、创建解析器
         * 2、得到Document文档对象
         * 3、得到根节点
         * 4、获取到第一个p1节点
         * 5、获取p1下面的所有的元素
         *         elements()方法,返回List集合
         * 
         * 使用List集合的方法,在特定位置添加元素:
         *     首先创建元素,然后在元素下创建文本
         *         使用DocumentHelper类的createElement("标签")方法创建标签,返回的是创建的标签。
         *         将文本添加到标签下,使用setText("文本内容")方法
         *     使用List集合的add(int index, Element element)方法
         *         index:插入位置,从0开始。
         *         element:插入元素
         */
        //创建解析器
        SAXReader reader = new SAXReader();
        //创建Document文档对象
        Document doc = reader.read("src/dom4j/person.xml");
        //获取根节点
        Element root = doc.getRootElement();
        //获取第一个p1标签
        Element p1 = root.element("p1");
        //获取p1下的所有标签
        List<Element> nodes = p1.elements();
 
        //创建school节点
        Element school = DocumentHelper.createElement("school");
        //添加文本
        school.setText("清华大学");
        //添加节点
        nodes.add(1, school);
        //回写XML文件
        XMLWriter xml = new XMLWriter(new FileOutputStream("src/dom4j/person.xml"), OutputFormat.createPrettyPrint());
        xml.write(doc);        //为什么写入的是Document对象,而不是修改后的List集合 
        xml.close();
    }
}


===============================================================================

14、使用dom4j实现修改节点的操作。
    将第一个p标签下的age元素的文本修改为30。

public class Dom4j {
    public static void main(String[] args) throws Exception
    {
        /**
         * 1、得到Document
         * 2、得到第一个p标签
         * 3、得到p标签下的age元素
         * 4、将文本修改为30
         * 5、回写XML文件
         */
        //获取Document文档对象
        Document doc = new SAXReader().read("src/dom4j/person.xml");
        //获取根节点
        Element root = doc.getRootElement();
        //获取根节点下的第一个p节点
        Element p = root.element("p");
        //获取p节点下的age元素
        Element age = p.element("age");
        //修改值为40
        age.setText("40");
        //回写XML文件
        new XMLWriter(new FileOutputStream("src/dom4j/person.xml"), OutputFormat.createPrettyPrint()).write(doc);
    }
}

===============================================================================
15、使用dom4j实现删除节点的操作

public class Dom4j {
    public static void main(String[] args) throws Exception
    {
        /**
         * 1、得到Document对象
         * 2、得到根节点
         * 3、得到第一个p标签
         * 4、得到第一个p标签下的school标签
         * 5、使用p标签删除school标签
         *         获取父节点方法:getParent()
         * 6、回写XML文件
         */
        //得到Document文档对象
        Document doc = new SAXReader().read("src/dom4j/person.xml");
        //获取根节点
        Element root = doc.getRootElement();
        //获取第一个p标签
        Element p = root.element("p");
        //获取p标签下的school标签
        Element school = p.element("school");
        //使用school的父标签删除school标签
        System.out.println(p.remove(school));
        new XMLWriter(new FileOutputStream("src/dom4j/person.xml"), OutputFormat.createPrettyPrint()).write(doc);
    }
}


===============================================================================
16、使用dom4j获取属性。
    获取name中的id属性。

public class Dom4j {
    public static void main(String[] args) throws Exception
    {
        /**
         * 1、得到Docuent文档对象
         * 2、得到根节点
         * 3、得到第一个p标签
         * 5、得到第一个p标签下的name标签
         * 6、得到name中的值
         */
        //获取Document文档对象
        Document doc = new SAXReader().read("src/dom4j/person.xml");
        //得到根节点
        Element root = doc.getRootElement();
        //得到第一个p节点
        Element p = root.element("p");
        //得到第一个p标签下的name元素
        Element name = p.element("name");
        //获得name中的id值
        System.out.println(name.attributeValue("id"));
    }
}

===============================================================================
17、使用dom4j支持XPATH的操作
    XPATH可以直接获取到某个元素。

    第一种形式:
        /AAA/BBB/CCC:表示一层一层的,获取AAA下面的BBB下面的CCC元素。
    第二种形式:
        //BBB:表示得到全部的BBB元素。
    第三种形式:
        /*:表示全部元素。
    第四种形式:
        BBB[1]:表示第一个BBB元素
        BBB[last()]:表示最后一个BBB元素
    第五种形式:
        //BBB[@id]:表示获得所有有id属性的BBB元素。
    第六种形式:
        //BBB[@id='b1']:表示获得所有id属性是b1的BBB元素。

    (1)XPATH的第一种书写形式:
        层级关系。
        /AAA/CCC:

        <AAA>

            <BBB></BBB>
            <BBB></BBB>
            <CCC></CCC>
            <DDD>
                <BBB></BBB>
            </DDD>
            <CCC></CCC>
        </AAA>

        (2)XPATH的第二种书写形式:
            如果路径以双斜线开头,则表示选择文档中所有满足双斜线之后的元素(无论层级关系)。
            //BBB

            <AAA>
                <BBB></BBB>
                <BBB></BBB>
                <CCC></CCC>
                <DDD>
                    <BBB></BBB>
                </DDD>
                <CCC></CCC>
            </AAA> 


                选择所有父元素是AAA的BBB元素。

 
            <AAA>
                <BBB></BBB>
                <BBB></BBB>
                <CCC></CCC>
                <DDD>
                    <BBB></BBB>    //父元素是DDD
                </DDD>
                <CCC></CCC>
            </AAA> 
 

        (3)XPATH的第三种书写形式:
            /AAA/CCC/DDD/*
            选择所有路径依附于/AAA/CCC/DDD/的元素。

            <AAA>
                <BBB>
                    <DDD></DDD>
                </BBB>
                <BBB>
                    <EEE></EEE>
                </BBB>
                <CCC>
                    <QQQ></QQQ>
                </CCC>
                <DDD>
                    <BBB></BBB>
                </DDD>
                <CCC></CCC>
            </AAA>



            /*/*/BBB选择所有的有3个祖先元素的BBB元素。

            <AAA>
                <BBB>
                    <DDD></DDD>
                </BBB>
                <BBB>
                    <EEE>
                        <BBB></BBB>
                    </EEE>
                </BBB>
                <CCC>
                    <QQQ></QQQ>
                </CCC>
                <DDD>
                    <BBB></BBB>
                </DDD>
                <CCC></CCC>
            </AAA>


            //*
            选择所有元素

            <AAA>

                <BBB>
                    <DDD></DDD>
                </BBB>
                <BBB>
                    <EEE>
                        <BBB></BBB>
                    </EEE>
                </BBB>
                <CCC>
                    <QQQ></QQQ>
                </CCC>
                <DDD>
                    <BBB></BBB>
                </DDD>
                <CCC></CCC>
            </AAA>


        (4)XPATH的第四种书写形式:
            方括号里面的表达式可以进一步的指定元素,其中数字表示元素在选择集中的位置(索引从0开始),而last()函数则表示选择集中的最后一个元素。

            /AAA/BBB[1]:
            选择AAA的第一个BBB子元素。

            <AAA>
                <BBB></BBB>
                <BBB></BBB>
                <CCC></CCC>
                <DDD>
                    <BBB></BBB>
                </DDD>
                <CCC></CCC>
            </AAA> 


            /AAA/BBB[last()]:
            选择AAA的最后一个BBB子元素。

            <AAA>
                <BBB></BBB>
                <BBB></BBB>
                <CCC></CCC>
                <DDD>
                    <BBB></BBB>
                </DDD>
                <CCC></CCC>
                <BBB></BBB> 
            </AAA>


        (5)XPATH的第五种书写形式。

            //@id:
            选择所有的id属性

 
            <AAA id="aa">
                <BBB></BBB>
                <BBB></BBB>
                <CCC id="cc"></CCC>
                <DDD>
                    <BBB id="bb"></BBB>
                </DDD>
                <CCC></CCC>
            </AAA>

            //BBB[@id]:
            选择有id属性的BBB元素 

 

            <AAA id="aa">
                <BBB></BBB>
                <BBB></BBB>
                <CCC id="cc"></CCC>
                <DDD>
                    <BBB id="bb"></BBB>
                </DDD>
                <CCC></CCC>
            </AAA>


        (6)XPATH的第六种书写形式。
            属性的值可以用来作为选择的准则,normalize-space函数删除了前部和尾部的空格,并把连续的空格串替换为一个单一的空格。

            //BBB[@id='b1']:
            选择含有id属性且id属性为'b1'的BBB元素。
            

 
            <AAA id="aa">
                <BBB></BBB>
                <BBB></BBB>
                <CCC id="cc"></CCC>
                <DDD>
                    <BBB id="b1"></BBB>
                </DDD>
                <CCC></CCC>
            </AAA>


            //BBB[@name='bbb']

18、使用dom4j操作XPATH
    默认情况下,dom4j是不支持XPATH的。
    如果想要在dom4j使用XPATH,首先需要引入XPATH的jar包。

    在dom4j中提供了两个方法,用来支持XPATH:
        selectNodes("XPATH表达式")
            获取多个节点。
        selectSingleNode("XPATH表达式")
            获取单个节点。

19、使用XPATH获取所有name元素的值

public class XpathDemo {
    public static void main(String[] args) throws Exception
    {
        /**
         * 查询所有name元素的值
         */
        Document doc = new SAXReader().read("src/dom4j/person.xml");
        String exp = "//name";
        List<Element> nodes = doc.selectNodes(exp);
        for(Element name : nodes)
        {
            System.out.println(name.getText());
        }
    }
}

20、使用XPATH第一个p标签下name元素的值

public class XpathDemo {
    public static void main(String[] args) throws Exception
    {
        Document doc = new SAXReader().read("src/dom4j/person.xml");
        Node name = doc.selectSingleNode("/person/p/name[@id='nameid']");
        System.out.println(name.getText());
    }

===============================================================================
21、实现简单的学生管理系统

    使用XML当做数据库,来存储学生信息。

 
import java.util.List;
import java.util.Scanner;
 
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
/**
 * 2016年11月4日21:24:53
 * 使用XML完成学生管理系系统
 * @author 31067
 *
 */
 
public class StudentService {
    private static Document doc = null;
    private static Scanner sc = new Scanner(System.in);
    public static void main(String[] args)
    {
        doc = Dom4jUtils.getDocument();
 
        while(true)
        {
            System.out.println("-------学生管理系统------\n");
            System.out.println("\t\t1  添加学生");
            System.out.println("\t\t2  修改学生信息");
            System.out.println("\t\t3  删除学生");
            System.out.println("\t\t4  根据姓名查询学生");
            System.out.println("\t\t5  查询全部学生");
            System.out.println("\t\t6 退出系统\n");
            System.out.println("---------请选择--------\n");
            String sel = sc.next();
            switch(sel)
            {
                case "1" :
                    System.out.println("请输入学生学号:");
                    String id = sc.next();
                    System.out.println("请输入学生姓名:");
                    String name = sc.next();
                    System.out.println("请输入学生年龄:");
                    String age = sc.next();
                    addStudent(new Student(id, name, age));
                    break;
                case "2" :
                    System.out.println("请输入要修改的学生学号:");
                    String id2 = sc.next();
                    modifyStudent(id2);
                    break;
                case "3" :
                    System.out.println("请输入要删除的学生学号:");
                    String id3 = sc.next();
                    deleteStudent(id3);
                    break;
                case "4" :
                    System.out.println("请输入要查询学生的学号:");
                    String id4 = sc.next();
                    findByName(id4);
                    break;
                case "5" :
                    findAllStudent();
                    break;
                case "6" :
                    System.exit(0);
                default :
                    System.out.println("您的输入有误,请重新输入!");
            }
        }
    }
    //增加学生
    public static void addStudent(Student st)
    {
        //获取根节点 
        Element student = doc.getRootElement();
        //根节点添加stu标签 
        Element stu = student.addElement("stu");
        //stu标签添加id、name、age标签 
        Element id = stu.addElement("id");
        Element name = stu.addElement("name");
        Element age = stu.addElement("age");
        //id、name、age标签赋值 
        id.setText(st.getId());
        name.setText(st.getName());
        age.setText(st.getAge());
        //XML文件回写
        if(Dom4jUtils.write(doc))
            System.out.println("增加成功!");
        else
            System.out.println("增加失败!");
    }
    //修改学生信息
    public static void modifyStudent(String id)
    {
        Element stu = null;
        //获取所有的stu标签 
        List<Element> nodes = doc.selectNodes("//stu");
        for(Element e : nodes)
        {
            stu = e;
            //如果id相等,则打印并退出循环,获取stu对象。 
            if(stu.element("id").getText().equals(id))
            {
                System.out.println("学生姓名为" + stu.element("name").getText());
                System.out.println("学生姓年龄" + stu.element("age").getText());
                break;
            }
        }
        System.out.println("请输入学生姓名:");
        String name = sc.next();
        System.out.println("请输入学生年龄:");
        String age = sc.next();

        //重新赋值
        stu.element("name").setText(name);
        stu.element("age").setText(age);
        if(Dom4jUtils.write(doc))
            System.out.println("修改成功!");
        else
            System.out.println("修改失败!");
    }
    //删除学生
    public static void deleteStudent(String id)
    {
        Element stu = null;
        List<Element> nodes = doc.selectNodes("//stu");
        for(Element e : nodes)
        {
            stu = e;
            if(stu.element("id").getText().equals(id))
            {
                System.out.println("学生姓名为" + stu.element("name").getText());
                System.out.println("学生姓年龄" + stu.element("age").getText());
                break;
            }
        }
        System.out.println("确认删除?Y/N");
        String sel = sc.next();
        if(!"Y".equals(sel))
            return;
        Element parent = stu.getParent();
        parent.remove(stu);
        if(Dom4jUtils.write(doc))
            System.out.println("删除成功!");
        else
            System.out.println("删除失败!");
    }
    //根据姓名查询学生信息
    public static void findByName(String id)
    {
        Element stu = null;
        List<Element> nodes = doc.selectNodes("//stu");
        for(Element e : nodes)
        {
            stu = e;
            if(stu.element("id").getText().equals(id))
            {
                System.out.println("学生姓名为:" + stu.element("name").getText());
                System.out.println("学生姓年龄:" + stu.element("age").getText());
                break;
            }
        }
    }
    //查询全部学生信息
    public static void findAllStudent()
    {
        Element stu = null;
        List<Element> nodes = doc.selectNodes("//stu");
        for(Element e : nodes)
        {
            stu = e;
            System.out.println("学生学号:" + stu.element("id").getText() +"学生姓名为:" + stu.element("name").getText() + "学生姓年龄:" + stu.element("age").getText());
        }
    }
}
 
------------------------------------------------------------------------------------------------------------------------------
 
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
 
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.*;
 
public class Dom4jUtils {
    public static final String PATH = "src/Student/student.xml";
    //获得Document对象
    public static Document getDocument()
    {
        try {
            return new SAXReader().read(PATH);
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return null;
    }
    //回写XML文件
    public static boolean write(Document doc)
    {
        XMLWriter xml = null;
        try {
            xml = new XMLWriter(new FileOutputStream("src/Student/student.xml"), OutputFormat.createPrettyPrint());
            xml.write(doc);
            xml.flush();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        finally {
            try {
                xml.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return false;
    }
}

------------------------------------------------------------------------------------------------------------------------------

public class Student {
    private String id;
    private String name;
    private String age;
 
 
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAge() {
        return age;
    }
    public void setAge(String age) {
        this.age = age;
    }
    public Student(String id, String name, String age) {
        super();
        this.id = id;
        this.name = name;
        this.age = age;
    }
 
    public String toString(){
        return "学号:" + this.id + " - 姓名:" + this.name + " - 年龄:" + this.age;
    }
}

 

posted @ 2017-02-07 17:40  WWWYC  阅读(244)  评论(0编辑  收藏  举报