XML技术-Schema约束-Dom4j-Xpath详解
这辈子没办法做太多事情所以每一件都要做到精彩绝伦 People can't do too many things in my life,so everything will be wonderful 乔布斯 本文档参考资料w3cschool.CHM API教程文档免费下载地址http://down.51cto.com/data/2300287 XML技术1.什么是XMLXML 指可扩展标记语言EXtensibleMarkup Language XML 是一种标记语言很类似 HTML XML 的设计宗旨是传输数据而非显示数据 XML 标签没有被预定义。您需要自行定义标签。 XML 被设计为具有自我描述性。 XML 是 W3C 的推荐标准 html和xml的区别 html超文本标记语言。它主要是用来封装页面上要显示的数据最后通过浏览器来解析html文件然后把数据展示在浏览器上。同样我们可以使用JS和DOM技术对html文件进行解析和操作。 xml可扩展的标记语言。它早期是为了代替html技术但是由于html书写的网页在全球占有率太高最后没有成功。 后期我们开始使用xml文件作为软件的配置文件或者数据的存储文件以及传输数据的文件。 2.XML作用
为提高系统的灵活性它所启动的模块通常由其配置文件决定 例如一个软件在启动时它需要启动、两个模块而A、这两个模块在启动时又分别需要A1、A2和B1、B2模块的支持为了准确描述这种关系此时使用文件最为合适不过。 3.XML语法一个XML文件分为如下几部分内容 文档声明 元素 属性 注释 CDATA区 、特殊字符 处理指令processing instruction 3.1文档声明l 在编写XML文档时需要先使用文档声明声明XML文档的类型。也就是告诉其他解析软件该文档是个XML文档。 l 最简单的声明语法 <?xmlversion="1.0" ?> l 用encoding属性说明文档的字符编码经常使用的 <?xmlversion="1.0" encoding="UTF-8" ?> l 用standalone属性说明文档是否独立 <?xmlversion="1.0" encoding=" UTF-8" standalone="yes" ?>
拖入浏览器解析
注意如果使用记事本编辑的话会解析错误中文乱码问题。只是使用记事本编辑的时候会出现其原因如下
l 常见错误 1. <?xml version=1.0 ?> 属性没加引号 2. <?xml version=“1.0” ?> 全角空格 3.编码错误 3.2元素element
包含标签体<a>wyait.blog.51cto.com/</a> 不含标签体的<a></a>,简写为<a/>
<a>welcometo <b> wyait.blog.51cto.com/</a></b>
第一段 <网址> wyait.blog.51cto.com</网址> 第二段 <网址> wyait.blog.51cto.com </网址> 由于在XML中空格和换行都作为原始内容被处理所以在编写XML文件时使用换行和缩进等方式来让原文件中的内容清晰可读的“良好”书写习惯可能要被迫改变。
一个XML元素可以包含字母、数字以及其它一些可见字符但必须遵守下面的一些规范
<inputtype=“text”>
<input><type>text</type></input> 3.4注释
注意 XML声明之前不能有注释 注释不能嵌套例如 <!--大段注释 …… <!--局部注释--> …… --> 3.5CDATA区
语法<![CDATA[ 内容 ]]> <![CDATA[ <wyait> <br/> </wyait > ]]> <demo> <!-- 当我们希望把一些文本原样的显示在浏览器中时 可以使用xml中提供的cdata区域
格式 <![CDATA[需要原样显示的数据]]>
由于CDATA区域书写麻烦可以使用特殊字符 < < > > --> <![CDATA[ <h1>在html表示的是标题标签 <br>在html表示换行 ]]>
<h1>在html表示的是标题标签
</demo> 3.5.1转义字符l对于一些单个字符若想显示其原始样式也可以使用转义的形式予以处理。 常见的XML转义字符记录如下: 空格:<string name="out_bound_submit">出  库</string> 其中的 就代表空格!解析的时候,空格还是空格! 换行: <string name="hello_world">你好!n世界!</string> 其中的n就代表换行 缩进: <string name="hello_world">你好!t世界!</string> 其中的t就代表按一次Tab键的几个空格 应当注意,由于系统定义的基本的缩进的格数不同,有的代表4个半角字符,有的代表8个半角字符, 所以可能显示时效果不同。 如果在xml配置中使用了换行、空格、缩进等,解析的时候会把换行、空格、缩进解析为n、 空格、t等转义字符!如下:
解析的时候: 代码中会导致,本身配置的放行路径,结果没有放行! 3.6处理指令processing instruction
3.7总结l所有XML 元素都须有关闭标签 lXML 标签对大小写敏感 lXML 必须正确地嵌套顺序 lXML 文档必须有根元素(只有一个) lXML 的属性值须加引号 l特殊字符必须转义--- CDATA lXML 中的空格、回车换行会解析时被保留 4.XML约束
在XML技术里可以编写一个文档来约束一个XML文档的书写规范这称之为XML约束。
常用的约束技术 XML DTD XML Schema XSD 4.1DTD约束DTD的快速入门 1、先创建一个xml文件
2、书写一个DTD文件 dtd文件的扩展名必须是dtd 在xml中有多少个标签在dtd中就书写多少个ELEMNT
3、在xml文件中导入DTD的约束
4.1.1DTD约束语法DTD和xml文件的结合方式
可以把dtd和xml书写在同一个文件中 <!DOCTYPE 根标签名 [ 写dtd的约束 ] > XML文件使用 DOCTYPE 声明语句来指明它所遵循的DTD文件DOCTYPE声明语句有两种形式 当引用的文件在本地时外部DTD采用如下方式 <!DOCTYPE文档根结点 SYSTEM "DTD文件的URL"> 例如 <!DOCTYPE books SYSTEM“book.dtd”>。在xml文件中手写一下。 l当引用的文件是一个公共的文件时公共DTD采用如下方式 <!DOCTYPE文档根结点 PUBLIC "DTD名称" "DTD文件的URL"> 例如<!DOCTYPE web-app PUBLIC "-//SunMicrosystems,Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> 4.1.2DTD的元素ELEMENT定义
在DTD中使用 ELEMENT 声明当前xml中可以出现的标签名称 () 限制当前这个标签中的文本或者子标签。
告诉我们 当前的xml中可以有一个 books 标签在这个books标签下可以有一个或多个book子标签。 + 当前括号中的这个标签可以出现一次或多次 当前括号中的这个标签可以出现零次或一次 * 当前括号中的这个标签可以出现零次或多次
括号中的逗号是在定义出现的子标签的顺序。
当前这个name标签中可以书写文本 4.1.3属性ATTLIST定义
<!ATTLIST 标签名 属性名 属性类型 属性约束 属性名 属性类型 属性约束 ... >
当前book标签上有一个abc属性这个属性的值是一个文本但是这个必须是必须书写的不能省略。 4.1.4实体ENTITY定义
相关标签参考
4.2Schema约束XSD约束4.2.1Schema概述XML Schema是用一套预先规定的XML元素和属性创建的这些元素和属性定义了XML文档的结构和内容模式。 XML Schema规定XML文档实例的结构和每个元素/属性的数据类型 Schema相对于DTD的明显好处是XMLSchema文档本身也是XML文档而不是像DTD一样使用自成一体的语法
XML从SGML中继承了DTD并用它来定义内容的模型验证和组织元素。同时它也有很多局限 DTD不遵守XML语法 DTD不可扩展 DTD不支持命名空间的应用 DTD没有提供强大的数据类型支持只能表示很简单的数据类型。 Schema完全克服了这些弱点使得基于Web的应用系统交换XML数据更为容易。下面是它所展现的一些新特性 Schema完全基于XML语法不需要再学习特殊的语法 Schema能用处理XML文档的工具处理而不需要特殊的工具 Schema大大扩充了数据类型支持booleans、numbers、dates and times、URIs、integers、decimal numbers和real numbers等 Schema支持原型也就是元素的继承。如我们定义了一个“联系人”数据类型然后可以根据它产生“朋友联系人”和“客户联系”两种数据类型 Schema支持属性组。我们一般声明一些公共属性然后可以应用于所有的元素属性组允许把元素、属性关系放于外部定义、组合 开放性。原来的DTD只能有一个DTD应用于一个XML文档现在可以有多个Schema运用于一个XML文档。 4.2.2Schema基本概念
W3C预先定义元素和属性-àSchema文档模式文档约束文档-àXML文档实例文档
在W3C XML schema规范中规定所有的Schema文档都使用<schema>作为其根元素 <schema>元素可以包含一些属性。一个XMLschema声明看起来经常以如下的形式出现 4.2.3Schema快速入门1、定义一个xml文件
2、书写一个Schema文件
在Schema文件中 必须以 schema作为 Schema文件的根标签。 xmlns="http://www.w3.org/2001/XMLSchema" 它的含义是表示当前的Schema文件是被当前指定的url名称空间所约束。 targetNamespace="http://www.example.org/books" 给当前这个Schema文件起名字当需要被当前这个Schema文件约束的xml文件需要通过当前这个名字引入当前Schema文件。 targetNamespace属性对应的属性值可以是任意的内容。比如targetNamespace="http://www.huyouta.com/books" <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.huyouta.com/books" elementFormDefault="qualified">
<!-- 在Schema文件中书写当前xml中可以出现的标签 以及子标签 等信息 1、先清楚xml中需要多少标签在Schema文件中就书写多少个element标签 2、element标签中的 name属性 就是xml中 可以书写的标签的名字 3、在Schema中它把xml中可以出现的标签分成简单标签和复杂标签 简单标签只有文本数据的标签成为简单标签 复杂标签如果标签上有属性或者有子标签或者有属性和子标签 或 属性和文本的标签复杂标签 4、针对复杂标签需要在当前的标签中书写子标签来限制当前复杂标签中的其他内容 在element标签中需要使用complexType声明当前的element标签name属性指定的是一个复杂标签 如果是简单标签可以使用simpleType 5、对于复杂标签需要在 complexType中书写sequence 标签表示子标签的顺序
--> <elementname="books"> <!--books 是一个复杂标签 --> <complexType> <sequence> <!-- 定义当前books 标签中的子标签的顺序--> <element name="book"> <complexType> <!-- 声明当前的book 又是一个复杂标签--> <sequence> <!-- 在element 标签中的 type属性来限制当前单标签中文本的类型 --> <elementname="name" type="string"></element> <elementname="author"type="string"></element> <elementname="price"type="double"></element> </sequence> </complexType> </element> </sequence> </complexType> </element> </schema> 3、在xml文件中引入Schema文件 xmlns="http://www.huyouta.com/books" 在xml中引入 Schema文件的名称 <?xml version="1.0" encoding="UTF-8"?> <books xmlns="http://www.huyouta.com/books" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.huyouta.com/booksbooks.xsd" > <book> <name>葵花宝典</name> <author>班长</author> <price>9.9</price> </book> </books> 4.2.4名称空间声明文档空间 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.huyouta.com/books " elementFormDefault="qualified" attributeFormDefault="unqualified" > <xs:schema> targetNamespace元素用于指定schema文档中声明的元素属于哪个名称空间。 elementFormDefault元素用于指定局部元素是否受到该schema指定targetNamespace所指定的名称空间限定 attributeFormDefault元素用于指定局部属性是否受到该schema指定targetNamespace所指定的名称空间限定 总结
5.XML解析
特点 一次将所有数据全部加载到内存中。 对xml文档中的每一个节点都当成一个Node对像处理。包括元素、文本、属性。 org.w3c.dom包中的Document,Element,Node。 非常方便进行修改。 已经集成在了JDK中是Sun对xml操作的标准。 缺点是当文档数据量很大时对内存的占用很大。 Sax ?C Sample Api for XML 。 在读取数据时分析数据通过事件监听器来完成。 速度快但只适合读取数据仅向前读取不可后退。
不管是html文件还是xml文件它们都是标记型文档都可以使用w3c组织制定的dom技术来解析。
dom解析技术是W3C组织制定的而所有的编程语言都对这个解析技术使用了自己语言的特点进行实现。 Java对dom技术解析标记型文档也做了实现 早期sun公司就制定的 dom 技术。而这个技术在页面xml的时候需要把整个xml文件加载到内存中可以根据getElementById、getElementsByName 、getElementsByTagName 等方法解析。 sun公司在JDK6版本对 dom解析技术进行升级 SAX解析 Stax 解析 sun公司的解析统称 JAXP。 5.1解析XML的方式
Dom4j是一个开源、灵活的XML API。 目前很多开源框架如struts,hibernate都使用dom4j做为解析其xml的工具。 支持文档的读写功能和Xpath快速查询操作。 由于dom4j 它不是sun公司的技术而属于第三方公司的技术我们需要使用dom4j 就需要到dom4j官网下载dom4j的jar包。
把dom4jjar包拷贝我们的项目中 在自己的项目中新建一个lib文件把dom4j jar包拷贝到其中
把jar包添加到当前的classpath路径中
5.2.1获取document对象
//注意以下类都来自于org.dom4j包 //1、实例化解析器 SAXReader sax = newSAXReader(); //2、读取xml文档 Document doc =sax.read("./src/xml/a.xml"); //3、必须先获取根节点 Element root =doc.getRootElement(); //4、获取第一个人的姓名 String name =root.element("user").element("name").getText(); System.err.println(name); 5.2.2获取所有标签中的文本值//演示使用dom4j 获取 xml中的标签中的数据 publicstaticvoid getElement()throws Exception{ SAXReader reader = new SAXReader(); // 获取dom树 Document dom = reader.read("users.xml");
//获取xml中的根标签 Element root = dom.getRootElement();
//获取根标签下的所有子标签 List<Element> list =root.elements();
//遍历集合获取到每个 user标签 for (Element e : list) { Elementname = e.element("name"); Elementage = e.element("age"); Elementsex = e.element("sex"); System.out.println(name.getText() + ":" + age.getText()+":"+ sex.getText()); } } 5.2.3修改指定标签中的值//把最后一个user中的sex 修改为女 publicstaticvoid UpdateElement()throws Exception{ SAXReader reader = new SAXReader(); // 获取dom树 Document dom = reader.read("users.xml");
//先获取根标签 Element root = dom.getRootElement(); //获取 users 下的所有user标签 List<Element> list =root.elements();
//获取最后一个user标签 Element lastUser =list.get(list.size()-1);
Element sex = lastUser.element("sex");
sex.setText("女");
//把内存中修改后的dom树重新写到xml文件中 //创建用于写出数据的流对象 //XMLWriter writer = new XMLWriter(newFileOutputStream("users.xml"));
//创建一个格式器 OutputFormat format = OutputFormat.createPrettyPrint(); //设置编码表 format.setEncoding("gbk");
XMLWriter writer = new XMLWriter(new FileWriter("users.xml"),format ); //写出数据 writer.write(dom); //关流 writer.close();
} 5.2.4删除标签// 删除 publicstaticvoid deleteElement() throws Exception { SAXReader reader = new SAXReader(); // 获取dom树 Document dom = reader.read("users.xml");
// 删除最后一个user标签
// 先获取根标签 Element root = dom.getRootElement(); // 获取 users 下的所有user标签 List<Element> list = root.elements();
// 获取最后一个user标签 Element lastUser = list.get(list.size() -1);
root.remove(lastUser);
XMLWriter writer = new XMLWriter(newFileOutputStream("users.xml")); writer.write(dom); // 关流 writer.close();
} 5.2.5增加标签// 创建一个新的dom写到文件 publicstaticvoid addElement() throws Exception {
// 先创建一个dom树这个dom树在内存中 Document dom = DocumentHelper.createDocument();
// 给树上添加根节点 Element books = dom.addElement("books");
// 给根books上添加了2个book 标签 Element book = books.addElement("book"); Element book2 = books.addElement("book");
// 给book标签上添加子标签 Element name = book.addElement("name"); Element author = book.addElement("author"); Element price = book.addElement("price");
// 给book下的子标签中添加文本 name.setText("九阴真经"); author.addText("李白"); price.addText("1.1");
// 给book标签上添加子标签 Element name2 = book2.addElement("name"); Element author2 = book2.addElement("author"); Element price2 = book2.addElement("price");
// 给book下的子标签中添加文本 name2.setText("九阳神功"); author2.addText("赵敏"); price2.addText("1.2");
// 给book标签上添加属性 book.addAttribute("addr","藏经阁"); book2.addAttribute("addr","桃花岛");
OutputFormat format = OutputFormat.createPrettyPrint(); XMLWriter writer = new XMLWriter(newFileOutputStream("books2.xml"),format); writer.write(dom); // 关流 writer.close(); } 5.2.6工具类抽取/** * 这时一个工具类它的功能是完成对dom数的获取和保存 * * @authorwyait * @version 1.0 */ publicclass DomUtils {
privatestatic Document dom = null;
static{ try{ SAXReaderreader = new SAXReader(); // 获取dom树 dom = reader.read("users.xml"); }catch( Exception e ){ //把异常写到日志文件中 System.out.println("恭喜您获取dom树失败"); } } /** * 用于获取dom树的方法 */ publicstatic DocumentgetDom(){ returndom; }
/** * 保存dom树 */ publicstaticvoid saveDom(){ try{ OutputFormatformat = OutputFormat.createPrettyPrint(); XMLWriterwriter = new XMLWriter(new FileOutputStream("users.xml"),format); writer.write(dom); // 关流 writer.close(); }catch(Exception e){ System.out.println("恭喜您保存dom树失败"); } } } 5.2.7Dom4j生成一个新的XML文件//1、通过DocumentHelper在内存中创建一个Document Document doc = DocumentHelper.createDocument(); doc.setXMLEncoding(“UTF-8”);//XML的编码格式 //生成一个节点,生成的第一个节点也是根节点此方法只使用一次 Element root =doc.addElement(“users”); root.addElement(“user”).setText(“Jack”);//再设置一个子节点同时设值 //写出,如果有中文请使用前一页所讲的技术处理 XMLWriter writer= new XMLWriter(new FileOutputStream(“a.xml”)); Writer.write(doc); Writer.close(); 5.3xpath技术偏理论xpath技术 也是 W3C 组织制定的 快速获取 xml 文件中某个 标签的 技术。 l XML PATH Language。 l 可以实现快速查询。 l XPATH包含 XPath 使用路径表达式在XML 文档中进行导航。 XPath 包含一个标准函数库 l 准备Xpath的包 jaxen.jar l Xpath通过以下方法使用 dom.selectNodes ?C 返回一个List对像 dom.selectSingleNode ?C 返回一个Node对像 5.3.1Xpath示例//以下选择所有的user节点,处理不带命名空间的安以下原则 List<Element> list =doc.selectNodes("//user"); System.err.println(list.size()); //以下选择所有name节点 list = doc.selectNodes("//name");//或从要开始:/users//name System.err.println(list.size());
//以下选择所在带有country属性的节点 list = doc.selectNodes("//user[@country]"); System.err.println(list.size());
//选择国家是 EN的节点,可以使用以下方法查询用户登录 //如果country不能重复则可以使用selectSingleNode //使用双引号或单引号都可以//user Node node =doc.selectSingleNode("//user[@country="EN"]"); System.err.println(node); 在xpath中 / 表示从根开始找标签 // 表示 不考虑标签的位置 只要匹配上就可以 //abc[@属性名] 选择abc标签但是要求abc 必须有指定属性名
在使用xpath技术结合 dom4j 快速获取标签 发生了异常 报了类没有找到异常。这时一般情况下都是缺少jar包。 一般如果缺少jar包的话 在报的异常中的第二个单词或者第三个单词是jar包的名称。
以下均为根据属性查询 //以下查询id元素为XX且name属性为用户组的name值的建立全部转成小写 String path = "//user[fn:upper-case(@id)=‘XX"'and fn:upper-case(@name)='"+name+"']"; Node n=dom.selectSingleNode(path);//因为确定有一个对象所以使用Single 或是转成小写以下查询id属性为hello的book元素 List list =dom.selectNodes("//book[fn:lower-case(@id)='hello']");
查询属性中包含某个值的元素类似于like //book[contains(@id,’A001’)] //查询book的id属性中包含A001字符串的 既然是模糊查询当然要进行一下大小写转换所以 //book[contains(fn:lower-case(@id),’a001’)]
如XML文档如下 <books> <book id=“A001”> <name>Oracle编程基础</name> <price>89.99</price> </book> </books> 查询包含Oracle一词的所有book元素。 //book[name=‘Oracle’] //精确查询子元素name的值为Oracle的book元素 //以下是模糊查询 //book[contains(name,’Oracle’)] //也可以将name元素的值转成小写 //book[contains(fn:lower-case(name),’oracle’]
由于命名空间的namespace是组成元素的一部分即前缀所以处理带有命名空间的XML文档时必须要设置命名空间 如 对于上面的文档所有的元素都来自于默认命名空间。
SAXReader sax = new SAXReader(); //声明一个map用于保存命名空间 Map<String,String> uris = newHashMap<String,String>(); //给命名空间取一个别名 uris.put("a","http://www.itcast.cn"); //设置命名空间后再读取xml文档 sax.getDocumentFactory().setXPathNamespaceURIs(uris); Document dom =sax.read("./xml2/a.xml"); //然后使用带有命名空间的前缀查询即可。 dom.selectNodes(“//a:book”); //带有属性的查询同前 dom.selectNodes(//a:book[@id] //带有元素的查询必须要添加命名空间的前缀 dom.seletNodes(“//a:book[a:name=‘oralce’]”); //查询子元素值为oracle的book元素 6.总结l SAXStAX读取速度快。都是JAXP的成员。 l StAXIterator编程接口和Cursor编程接口。 l Dom4j。Dom。都会将所有节点加载加载到内存中。CRUD非常方便。 l Dom4j支持XPath. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |