XML*


目录

  • XML简介
  • XML基本语法
  • XML解析
     * DOM解析
       * DOM解析原理及工具
       * DOM4J解析工具用法及示例
       * xPath技术
     * SAX解析
       * SAX解析工具
       * SAX解析原理
       * SAX解析工具用法及示例
     * SAX解析与DOM解析的区别
  • XML约束
     * 引入
     * XML约束技术
     * DTD约束
     * Schema约束

XML简介

XML(Extend Markup Language)是一种标记语言,被用来格式化的传输数据
示例

<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type = "text/css">
<!--this is content-->
<CATALOG>
  <CD id = "132">
    <TITLE>Empire Burlesque</TITLE>
    <ARTIST>Bob Dylan</ARTIST>
    <COUNTRY>USA</COUNTRY>
    <COMPANY>Columbia</COMPANY>
    <PRICE>10.90</PRICE>
    <YEAR>1985</YEAR>
  </CD>
</CATALOG>

其中:

  • <?xml version="1.0" encoding="ISO-8859-1"?>声明了XML的版本(version)以及编码方式(encoding)
  • <?xml-stylesheet type = "text/css"> 处理指令,告诉XML解析如何解析XML文件,type的值表示对应的css文件
  • < !--this is content-->是注释
  • <CATALOG></CATALOG>是一对标签它们的名字可以自己定义,其中<CATALOG>是开始标签,</CATALOG>是关闭标签
  • <CD id = "132"> id是CD的属性
  • <PRICE>10.90</PRICE> 10.90是标签的内容
  • xml描述了一种树形结构 CATALOG是根,CD是CATALOG的子节点;TITLE,ARTIST,COUNTRY等是CD的子节点

XML基本语法

一、XML对大小写敏感
二、所有XML标签都必须有关闭标签
三、头尾标签名应该一样
四、属性值必须加引号
五、在 XML 中,空格会被保留(XML中多个空格只会保留一个)
六、实体引用(转义字符)

  • 在 XML 中,一些字符拥有特殊的意义。如果你把字符 "<" 放在 XML 元素中,会发生错误,这是因为解析器会把它当作新元素的开始。这样会产生 XML 错误:
    解决办法:


    实体引用.PNG
  • CDATA块,让一些需要进行原样输出的内容中的特殊字符原样输出。
<![CDATA[<html><head></head><body></body></html>]]>

DOM解析

1)DOM解析原理
DOM解析XML文档时,XML解析器一次性吧整个XML文档加载进内存,然后在内存中构建一棵Document对象树,通过Document对象,可以得到下面的节点对象,通过节点对象访问数据
2)DOM解析工具

  • JAXP (oracle-Sun公司官方)
  • JDOM工具(非官方)
  • Dom4J工具(非官方)(三大框架默认读取xml的工具就是Dom4j)
DOM4J解析工具

需要导包使用

1)dom4j结构


domj4.png

2)dom4j读取xml文件
节点:

  • Iterator Element.nodeIterator(); //获取当前标签节点下的所有子节点

标签:

  • Element Document.getRootElement(); //获取xml文档的根标签
  • Element ELement.element("标签名") //指定名称的第一个子标签
  • Iterator<Element> Element.elementIterator("标签名");// 指定名称的所有子标签
  • List<Element> Element.elements(); //获取所有子标签

属性:

  • String Element.attributeValue("属性名") //获取指定名称的属性值
  • Attribute Element.attribute("属性名");//获取指定名称的属性对象
  • Attribute.getName() //获取属性名称
  • Attibute.getValue() //获取属性值
  • List<Attribute> Element.attributes(); //获取所有属性对象
  • Iterator<Attribute> Element.attibuteIterator(); //获取所有属性对象

文本:

  • Element.getText(); //获取当前标签的文本
  • Element.elementText("标签名") //获取当前标签的指定名称的子标签的文本内容

示例1:利用dom4j输出一个xml文件

public class Demo1 {
    @Test
    public void test()throws Exception {
        SAXReader  reader = new SAXReader();
        Document document = reader.read(new File("./src/contact.xml"));
        //获得根标签
        Element element = document.getRootElement();
        StringBuffer sb = new StringBuffer();
        //用此方法遍历整个xml文件(先根遍历形式)
        getchild(element,sb);
        System.out.println(sb.toString());
        }

    private void getchild(Element element, StringBuffer sb) {
        // TODO Auto-generated method stub
        sb.append("<"+element.getName());
        //获得标签的所有属性
        List<Attribute> attrs = element.attributes();
        //输出标签属性
        if(attrs!=null) {
            for (Attribute attribute : attrs) {
                sb.append(" "+attribute.getName()+"=\""+attribute.getValue()+"\"");
            }
        }
        sb.append(">");
        //获得当前标签下的所有子标签
        Iterator<Node> iterator= element.nodeIterator();
        while(iterator.hasNext()) {
            Node node = iterator.next();
            //输出标签
            if(node instanceof Element) {
                Element e = (Element)node;
                getchild(e,sb);
            }
            //输出文本
            if(node instanceof Text) {
                Text text = (Text)node;
                sb.append(node.getText());
            }
        }
        sb.append("</"+element.getName()+">");  
    }
}

示例2:把xml获取的信息封装到对象内

/**
 * 把xml封装到对象中
 *
 */
public class Demo2 {
    @Test
    public void test2() throws Exception{
        SAXReader reader = new SAXReader();
        Document doc = reader.read(new File("./src/contact.xml"));
        Element elem = doc.getRootElement();
        Iterator<Element> it = elem.elementIterator();
        ArrayList<Contact> contacts = new ArrayList();
        while(it.hasNext()) {
            Contact contact = new Contact();
            Element element = it.next();
            contact.setId(element.attributeValue("id"));
            contact.setAge(element.elementText("age"));
            contact.setPhone(element.elementText("phone"));
            contact.setEmail(element.elementText("email"));
            contact.setQq(element.elementText("qq"));
            contacts.add(contact);
        }
        
        for(Contact contact:contacts) {
            System.out.println(contact);
        }
    }
}

3) 修改xml文件
增加:

  • DocumentHelper.createDocument() 增加文档
  • addElement("名称") 增加标签
  • addAttribute("名称",“值”) 增加属性

修改:

  • Attribute.setValue("值") 修改属性值
  • Element.addAtribute("同名的属性名","值") 修改同名的属性值
  • Element.setText("内容") 修改文本内容

删除

  • Element.detach(); 删除标签
  • Attribute.detach(); 删除属性

写入

  • OutputFormat.createPrettyPrint() 创建易读的xml文件
  • OutputFormat.createCompactFormat() 创建紧凑的xml文件
  • format.setEncoding("编码方式");设置编码方式
  • XMLWriter(OutputStream out,OutPutformat format) 设置写入方式
  • XMLWriter.write 写入内容

写入基本流程:首先创构建一个空的Document对象,然后向其中按照节点关系添加标签(根标签只能有一个),然后创建文件输出流,指定输出格式,利用XMLWriter对象设置格式和写入内容,最后关闭writer对象。

示例3:创建文件并写入一个简单的XML文档:


************
/**
 * 生成xml文档
 *
<Students>
<Student id="1">
    <name>张三</name>
    <gender>男</gender>
    <grade>计算机1班</grade>
    <address>广州天河</address>
</Student>
<Student id="2">
    <name>李四</name>
    <gender>女</gender>
    <grade>计算机2班</grade>
    <address>广州越秀</address>
</Student>
</Students>
 *
 */
public class Demo3 {
    @Test
    public void test() throws Exception {
        //在内存创建Document文档
        Document doc = DocumentHelper.createDocument();
        //写入内容
        Element rootElement = doc.addElement("Students");
        //增加第二层标签
        Element studentElem = rootElement.addElement("Student");
        //增加属性
        studentElem.addAttribute("id", "1");
        //添加第三层标签
        studentElem.addElement("name").setText("张三");
        studentElem.addElement("gender").setText("男");
        studentElem.addElement("grade").setText("计算机一班");
        studentElem.addElement("address").setText("广州天河");
        //增加第二个二层标签
        Element studentElemnt2 = rootElement.addElement("Student");
        studentElemnt2.addAttribute("id", "2");
        //为第二个二层标签添加子标签
        studentElemnt2.addElement("name").setText("李四");
        studentElemnt2.addElement("gender").setText("女");
        studentElemnt2.addElement("grade").setText("计算机二班");
        studentElemnt2.addElement("address").setText("广州越秀");
        
        //将内容写出到文件
        //创建输出流
        FileOutputStream out = new FileOutputStream(new File("f:/student.xml"));
        //指定输出方式
        OutputFormat format = OutputFormat.createPrettyPrint();
        //指定编码方式
        format.setEncoding("utf-8");
        XMLWriter writer = new XMLWriter(out,format);
        //写出内容
        writer.write(doc);
        //关闭资源
        writer.close();
    }
}

示例4:修改、删除xml文件

/**
 * 修改id为2的学生的姓名+删除id为2的学生标签
 *
 */
public class Demo3 {
    @Test
    public void test() throws Exception {
        //将XML文件载入为document对象
        Document document = new SAXReader().read(new File("f:/student.xml"));
        //获取所有Student标签
        Iterator<Element> it = document.getRootElement().elementIterator("Student");
        //查询id为2的学生
        while(it.hasNext()) {
            Element elem = it.next();
            System.out.println(elem.attribute("id").getValue());
            if(elem.attributeValue("id").equals("2")) {
                //修改姓名
                //elem.element("name").setText("王丽");
                //删除该学生标签
                elem.detach();
                break;
            }
        }
        
        FileOutputStream out = new FileOutputStream("f:/student.xml");
        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setEncoding("utf-8");
        XMLWriter writer = new XMLWriter(out,format);
        writer.write(document);
        writer.close();
    }
}

4)xPath技术

当使用dom4j查询比较深的层次节点时比较麻烦,xPath技术可以使我们快速获得深层次节点
使用xPath的方法需要导入dom4j文件夹下的jaxen-1.1-beta-6.jar包。

xPath语法:
Xpath语法类似于在一个文件系统中定位文件
W3C的Xpath语法教程:http://www.w3school.com.cn/xpath/xpath_syntax.asp

  • / 绝对路径 表示从xml的根位置开始或子元素(一个层次结构)
  • // 相对路径 表示不分任何层次结构的选择元素。
  • * 通配符 表示匹配所有元素
  • [] 条件 表示选择什么条件下的元素
  • @ 属性 表示选择属性节点
  • and 关系 表示条件的与关系(等价于&&)
  • text() 文本 表示选择文本内容

在DOM4J中的使用方法:

  • List<Node> selectNodes("xpath表达式"); 查询多个节点对象
  • Node selectSingleNode("xpath表达式"); 查询一个节点对象

SAX解析

1)SAX解析工具
SAX解析工具- Sun公司提供的。内置在jdk中。org.xml.sax.*
2)SAX解析原理
加载一点,读取一点,处理一点。对内存要求比较低。

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

  • parse(File file,DefautHandler);
    参数一: File:表示 读取的xml文件。
    参数二: DefaultHandler: SAX事件处理程序。需要自己实现它的子类,覆盖相应方法进行解析

DefaultHandler类的API:

  • 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) : 读到文本内容时调用

3)示例,利用SAX解析输出完整xml文档内容
1.主函数:

/**
 * 读取contact.xml文件,完整输出文档内容
 *
 */
public class Demo2 {

    public static void main(String[] args)throws Exception {
        //1.创建SAXParser
        SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
        //2.读取xml文件
        MyDefaultHandler2 handler = new MyDefaultHandler2();
        parser.parse(new File("./src/contact.xml"), handler);
        String content = handler.getContent();
        System.out.println(content);
    }
}

2.MyDefaultHandler2类

/**
 * SAX处理器程序
 */
public class MyDefaultHandler2 extends DefaultHandler {
    //存储xml文档信息
    private StringBuffer sb = new StringBuffer();
    
    //获取xml信息
    public String getContent(){
        return sb.toString();
    }
    

    /**
     * 开始标签
     */
    @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<attributes.getLength();i++){
                //得到属性名称
                String attrName = attributes.getQName(i);
                //得到属性值
                String attrValue = attributes.getValue(i);
                sb.append(" "+attrName+"=\""+attrValue+"\"");
            }
        }
        sb.append(">");
    }
    
    /**
     * 文本内容
     */
    @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 endElement(String uri, String localName, String qName)
            throws SAXException {
        sb.append("</"+qName+">");
    }
}

SAX解析与DOM解析的区别

DOM解析 SAX解析
原理: 一次性加载xml文档,不适合大容量的文件读取 原理: 加载一点,读取一点,处理一点。适合大容量文件的读取
DOM解析可以任意进行增删改查 SAX解析只能读取
DOM解析任意读取任何位置的数据,甚至往回读 SAX解析只能从上往下,按顺序读取,不能往回读
DOM解析面向对象的编程方法(Node,Element,Attribute),Java开发者编码比较简单。 SAX解析基于事件的编程方法。java开发编码相对复杂。

XML约束

1)引入
XML语法是由w3c组织制定的规范xml文件的基本编写规则,而XML约束是开发者自定义规则以使XML符合自己的规范的约束。

2)XML约束技术
DTD约束:语法相对简单,功能也相对简单。学习成本也低。
Schema约束:语法相对复杂,功能也相对强大。学习成本相对高!!!(名称空间)

3)DTD约束
1.导入DTD方式

  • 内部导入
<?xml version="1.0"?>
<!DOCTYPE note [//定义此文档是 note 类型的文档。
  <!ELEMENT note (to,from,heading,body)>     //定义 note 元素有四个元素:"to、from、heading,、body"
  <!ELEMENT to      (#PCDATA)>               //元素为 "#PCDATA" 类型
  <!ELEMENT from    (#PCDATA)>               //元素为 "#PCDATA" 类型
  <!ELEMENT heading (#PCDATA)>               //元素为 "#PCDATA" 类型
  <!ELEMENT body    (#PCDATA)>              //元素为 "#PCDATA" 类型
]>
<note>
  <to>George</to>
  <from>John</from>
  <heading>Reminder</heading>
  <body>Don't forget the meeting!</body>
</note>
  • 外部导入
    本地文件系统:<!DOCTYPE note SYSTEM "note.dtd">
    公共的外部导入:<!DOCTYPE 根元素 PUBLIC "http://gz.itcast.cn/itcast.dtd">

2.DTD语法

  • 约束标签 <!ELEMENT 元素名称 类别> 或 <!ELEMENT 元素名称 (元素内容)>
    类别:
      空标签: EMPTY。 表示元素一定是空元素。
      普通字符串: (#PCDATA)。表示元素的内容一定是普通字符串(不能含有子标签)。
      任何内容: ANY。表示元素的内容可以是任意内容(包括子标签)

顺序问题:
<!ELEMENT 元素名称 (子元素名称 1,子元素名称 2,.....)>: 表示子标签必须按顺序出现
次数问题:
标签名 : 表示标签必须出现且只出现1次。
标签名+ : 至少出现1次
标签名* : 0或n次。
标签名? : 0 或1次。

  • 约束属性 <!ATTLIST 元素名称 属性名称 属性类型 默认值>
    默认值:
        #REQUIRED  表示属性是必需的
        #IMPLIED  表示属性不是必需的
        #FIXED value  表示属性不是必须的,但属性值是固定的
    属性类型:控制属性值的
        CDATA : 表示普通字符串
        (en1|en2|..):  表示一定是任选其中的一个值
        ID: 表示在一个xml文档中该属性值必须唯一。值不能以数字开头

4)Schema约束
名称空间:告诉xml文档的哪个元素被哪个schema文档约束。 在一个xml文档中,不同的标签可以受到不同的schema文档的约束。
1.一个名称空间受到schema文档约束的情况
2.多个名称空间受到多个schema文档约束的情况
3.默认名称空间的情况
4.没有名称空间的情况

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342