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文件 <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> 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<Element> 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<Node> 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<Node> 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<Element> list=(List<Element>)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+" 姓名:"+name+" 性别:"+ gender+" 年龄:"+ age+" 地址:"+address+ " 电话:"+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<attributes.getLength();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("</"+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); 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解析面向对象的编程方法(Node,Element,Attribute),Java开发者编码比较简单。 |
SAX解析基于事件的编程方法。java开发编码相对复杂。 |
2.XML约束
一:约束技术:
DTD约束:语法相对简单,功能也相对简单。学习成本也低。
Schema约束:语法相对复杂,功能也相对强大。学习成本相对高!!!(名称空间)
二:DTD约束:
导入:内部导入;外部导入
外部导入:本地文件系统;<!DOCTYPE note SYSTEM "note.dtd">
公共的外部导入:<!DOCTYPE 根元素 PUBLIC "http:........">
语法:
约束标签:<!ELEMENT 元素名称 类别> 或 <!ELEMENT 元素名称 (元素内容)>
类别:EMPTY:空标签;(#PCDATA)表示元素一定是普通字符(不能包含子标签);ANY:表示元素任意字符(可以包含子标签)
元素内容:
顺序问题:<!ELEMENT 元素名称 (子元素名称 1,子元素名称 2,.....)>: 按顺序出现子标签
次序问题:空:1次;+:至少1次;*:0~n次;?0~1次
约束属性:<!ATTLIST 元素名称 属性名称 属性类型 默认值>
默认类型:控制属性值的
CDATA :表示普通字符串
(en1|en2|..): 表示一定是任选其中的一个值
ID:表示在一个xml文档中该属性值必须唯一。值不能以数字开头
默认值:#REQUIRED 属性值是必需的
#IMPLIED 属性不是必需的
#FIXED value 属性不是必须的,但属性值是固定的
例子:
<!ELEMENT note (from?,to+,heading*,body+)> <!ELEMENT to EMPTY> <!ELEMENT from (#PCDATA)> <!ELEMENT heading (#PCDATA)> <!ELEMENT body (#PCDATA)> <!ATTLIST to id ID #REQUIRED>
<?xml version="1.0"?> <!DOCTYPE note SYSTEM "note.dtd"> <note> <from></from> <to id="a1"></to> <to id="a2"></to> <to id="a3"></to> <heading>Reminder</heading> <heading>Reminder</heading> <heading>Reminder</heading> <body>Don't forget me this weekend</body> <body>Don't forget me this weekend</body> <body>Don't forget me this weekend</body> </note>
三: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:售价>28</itcast:售价> </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中编写调到设计模式编写更方便