Xml


1.XML基础

  一:作用

    作为软件配置文件;作为小型的数据库

  二:语法

    标签:标签名不能以数字开头,中间不能有空格,区分大小写,有且只有一个根标签

    属性:可以有多个属性,属性值必须用引号(单双都可以但不可以单双混用)

       文档声明:<?xml version="1.0" encoding="utf-8">

          encoding="utf-8": 打开或解析xml文档时的编码

          注意:保存xml文档时的编码 和 解析xml文档时的编码要保持一致,才能避免中文乱码问题!

  三:XML 解析

    程序读取或者操作xml文档

    解析方式:DOM解析 vs SAX解析

    (一)DOM解析:   

       DOM解析原理:一次性把xml文档加载成Document树,通过Document对象得到节点对象,通过节点对象访问xml文档内容(标签,属性,文本,注释)。

       使用工具:Dom4j工具    

       使用语法:

          a.读取xml文档

           Document doc = new SAXReader().read("xml文件");

             节点:nodeIterator:所有节点;

             标签:element("名字")指定名称的第一个子标签

              elementIterator("名称");  指定名称的所有子标签对象

              elements();  所有子标签对象

           属性:

              attributeValue("名称")指定名称的属性值

              attribute("名称")指定名称的属性对象

              getName() 属性名称

              getValue() 属性值

              atributeIterator()   所有属性对象(Iterator)

              attributes() 所有属性对象(List)

           文本:

              getText()  得到当前标签的文本

              elementText("子标签名称") 得到子标签的文本

          b.写Xml文档

            XMLWriter writer = new XMLWriter(OutputStream, OutputForamt)

              wirter.write(Document);

          c.修改Xml文档的API

            增加:DocumentHelper.createDocument() 增加文档

               addElement("名称") 增加标签

               addAttribute("名称",“值”) 增加属性

            修改:Attribute.setValue("值") 修改属性值

               Element.addAtribute("同名的属性名","值") 修改同名的属性值

               Element.setText("内容") 修改文本内容

            删除:Element.detach(); 删除标签

               Attribute.detach();  删除属性

例子:

/**
 *  课堂练习: 
 * 1.使用dom4j的api来生成以下的xml文件


    张三
    
    计算机1班
    
广州天河
李四 计算机2班
广州越秀
2.修改id为2的学生的姓名,改为“王丽” 3.删除id为2的学生 *
@author APPle * */ public class Demo2 { public static void main(String[] args) throws IOException, Exception { // TODO Auto-generated method stub //第一题 /*Document doc=DocumentHelper.createDocument(); Element root=doc.addElement("Students"); Element e1=root.addElement("Student"); Element e11=e1.addElement("name"); Element e12=e1.addElement("gender"); Element e13=e1.addElement("grade"); Element e14=e1.addElement("address"); e1.addAttribute("id", "1"); e11.setText("张三"); e12.setText("男"); e13.setText("计算机1班"); e14.setText("广州天河"); Element e2=root.addElement("Student"); Element e21=e2.addElement("name"); Element e22=e2.addElement("gender"); Element e23=e2.addElement("grade"); Element e24=e2.addElement("address"); e2.addAttribute("id", "2"); e21.setText("李四"); e22.setText("女"); e23.setText("计算机2班"); e24.setText("广州越秀"); XMLWriter writer=new XMLWriter(new FileOutputStream(new File("e:/b.xml"))); writer.write(doc);*/ //第二题 Document doc1=new SAXReader().read(new File("e/b.xml")); Element ele1=doc1.getRootElement(); @SuppressWarnings("unchecked") Iterator it=ele1.elementIterator(); while(it.hasNext()){ Element e=it.next(); if(e.attributeValue("id").equals("2")){ e.element("name").setText("王丽"); } } XMLWriter writer1=new XMLWriter(new FileOutputStream(new File("e:/bb.xml"))); // 设置编码 OutputFormat format = OutputFormat.createPrettyPrint(); format.setEncoding("utf-8"); writer1.write(doc1); } }

    (二)xPath技术

         a.出现的原因:当使用dom4j查询比较深层次结构的节点(标签属性文本)比较麻烦!就出现这个能快速定位到xml中的具体位置

         b.作用:快速获取所需节点对象

         c.使用:1.导入xPath支持的jar包:jaxen-1.1-beta-6.jar

             2.使用方法:List selectNodes("xpath表达式");查询多个节点对象

                   Node selectSingleNode("xpath表达式");查询一个节点对象

         d.语法:

            / 绝对路径 表示从xml的根位置开始或子元素(一个层次结构)

            // 相对路径 表示不分任何层次结构的选择元素。

            * 通配符 表示匹配所有元素

            [] 条件 表示选择什么条件下的元素

            @ 属性 表示选择属性节点

            and 关系 表示条件的与关系(等价于&&)

            text() 文本 表示选择文本内容

例子:

/**
     * 删除id=002的学生标签
     * @param doc 
     * @param id
     * @throws IOException 
     * @throws Exception 
     */
    public static void deleById() throws IOException, Exception{
        Document doc=new SAXReader().read(new File("./src/XML/contact.xml"));
        //1.查询id为2的学生标签
        //使用xpath技术
        Element ee=(Element)doc.selectSingleNode("//contact[@id='002']");
        //删除标签
        ee.detach();
        //写回去
        FileOutputStream fos=new FileOutputStream("./src/XML/contact.xml");
        @SuppressWarnings("static-access")
        OutputFormat format=new OutputFormat().createPrettyPrint();
        format.setEncoding("utf-8");
        XMLWriter writer=new XMLWriter(fos,format);
        writer.write(doc);
        writer.close();
    }
    /**
     * 表达式语法
     * 
     */
    public static void test() throws Exception{
        Document doc = new SAXReader().read(new File("./src/contact.xml"));
        String xpath = "";
        /**
         * 1.      /      绝对路径      表示从xml的根位置开始或子元素(一个层次结构)
         */
        xpath = "/contactList";
        xpath = "/contactList/contact";
        
        /**
         * 2. //     相对路径       表示不分任何层次结构的选择元素。
         */
        xpath = "//contact/name";
        xpath = "//name";
        
        /**
         * 3. *      通配符         表示匹配所有元素
         */
        xpath = "/contactList/*"; //根标签contactList下的所有子标签
        xpath = "/contactList//*";//根标签contactList下的所有标签(不分层次结构)
        /**
         * 4. []      条件           表示选择什么条件下的元素
         */
        //带有id属性的contact标签
        xpath = "//contact[@id]";
        //第二个的contact标签
        xpath = "//contact[2]";
        //选择最后一个contact标签
        xpath = "//contact[last()]";

        /**
         * 5. @     属性            表示选择属性节点
         */
        xpath = "//@id"; //选择id属性节点对象,返回的是Attribute对象
        xpath = "//contact[not(@id)]";//选择不包含id属性的contact标签节点
        xpath = "//contact[@id='002']";//选择id属性值为002的contact标签
        xpath = "//contact[@id='001' and @name='eric']";//选择id属性值为001,且name属性为eric的contact标签
        
        /**
         *6.  text()   表示选择文本内容
         */
        //选择name标签下的文本内容,返回Text对象
        xpath = "//name/text()";
        xpath = "//contact/name[text()='张三']";//选择姓名为张三的name标签
        
        @SuppressWarnings("unchecked")
        List list = doc.selectNodes(xpath);
        for (Node node : list) {
            System.out.println(node);
        }
    }
    /**
     * 模拟用户登录
     * @throws IOException 
     * @throws Exception 
     */
    public static void denglu() throws IOException, Exception{
        BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));
        System.out.println("请输入用户名:");
        String name = reader.readLine();
        System.out.println("请输入密码:");
        String password = reader.readLine();
        
        //之后再Xml文档中查找是否有
        Document doc=new SAXReader().read(new File("./src/XML/user.xml"));
        Element user=(Element) doc.selectSingleNode("//user[@name='"+name+"' and @password='"+password+"']");
        if(user!=null){
            System.out.println("登录成功");
        }else{
            System.out.println("登录失败");
        }
    }
    /**
     * 读取Html文件
     * 练习:读取联系人的所有信息
     * 按照以下格式输出:
     *          编号:001 姓名:张三 性别:男 年龄:18 地址:xxxx 电话: xxxx
     *       编号:002 姓名:李四 性别:女 年龄:20 地址:xxxx 电话: xxxx
     *       ......
     */
    public static void readHtml() throws Exception{
        Document doc=new SAXReader().read(new File("./src/XML/persionList.html"));
        //读取所有tbody中的tr标签
        @SuppressWarnings("unchecked")
        List list=(List)doc.selectNodes("//tbody/tr");
        //2.遍历
                for (Element elem : list) {
                    //编号
                    //String id = ((Element)elem.elements().get(0)).getText();
                    String id = elem.selectSingleNode("td[1]").getText();
                    //姓名
                    String name = ((Element)elem.elements().get(1)).getText();
                    //性别
                    String gender = ((Element)elem.elements().get(2)).getText();
                    //年龄
                    String age = ((Element)elem.elements().get(3)).getText();
                    //地址
                    String address = ((Element)elem.elements().get(4)).getText();
                    //电话
                    String phone = ((Element)elem.elements().get(5)).getText();
                    
                    System.out.println("编号:"+id+"\t姓名:"+name+"\t性别:"+
                                        gender+"\t年龄:"+
                                        age+"\t地址:"+address+
                                        "\t电话:"+phone);
                }
    }

    (三)SAX解析

      a.出现原因:因为DOM解析会一次将xml文档加载到内存中去,然后内存中的构建Document树,这样对内存要求比较高,不适合读取大容量的xml文件,容易导致内存溢出

      b.解析原理:加载一点,读取一点,处理一点,对内存要求比较低

      c.解析工具:内置再jdk中的org.xml.sax.*(Sun公司提供)

      d.核心API:SAXParser类:用于读取和解析xml文件对象

           parse(File f, DefaultHandler dh)方法: 解析xml文件

              DefaultHandler: SAX事件处理程序。使用DefaultHandler的子类

      d.如何使用:

        1.创建SAXParser对象

          SAXParser parser=SAXParserFactory.newInstance().newSAXParser();

        2.调用parse方法

          parser.parse(new File("./src/contact.xml"), new MyDefaultHandler());}

           MyDefaultHandler()是DefaultHandler子类需要对这个重写方法达到操作xml文件的目的

        3.重写DefaultHandler子类

          void startDocument() : 在读到文档开始时调用

          void endDocument() :在读到文档结束时调用

          void startElement(String uri, String localName, String qName, Attributes attributes) :读到开始标签时调用

          void endElement(String uri, String localName, String qName) :读到结束标签时调用

          void characters(char[] ch, int start, int length) : 读到文本内容时调用

 例子:

主函数

public class SAX1 {

    public static void main(String[] args) throws Exception, SAXException {
        //创建SAXParser对象
        SAXParser parser=SAXParserFactory.newInstance().newSAXParser();
        //调用parse方法
        MyDefaultHandler2 handler=new MyDefaultHandler2();
        parser.parse(new File("./src/XML/contact.xml"),handler );
        String content=handler.getContent();
        System.out.println(content);
    }
}

重写的DefaultHandler1子类

public class MyDefaultHandler2 extends DefaultHandler{
    //存储xml文档信息
    private StringBuffer sb=new StringBuffer();
    //获取xml信息
    public String getContent(){
        return sb.toString();
    }
    /**
     * 开始标签时调用
     * @param qName: 表示开始标签的标签名
     * @param attributes: 表示开始标签内包含的属性列表
     */
    @Override
    public void startElement (String uri, String localName,
            String qName, Attributes attributes)
                    throws SAXException
    {
        sb.append("<"+qName);
        if(attributes!=null){
            for(int i=0;i){
                //获得属性名
                String attrName=attributes.getQName(i);
                //获得属性值
                String attrValue=attributes.getValue(i);
                sb.append(" "+attrName+"=\""+attrValue+"\"");
            }
        }
        sb.append(">")    ;

    }
    /**
     * 结束标签时调用
     * @param qName: 结束标签的标签名称
     */
    @Override
     public void endElement (String uri, String localName, String qName)
                throws SAXException
     {
        sb.append("");
     }
    /**
     * 读到文本内容的时调用
     * @param ch: 表示当前读完的所有文本内容
     * @param start: 表示当前文本内容的开始位置
     * @param length: 表示当前文本内容的长度
     * char[](                                       张三              20)   100
     *                              98 2   
     */ 
    @Override
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        //得到当前文本内容
        String content = new String(ch,start,length);
        sb.append(content);
    }
    /**
     * 结束文档时调用
     */
    @Override
    public void endDocument() throws SAXException {
    }
    
}

重写DefaultHandler1子类

public class MyDefaultHandler extends DefaultHandler{
    /**
     * 开始文档时调用
     */
    @Override
    public void startDocument()throws SAXException {
        System.out.println("MyDefaultHandler.startDocument()");
    }
    /**
     * 开始标签时调用
     * @param qName: 表示开始标签的标签名
     * @param attributes: 表示开始标签内包含的属性列表
     */
    @Override
    public void startElement (String uri, String localName,
            String qName, Attributes attributes)
                    throws SAXException
    {
        System.out.println("MyDefaultHandler.startElement()-->"+qName);
    }
    /**
     * 结束标签时调用
     * @param qName: 结束标签的标签名称
     */
    @Override
     public void endElement (String uri, String localName, String qName)
                throws SAXException
     {
        System.out.println("MyDefaultHandler.endElement()-->"+qName);
     }
    /**
     * 读到文本内容的时调用
     * @param ch: 表示当前读完的所有文本内容
     * @param start: 表示当前文本内容的开始位置
     * @param length: 表示当前文本内容的长度
     * char[](                                       张三              20)   100
     *                              98 2   
     */ 
    @Override
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        //得到当前文本内容
        String content = new String(ch,start,length);
        System.out.println("MyDefaultHandler.characters()-->"+content);
    }
    /**
     * 结束文档时调用
     */
    @Override
    public void endDocument() throws SAXException {
        System.out.println("MyDefaultHandler.endDocument()");
    }
    
}

    (四)DOM vs SAX解析

DOM解析

SAX解析

原理: 一次性加载xml文档,不适合大容量的文件读取

原理: 加载一点,读取一点,处理一点。适合大容量文件的读取

DOM解析可以任意进行增删改成

SAX解析只能读取

DOM解析任意读取任何位置的数据,甚至往回读

SAX解析只能从上往下,按顺序读取,不能往回读

DOM解析面向对象的编程方法(NodeElementAttribute,Java开发者编码比较简单。

SAX解析基于事件的编程方法。java开发编码相对复杂。

2.XML约束

  一:约束技术:  

    DTD约束:语法相对简单,功能也相对简单。学习成本也低。

    Schema约束:语法相对复杂,功能也相对强大。学习成本相对高!!!(名称空间)

  二:DTD约束:

      导入:内部导入;外部导入

        外部导入:本地文件系统;SYSTEM "note.dtd">

             公共的外部导入:

      语法:

        约束标签:

            类别:EMPTY:空标签;(#PCDATA)表示元素一定是普通字符(不能包含子标签);ANY:表示元素任意字符(可以包含子标签)

            元素内容:  

                顺序问题:元素名称 (子元素名称 1,子元素名称 2,.....)> 按顺序出现子标签

                次序问题:空:1次;+:至少1次;*:0~n次;?0~1次

        约束属性:

            默认类型:控制属性值的

                CDATA :表示普通字符串

                (en1|en2|..) 表示一定是任选其中的一个值

                ID:表示在一个xml文档中该属性值必须唯一。值不能以数字开头

            默认值:#REQUIRED 属性值是必需的

                #IMPLIED   属性不是必需的

                #FIXED value 属性不是必须的,但属性值是固定的

例子:

  
  
  
  
  
  
<?xml version="1.0"?>


  
  
  
  
  Reminder
  Reminder
  Reminder
  Don't forget me this weekend
  Don't forget me this weekend
  Don't forget me this weekend

  三:Schema约束

   (一)使用它的原因

      a.支持数据类型b.是DTD的替代c.是用xml来编写之后处理Schema变得更加方便d.可保护数据通信e.可扩展

  (二)名称空间:告诉xml文档的哪个元素被哪个schema文档约束 在一个xml文档中,不同的标签可以受到不同的schema文档的约束。

       1)一个名称空间受到schema文档约束的情况

       2)多个名称空间受到多个schema文档约束的情况

       3)默认名称空间的情况

       4)没有名称空间的情况

  (三)使用方法

      http://www.w3school.com.cn/schema/schema_howto.asp

  (四)例子

<?xml version="1.0" encoding="UTF-8"?>
<itcast:书架 xmlns:itcast="http://www.itcast.cn"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:schemaLocation="http://www.itcast.cn book.xsd">
    <itcast:>
        <itcast:书名>JavaScript网页开发itcast:书名>
        <itcast:作者>张孝祥itcast:作者>
        <itcast:售价>28itcast:售价>
    itcast:书>

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

  (五)注意:

    对Schema的编写我们可在eclipse中编写调到设计模式编写更方便