XML(eXtensive Markup Language)可扩展的标记语言,是万维网联盟(World Wide Web Consortium W3C)定义的一种标准。 可扩展性指允许用户按照XML规则自定义标记(tags 标签)。
作用:
作为微型数据库,存储数据; 作为通信数据; 用于不同平台,不用系统交换数据; 作为配置文件,为应用程序配置数据; 结合样式表语言,展示数据。强项:轻松表达多层结构的数据;可扩展。 优点:平台无关,语言无关。设计目标是描述数据并集中于数据的内容,与显示分离。 提醒:不能用XML来直接写网页。即便是包含了XML数据,依然要转换成HTML格式才能在浏览器上显示。
xml特征 :纯文本 、严格的格式、可扩展(标记可扩展)。
XML文档主要由如下部分组成: XML声明–处理指令(Processing Instruction) 、元素、属性、实体、注释。
大多数XML文档以XML声明作为开始,它向解析器提供了关于文档的基本信息。建议使用XML声明,但它不是必需的。如果有的话,那么它一定是文档的第一行内容。例如:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>声明最多可以包含三个名称-值对(许多人称它们为属性,尽管在技术上它们并不是)。
问号与xml之间不能有空格;
version 是使用的XML 版本:1.0, 1.1 ;
encoding 是该文档所使用的字符集。该声明中引用的ISO-8859-1 字符集包括大多数西欧语言用到的所有字符。默认字符在UTF-8字符集中,这是一个几乎支持世界上所有语言的字符和象形文字的Unicode 标准;
standalone(可以是yes 或no)定义了是否孤立处理该文档。如果XML文档没有引用任何其它文件,则可以指定 standalone=”yes”。如果XML文档引用其它描述该文档可以包含什么的文件(如DTD),则 standalone=”no”。默认值为”no”。
<标记名>内容<’/标记名>:左尖括号“<“和右尖括号“>“之间的文本:
在< >中的称为开始标记;在<’/ >中的称为结束标记;空标记:不包含元素内容的标记。空标签必须以“/>”结束。格式: <空标记的名称/>,<空标记的名称 属性列表/>。注意:
除空标记外,标签必须成对:有始有终。所有的开始标签和结束标签必须匹配;在标记符“<“和”标记的名称”之间不能含有空格。在标记符”/>”前面可以有空格或回行;XML的标记是区分大小写的,开始标记与结束标记名称必须严格完全相同。XML标记必须遵循下面的命名规则:
名字中可以包含字母、数字以及其它字母或文字;还可包含下划线(_)、点(.)、连字符(-);名字不能以数字开头;可以用字母、文字或者下划线开头;名字不能以字母xml (或XML 或Xml ..) 开头;名字中不能包含空格。属性是标记的属性,可以为标记添加附加信息。属性是一个名值对,必须由名称和值组成,属性必须在标记的开始标记或空标记中声明,用”=”为属性指定一个值。 语法如下:
<标记名称 属性列表/> <标记名称 属性列表>XXX</标记名称> <!-- 例如 --> <桌子 width="40" height='100'/>所有的属性值必须位于单引号或双引号中。每个标记内可以出现多组属性,但是不能出现同名属性。开始标志内,类似赋值语句,例如:
<eric age="80" sex="man">……</eric>使用属性的原则:
属性不体现数据的结构,只是数据的附加信息; 一个信息是作为一个标记的属性或子标记,取决于具体问题,不要因为属性的频繁使用破坏XML的数据结构。下面是一个结构清晰的XML文件:
<楼房 height="23m" width="12m"> <结构>混凝土</结构> <类别>商用</类别> </楼房>下面是一个结构不清晰的XML文件:
<楼房 height="23m" width="12m" 结构="混凝土" 建筑商="华海集团" 类别="商用"></楼房>XML 规范预定义了五个实体。
< ==== < > ==== > " ==== ” ' ==== ‘ & ==== &自定义实体:在DTD中定义 <’!ENTITY 实体标志 “实体内容”> ,在xml中引用自定义实体,用 &实体标志; 代表实体内容。另外,无法从键盘输入的字符可以使用字符引用,就是用字符的Unicode代码点来引用该字符。以””开始字符引用,以分号结尾,x必须为小写,使用十六进制。如: =’; 表示等于号。 也可以使用字符引用来引用 <,>,’,”,& ” 查看字符的代码点(附件-> 系统工具-> 字符映射表)。
当一段文本中出现很多实体引用和字符引用时,会导致文本数据的读写困难,CDATA段就是为了解决这一问题引入的。 DATA区段开始于 “<.![CDATA[” 结束于 “]]>” 。CDATA内部的所有东西都会被解析器忽略解析,不用检查它的格式。例如:
<superType 范围="200" 程度="100%"> <![CDATA[<"溅射"伤害>]]> </superType>解析后内容:<”溅射”伤害> ,但是CDATA段中不能嵌套另一个CDATA段。
XML文件允许自定义标记,所以可能出现同名字的标记,为了区分这些标记,就需要使用名称空间。名称空间的目的是有效的区分相同的标记,其实并不真实存在。
语法:使用属性 xmlns 来定义命名空间。 声明有前缀的名称空间 xmlns:前缀名=名称空间的名字 ; 声明无前缀的名称空间 xmlns=名称空间的名字 (缺省);
注意:当且仅当它们的名字相同时称二个名称空间相同,也就是说,对于有前缀的名称空间,如果二个名称空间的名字相同,即使前缀不相同,也是相同的名称空间,返之同然。前缀只是方便引用而已。
为什么需要验证?对XML文件施加额外的约束,以便交流。 规范的XML文件不一定是有效的;有效的一定是规范的。 构成格式良好的基本规则:
第一条指令(声明)必须顶头写,前面不能有任何空格等 ;标记必须成对;最外围的元素(根元素)只能有一个;属性只能出现在开始标记内;属性必须有值;属性值必须加引号(单引号、双引号都可以) ;元素可以嵌套,但是不能交叉;空元素可以简写,例:<.A><./A> 简写后:<.A/>;大小写敏感。root:根节点名称; DTDName.dtd:dtd文件的路径与名字,相同文件夹下可以省略路径,只用名字。
元素(ELEMENT)、属性(ATTLIST)、实体(ENTITY)、符号(NOTATION)。
(1)元素(ELEMENT):XML元素类型声明
声明元素:
<!ELEMENT 元素名 (内容模式)>元素的内容通过内容模式来描述。
DTD 内容模式的种类有:
EMPTY:元素不能包含任何数据,但可以有属性(前提是必须声明其属性);不能有子元素,不能有文本数据(包括空白,换行符);DTD中定义: <!ELEMENT elementName EMPTY>XML中:
<elementName/>(推荐) 或者: <elementName></elementName> (#PCDATA):规定元素只包含已析的字符数据,而不包含任何类型的子元素的内容类型;DTD中定义: <!ELEMENT student (#PCDATA)>XML中合法内容:
<student>watching TV</student> (Elements):元素由内容模式部件指定。 <!ELEMENT name (child particles) >内容模式部件可以是下表列出的内容:
<!ELEMENT name (a,b)> 子元素a、b必须出现,且按照列表的顺序 <!ELEMENT name (a|b)> 选择;子元素a、b只能出现一个 <!ELEMENT name (a) > 子元素a只能且必须出现一次 <!ELEMENT name (a)+ > 子元素a出现一次或多次 <!ELEMENT name (a)* > 子元素a出现任意次(包括零次、一次及多次) <!ELEMENT name (a)? > 子元素a出现一次或不出现 Mixed 混合模式:子元素中既可有文本数据又可有下级子元素。 <!ELEMENT rn (#PCDATA| an | en)*>“|”和“”必须写。上句表示在 rn 内,字符数据或en及an,可以出现任意多次,顺序不限。优先写(#PCDATA) 如:(#PCDATA|name) 正确 ,(name|#PCDATA)* 错误。
ANY:元素可以包含任何类型的数据。子元素(必须在DTD中有定义)和文本数据(包括空白)。DTD中定义: <!ELEMENT a ANY> <!ELEMENT b ANY>XML中合法内容:
<a>somngthing</a> 或者 <a/> 或者 <a><b>oo</b></a>(2)属性(ATTLIST):特定元素类型可设置的属性&属性的允许值声明
<!ATTLIST elementName attributeName1 attributeType attributeDefault ....... attributeNameN attributeType attributeDefault>属性类型 (Attribute Type):
CDATA :该属性只能包含字符数据(注意与CDATA段、PCDATA的区别) ;NMTOKEN :是CDATA的子集,它的字符只能是字母,数字,句点,破折号,下划线或冒号;NMTOKENS :类似NMTOKEN,但这个可以包含多个值,每个值之间用空格隔开;ID : 该属性的取值在同一文档内是唯一的。一个元素只能有一个ID类型的属性;IDREF :类似指针,指向文档中其他地方声明的ID值。如果该属性取值和指向的ID值不匹配,则返回错误。IDREFS :类似IDREF,但它可以具有由空格分隔开的多个引用;ENTITY: 该属性的值必须对应一个在文档内部声明的但还没有分析过的实体;ENTITYS:类似ENTITY,但它可以包含由空格分隔开的多个实体;NOTATION :该属性的值必须引用在文档中其他地方声明的某个注释的名称;(enumerated) :类似枚举的变量,该属性必须匹配所列的值。各值用“|”分隔开。 如: (春|夏|秋|冬) 实际内容文档只能从中取一个。属性特性 (Attribute Default) :
#REQUIRED 必须有且只能有一个属性;#IMPLIED 可有可无;#FIXED 在DTD中定义默认值,XML中可以不指定,指定则必须等于该默认值;attribute-value 如果不指定则用DTD定义的默认值,指定则用指定的值。属性(ATTLIST)的举例:
例一(#REQUIRED)
DTD中:
<!ELEMENT el (#PCDATA)> <!ATTLIST el at1 NMTOKENS #REQUIRED at2 CDATA #REQUIRED>XML中:
正确: <el at1 = "10 20" at2="10" >something</el> 错误: <el at="10">something</el> (没有写另一个#REQUIRED的属性 at2 )例二(#IMPLIED,#FIXED)
DTD中:
<!ELEMENT el (#PCDATA)> <!ATTLIST el at CDATA #FIXED "10" at2 CDATA #IMPLIED >XML中:
正确: <el at2="20" >something</el> (at有默认值"10",at2 可写可不写) 错误: <el at="11" >something</el>(at要么不写,要写只能写成跟默认值相同的)例三(attribute-value)
DTD中:
<!ELEMENT el (#PCDATA)> <!ATTLIST el at CDATA "10" at2 CDATA "20" >XML中:
正确: <el at="11" >something</el>例四(enumerated + attribute-value)
DTD中:
<!ELEMENT el (#PCDATA)> <!ATTLIST el at (10|20|30) "10">XML中:
正确: <el at="20">something</el> (at要么不写,默认值 10;要么在(10|20|30)中选一个写)(3)实体(ENTITY):可重用的内容声明。
在DTD中定义
<!ENTITY 实体标志 "实体内容">在xml中引用自定义的实体,用 &实体标志; 代表实体内容。
(4)符号(NOTATION) :不要解析的外部内容的格式声明。
内部实体:在xml文件里面写(少用); 外部实体:另外在xml同一文件夹下建立一个dtd文件(提倡);
外部的:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE root SYSTEM "goodsInfo.dtd"><!--用这句引用外部dtd--> <root> <goodsInfo> <goodsName>goodsName</goodsName> <goodsPrice>goodsPrice</goodsPrice> </goodsInfo> </root>以下是名为”goodsInfo.dtd”文件
<!ELEMENT root (goodsInfo)> <!ELEMENT goodsInfo (goodsName,goodsPrice)> <!ELEMENT goodsName (#PCDATA)> <!ELEMENT goodsPrice (#PCDATA)>内部的:
<?xml version="1.0" encodint="utf-8"?> <!DOCTYPE root [ <!ELEMENT root(student)> <!ELEMENT student (#PCDATA)> <!ENTITY CCTV "中央电视台"> ]> <!--把DTD文件写在体内--> <root> <student> student watch &CCTV;<!--使用自定义实体 CCTV--> </student> </root>xsd文档的作用:
定义可出现在文档中的元素;定义可出现在文档中的属性;定义哪个元素是子元素;定义子元素的次序;定义子元素的数目;定义元素是否为空,或者是否可包含文本 ;定义元素和属性的数据类型;定义元素和属性的默认值以及固定值;优点:
XML Schema本身就是一个XML;XML Schema 支持数据类型;XML Schema 支持名称空间;XML Schema 约束能力更强大;缺点:XML Schema比DTD更复杂,不能定义实体。
简单类型(元素,属性,Facet)、复杂类型元素、匿名类型、外置类型。
<xs:element name=“元素名” type=“元素类型"/>Schema内置了很多类型,常用的类型有:
xs:string 字符串;xs:decimal 浮点型;xs:integer 整型;xs:boolean 布尔型;xs:date 日期;xs:time 时间;xs:是命名空间前缀,元素的默认值用属性default指定,例:
<xs:element name="color" type="xs:string" default="red"/>元素的固定值用属性fixed指定,例:
<xs:element name="color" type="xs:string" fixed="red"/>元素出现的次数用属性minOccurs、maxOccurs来表示,默认值为1,unbounded表示不限制次数,例:
<xs:element name="comment" type=“xs:string” minOccurs="0"/> <xs:element name="item" type=“xs:string” minOccurs="99" maxOccurs="unbounded">属性声明语法:
<xs:attribute name=“属性名” type=“属性类型"/>属性声明通常会出现在元素声明中,Schema的内置类型同样对属性类型有效,属性的默认值用属性default指定;
<xs:attribute name=“gender" type="xs:string" default=“male"/>属性的固定值用属性fixed指定:
<xs:attribute name=“gender" type="xs:string" fixed=“male"/>属性必须或可选性用属性use指定:
<xs:attribute name=“gender" type="xs:string" use=“required"/>use属性值的取值有: optional(默认值)(可有可没有), required(必须有), prohibited(禁止,很少用)。
Facet(刻面):对xml元素或属性的简单数据类型进一步约束
限制字符串的长度, 包括 (length、minLength、maxLength) ;限制整数的大小范围,包括 (minInclusive, maxInclusive, minExclusive, maxExclusive) ;限制元素内容的枚举取值(enumeration);限制浮点型数值的位数(totalDigits, fractionDigits) ;定义在下列元素中:
<xs:simpleType> <xs:restriction> (此处写Facet) </xs:restriction> </xs:simpleType>复杂类型元素:包含其他元素和文本或属性的 XML 元素,语法:
使用元素 <xs:complexType/> 来定义四种类型的复杂元素:只包含属性、只包含属性和子元素、只包含文本内容和属性、包含属性,子元素和文本内容。
只包含属性 :
<xs:element name='blank'> <xs:complexType> <xs:attribute name='base' type='xs:integer' use='optional' default='10'/> </xs:complexType> </xs:element>只包含属性和子元素:
<xs:element name=‘customer'> <xs:complexType> <xs:sequence> <xs:element name=‘favor’ type=‘xs:string’/> </xs:sequence> <xs:attribute name=‘age' type='xs:integer'/> </xs:complexType> </xs:element>复杂类型元素包含的子元素出现的顺序
<sequence> --- 子元素必须以它们被声明的次序出现 <choice> --- 子元素是选择关系,只能出现其中一个 <all> --- 子元素可按任意次序出现只包含文本内容和属性:
<xs:element name='quantity'> <xs:complexType> <xs:simpleContent> <xs:extension base='xs:nonNegativeInteger'> <xs:attribute name='backorderable‘ type='xs:boolean'/> </xs:extension> </xs:simpleContent> </xs:complexType> </xs:element>包含属性,子元素和文本内容:
<xs:element name="工作经历"> <xs:complexType mixed="true"> <xs:sequence> <xs:element name="year“ type="xs:date"/> </xs:sequence> <xs:attribute name=“title” type=“xs:string”use=“optional”/> </xs:complexType> </xs:element>匿名类型定义:
<xs:element name="employee" > <xs:complexType> <xs:sequence> <xs:element name="firstname" type="xs:string"/> <xs:element name="lastname" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element>外置类型定义:
<xs:element name="employee" type=“emptype”/> <xs:complexType name=“emptype”> //必须定义在根元素中 <xs:sequence> <xs:element name="firstname" type="xs:string"/> <xs:element name="lastname" type="xs:string"/> </xs:sequence> </xs:complexType>Schema文件:
<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema" //必须且固定(名字xs 可改变) targetNamespace=" www.tarena.com.cn" xmlns="http://www.tarena.com.cn" elementFormDefault="qualified" />XML Schema 文件的根元素一定是<.schema>;
xmlns:xs=”http://www.w3.org/2001/XMLSchema”:指明schema 中用到的元素和数据类型来自的命名空间为“http://www.w3.org/2001/XMLSchema” ,xs为自定义的前缀名。
targetNamespace=”http://www.tarena.com.cn”:目标命名空间。用于指明此 xsd文档 约束的xml文件中元素 (note, to, from, heading, body) 的命名空间;
xmlns=”http://www.tarena.com.cn”: XSD也是一个XML文档, schema文档中默认的命名空间是 “http:// www.tarena.com.cn ” ;
elementFormDefault=”qualified“:Schema中定义的元素在xml中使用时,必须被命名空间限定。
受约束的XML文件:
<?xml version="1.0"?> <note xmlns="http://www.tarena.com.cn" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.tarena.com.cn note.xsd" />xmlns=”http://www.tarena.com.cn”:缺省命名空间的声明。此声明会告知 schema 验证器,在此 XML 文档中使用的元素默认都被声明于 “http://www.tarena.com.cn” 这个命名空间。
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=”http://www.tarena.com.cn note.xsd” /> :指定xsd的物理位置,前半部分是名称空间,后半部分参数是物理位置。使用的属性schemaLocation需要指定其所在的命名空间。
DOM:Document Object Model,文档对象模型。这种方式是W3C推荐的处理XML的一种标准方式。
SAX:Simple API for XML。这种方式不是官方标准,属于开源社区XML-DEV,几乎所有的XML解析器都支持它。
DOM与SAX比较:
DOM解析:处理大型文件时其性能下降的非常厉害。这个问题是由DOM的树结构所造成的,这种结构占用的内存较多,而且DOM必须在解析文件之前把整个文档装入内存,适合对XML的随机访问。优点:提供随机定义元素操作,来回移动指针、将整个XML文件一次性加载到内存,形成虚的内存树;缺点:如果XML文件较大,内存空间占用较大、强制将较大的XML文件加载到内存中,有可能损害文件。
SAX解析:不同于DOM,SAX是事件驱动型的XML解析方式。它顺序逐行读取XML文件,不需要一次全部装载整个文件。当遇到像文件开头,文档结束,或者标签开头与标签结束时,它会触发一个事件,用户通过在其回调事件中写入处理代码来处理XML文件,适合对XML的顺序访问。
JAXP:DOM或SAX方式进行解析XML。API在JDK之中;
JDom::JDOM是一个开源项目,它基于树型结构,利用纯JAVA的技术对XML文档实现解析、生成、序列化以及多种操作。(http://jdom.org),JDOM 直接为JAVA编程服务。它利用更为强有力的JAVA语言的诸多特性(方法重载、集合概念等),把SAX和DOM的功能有效地结合起来。JDOM是用Java语言读、写、操作XML的新API函数。在直接、简单和高效的前提下,这些API函数被最大限度的优化。
Dom4J(推荐):dom4j是目前在xml解析方面是最优秀的(Hibernate、Sun的JAXM也都使用dom4j来解析XML),它合并了许多超出基本 XML 文档表示的功能,包括集成的 XPath 支持、XML Schema 支持以及用于大文档或流化文档的基于事件的处理。
Java代码
import java.io.File; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; public class DomTest1 { public static void main(String[] args) throws Exception { // step 1: 获得dom解析器工厂(工作的作用是用于创建具体的解析器) DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); //System.out.println("class name: " + dbf.getClass().getName()); // step 2:获得具体的dom解析器 DocumentBuilder db = dbf.newDocumentBuilder(); //System.out.println("class name: " + db.getClass().getName()); // step3: 解析一个xml文档,获得Document对象(根结点) Document document = db.parse(new File("candidate.xml")); NodeList list = document.getElementsByTagName("PERSON"); for(int i = 0; i < list.getLength(); i++) { Element element = (Element)list.item(i); String content = element.getElementsByTagName("NAME") .item(0).getFirstChild().getNodeValue(); System.out.println("name:" + content); content = element.getElementsByTagName("ADDRESS") .item(0).getFirstChild().getNodeValue(); System.out.println("address:" + content); content = element.getElementsByTagName("TEL") .item(0).getFirstChild().getNodeValue(); System.out.println("tel:" + content); content = element.getElementsByTagName("FAX") .item(0).getFirstChild().getNodeValue(); System.out.println("fax:" + content); content = element.getElementsByTagName("EMAIL") .item(0).getFirstChild().getNodeValue(); System.out.println("email:" + content); System.out.println("--------------------------------------"); } } } import java.io.File; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Attr; import org.w3c.dom.Comment; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * 使用递归解析给定的任意一个xml文档并且将其内容输出到命令行上 * @author */ public class DomTest3 { public static void main(String[] args) throws Exception { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.parse(new File("student.xml")); //获得根元素结点 Element root = doc.getDocumentElement(); parseElement(root); } private static void parseElement(Element element){ String tagName = element.getNodeName(); NodeList children = element.getChildNodes(); System.out.print("<" + tagName); //element元素的所有属性所构成的NamedNodeMap对象,需要对其进行判断 NamedNodeMap map = element.getAttributes(); //如果该元素存在属性 if(null != map){ for(int i = 0; i < map.getLength(); i++){ //获得该元素的每一个属性 Attr attr = (Attr)map.item(i); String attrName = attr.getName(); String attrValue = attr.getValue(); System.out.print(" " + attrName + "=\"" + attrValue + "\""); } } System.out.print(">"); for(int i = 0; i < children.getLength(); i++){ Node node = children.item(i); //获得结点的类型 short nodeType = node.getNodeType(); if(nodeType == Node.ELEMENT_NODE){ //是元素,继续递归 parseElement((Element)node); } else if(nodeType == Node.TEXT_NODE){ //递归出口 System.out.print(node.getNodeValue()); } else if(nodeType == Node.COMMENT_NODE){ System.out.print("<!--"); Comment comment = (Comment)node; //注释内容 String data = comment.getData(); System.out.print(data); System.out.print("-->"); } } System.out.print("</" + tagName + ">"); } }Java代码
import java.io.File; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; public class SaxTest1{ public static void main(String[] args) throws Exception { //step1: 获得SAX解析器工厂实例 SAXParserFactory factory = SAXParserFactory.newInstance(); //step2: 获得SAX解析器实例 SAXParser parser = factory.newSAXParser(); //step3: 开始进行解析 parser.parse(new File("student.xml"), new MyHandler()); } } class MyHandler extends DefaultHandler { @Override public void startDocument() throws SAXException { System.out.println("parse began"); } @Override public void endDocument() throws SAXException { System.out.println("parse finished"); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { System.out.println("start element"); } @Override public void endElement(String uri, String localName, String qName) throws SAXException { System.out.println("finish element"); } } import java.io.File; import java.util.Stack; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; public class SaxTest2 { public static void main(String[] args) throws Exception { SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); parser.parse(new File("student.xml"), new MyHandler2()); } } class MyHandler2 extends DefaultHandler { private Stack<String> stack = new Stack<String>(); private String name; private String gender; private String age; @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { stack.push(qName); for(int i = 0; i < attributes.getLength(); i++) { String attrName = attributes.getQName(i); String attrValue = attributes.getValue(i); System.out.println(attrName + "=" + attrValue); } } @Override public void characters(char[] ch, int start, int length) throws SAXException { String tag = stack.peek(); if("姓名".equals(tag)) { name = new String(ch, start,length); } else if("性别".equals(tag)){ gender = new String(ch, start, length); } else if("年龄".equals(tag)){ age = new String(ch, start, length); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { stack.pop(); //表示该元素已经解析完毕,需要从栈中弹出 if("学生".equals(qName)){ System.out.println("姓名:" + name); System.out.println("性别:" + gender); System.out.println("年龄:" + age); System.out.println(); } } }Java代码:JDOM创建xml
import java.io.FileWriter; import org.jdom.Attribute; import org.jdom.Comment; import org.jdom.Document; import org.jdom.Element; import org.jdom.output.Format; import org.jdom.output.XMLOutputter; public class JDomTest1{ public static void main(String[] args) throws Exception { Document document = new Document(); Element root = new Element("root"); document.addContent(root); Comment comment = new Comment("This is my comments"); root.addContent(comment); Element e = new Element("hello"); e.setAttribute("sohu", "www.sohu.com"); root.addContent(e); Element e2 = new Element("world"); Attribute attr = new Attribute("test", "hehe"); e2.setAttribute(attr); e.addContent(e2); e2.addContent(new Element("aaa").setAttribute("a", "b") .setAttribute("x", "y").setAttribute("gg", "hh").setText("text content")); Format format = Format.getPrettyFormat(); format.setIndent(" "); // format.setEncoding("gbk"); XMLOutputter out = new XMLOutputter(format); out.output(document, new FileWriter("jdom.xml")); } }Java代码:JDOM解析xml
import java.io.File; import java.io.FileOutputStream; import java.util.List; import org.jdom.Attribute; import org.jdom.Document; import org.jdom.Element; import org.jdom.input.SAXBuilder; import org.jdom.output.Format; import org.jdom.output.XMLOutputter; public class JDomTest2 { public static void main(String[] args) throws Exception { SAXBuilder builder = new SAXBuilder(); Document doc = builder.build(new File("jdom.xml")); Element element = doc.getRootElement(); System.out.println(element.getName()); Element hello = element.getChild("hello"); System.out.println(hello.getText()); List list = hello.getAttributes(); for(int i = 0 ;i < list.size(); i++) { Attribute attr = (Attribute)list.get(i); String attrName = attr.getName(); String attrValue = attr.getValue(); System.out.println(attrName + "=" + attrValue); } hello.removeChild("world"); XMLOutputter out = new XMLOutputter(Format.getPrettyFormat().setIndent(" ")); out.output(doc, new FileOutputStream("jdom2.xml")); } }Java代码:DOM4J解析XML单元测试
package com.study.xml.junit; import java.io.FileOutputStream; import java.io.OutputStream; import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.dom4j.Node; import org.dom4j.io.OutputFormat; import org.dom4j.io.SAXReader; import org.dom4j.io.XMLWriter; import org.junit.Test; /** * @Name: DOM4JTest * @Description: 使用DOM4J解析XML测试类 * @Author: XXX * @CreateDate: XXX * @Version: V1.0 */ public class DOM4JTest { /** * @Name: writeXML2Console * @Description: 将指定XML文件中的内容打印到控制台 * @Author: XXX * @Version: V1.0 * @CreateDate: XXX * @Parameters: * @Return: void */ @Test public void writeXML2Console() throws Exception { SAXReader reader = new SAXReader() ; String url = "src/books.xml" ; Document document = reader.read(url) ; OutputFormat format = OutputFormat.createPrettyPrint() ; XMLWriter writer = new XMLWriter(System.out, format) ; writer.write(document) ; } /** * @Name: findElementContent * @Description: 得到某个具体节点的内容 * 例如: * 得到第二本书节点中的售价节点的内容 * @Author: XXX * @Version: V1.0 * @CreateDate: XXX * @Parameters: * @Return: void */ @Test public void findElementContent() throws Exception { SAXReader reader = new SAXReader() ; String url = "src/books.xml" ; Document document = reader.read(url) ; Element rootElement = document.getRootElement() ; Element secondBook = (Element) rootElement.elements("书").get(1) ; Element salePrice = secondBook.element("售价") ; System.out.println(salePrice.getUniquePath() + "[" + salePrice.getText() + "]"); } /** * @Name: iteratorAllElement * @Description: 遍历所有元素节点 * @Author: XXX * @Version: V1.0 * @CreateDate: XXX * @Parameters: * @Return: void */ @Test public void iteratorAllElement() throws Exception { SAXReader reader = new SAXReader() ; String url = "src/books.xml" ; Document document = reader.read(url) ; Element rootElement = document.getRootElement() ; treeWalk(rootElement) ; } private void treeWalk(Element element) { System.out.println(element.getName()); for (int i = 0; i < element.nodeCount(); i++) { Node node = element.node(i) ; if(node instanceof Element) { treeWalk((Element) node) ; } } } /** * @Name: updateElementContent * @Description: 修改某个元素节点下的内容 * 例如: * 修改第二本书节点下售价节点的内容为300 * @Author: XXX * @Version: V1.0 * @CreateDate: XXX * @Parameters: * @Return: void */ @Test public void updateElementContent() throws Exception { SAXReader reader = new SAXReader() ; String url = "src/books.xml" ; Document document = reader.read(url) ; Element rootElement = document.getRootElement() ; Element secondBook = (Element) rootElement.elements("书").get(1) ; Element salePrice = secondBook.element("售价") ; salePrice.setText("300") ; OutputStream out = new FileOutputStream(url) ; OutputFormat format = OutputFormat.createPrettyPrint() ; format.setEncoding("UTF-8") ; XMLWriter writer = new XMLWriter(out, format) ; writer.write(document) ; } /** * @Name: addChildElement * @Description: 向指定元素节点增加子节点 * 例如: * 在第二本书节点下增加内部价:<批发价 id="p2" name="pfj">800</批发价> * @Author: XXX * @Version: V1.0 * @CreateDate: XXX * @Parameters: * @Return: void */ @Test public void addChildElement() throws Exception { SAXReader reader = new SAXReader() ; String url = "src/books.xml" ; Document document = reader.read(url) ; Element rootElement = document.getRootElement() ; Element secondBook = (Element) rootElement.elements("书").get(1) ; secondBook.addElement("批发价") .addAttribute("id", "p2") .addAttribute("name", "pfj") .addText("800") ; OutputStream out = new FileOutputStream(url) ; OutputFormat format = OutputFormat.createPrettyPrint() ; format.setEncoding("UTF-8") ; XMLWriter writer = new XMLWriter(out, format) ; writer.write(document) ; } /** * @Name: addSameLevelElement * @Description: 向指定元素节点下增加同级元素节点 * 例如: * 向第二本书节点的售价前增加内部价<内部价>200</内部价> * @Author: XXX * @Version: V1.0 * @CreateDate: XXX * @Parameters: * @Return: void */ @Test public void addSameLevelElement() throws Exception { SAXReader reader = new SAXReader() ; String url = "src/books.xml" ; Document document = reader.read(url) ; Element rootElement = document.getRootElement() ; Element secondBook = (Element) rootElement.elements("书").get(1) ; Element innerPrice = DocumentHelper.createElement("内部价") ; innerPrice.addText("200") ; secondBook.elements().add(2, innerPrice) ; OutputStream out = new FileOutputStream(url) ; OutputFormat format = OutputFormat.createPrettyPrint() ; format.setEncoding("UTF-8") ; XMLWriter writer = new XMLWriter(out, format) ; writer.write(document) ; } /** * @Name: deleteElement * @Description: 删除指定元素节点: * 例如: * 删除第二本书节点下的批发价节点 * @Author: XXX * @Version: V1.0 * @CreateDate: XXX * @Parameters: * @Return: void */ @Test public void deleteElement() throws Exception { SAXReader reader = new SAXReader() ; String url = "src/books.xml" ; Document document = reader.read(url) ; Element rootElement = document.getRootElement() ; Element secondBook = (Element) rootElement.elements("书").get(1) ; Element pfj = secondBook.element("批发价") ; secondBook.remove(pfj) ; OutputStream out = new FileOutputStream(url) ; OutputFormat format = OutputFormat.createPrettyPrint() ; format.setEncoding("UTF-8") ; XMLWriter writer = new XMLWriter(out, format) ; writer.write(document) ; } /** * @Name: opeElementAttribute * @Description: 操作节点属性 * 例如: * 添加:向第二本书节点上添加属性:bookid="a2" * 删除:删除第二本书节点中批发价节点的name属性 * 修改:将第三本书节点的id属性改为:bookid="a33" * @Author: XXX * @Version: V1.0 * @CreateDate: XXX * @Parameters: * @Return: void */ @Test public void opeElementAttribute() throws Exception { SAXReader reader = new SAXReader() ; String url = "src/books.xml" ; Document document = reader.read(url) ; Element rootElement = document.getRootElement() ; //向第二本书节点上添加属性:bookid="a2" Element secondBook = (Element) rootElement.elements("书").get(1) ; secondBook.addAttribute("bookid", "a2") ; //删除批发价中的name属性 Element pfj = secondBook.element("批发价") ; Attribute name = pfj.attribute("name") ; pfj.remove(name) ; //将第三本书节点的id属性改为:bookid="a33" Element thridBook = (Element) rootElement.elements("书").get(2) ; thridBook.setAttributeValue("bookid", "a33") ; OutputStream out = new FileOutputStream(url) ; OutputFormat format = OutputFormat.createPrettyPrint() ; format.setEncoding("UTF-8") ; XMLWriter writer = new XMLWriter(out, format) ; writer.write(document) ; } }百度百科解释:
XPath即为XML路径语言,它是一种用来确定XML(标准通用标记语言的子集)文档中某部分位置的语言。XPath基于XML的树状结构,提供在数据结构树中找寻节点的能力。起初 XPath 的提出的初衷是将其作为一个通用的、介于XPointer与XSLT间的语法模型。但是 XPath 很快的被开发者采用来当作小型查询语言。
XPath是一个努力为XSL转换XSLT和XPointer之间共享一个共同的XPointer功能语法和语义的结果。它的主要目的是解决一个XML XML文档部分[ ]。为了支持这一功能,还提供用于处理字符串的基本设施、数字和布尔值。XPath使用一个紧凑的、非XML语法方便使用在uri和XML属性值的XPath。XPath操作基于XML文档的逻辑结构,而不是其表面的语法。Xpath的名字来自其使用的符号在URL路径通过一个XML文档的层次结构导航。 除了用于定位,XPath还设计有一个真子集,可用于匹配(测试一个节点是否符合一个模式);使用XPath进行XSLT。
XPath模型的XML文档的节点树。有不同类型的节点,包括元素节点、属性节点和文本节点。XPath定义了一个方法来计算每个节点类型字符串值。某些类型的节点也有名字。XPath完全支持XML命名空间的XML名称。因此,一个节点的名称被建模为一个地方的部分和一个可能的空命名空间URI;这就是所谓的扩展名。
Java代码:DOM4J+XPATH解析XML文件
package com.study.xml.junit; import java.io.FileOutputStream; import java.io.OutputStream; import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.dom4j.Node; import org.dom4j.XPath; import org.dom4j.io.OutputFormat; import org.dom4j.io.SAXReader; import org.dom4j.io.XMLWriter; import org.junit.Test; import com.study.xml.utils.DOM4JUtils; /** * @Name: DOM4JXpathTest * @Description: 使用DOM4J解析XML测试类,使用Xpath语法定位元素位置 * @Author: XXX * @CreateDate: XXX * @Version: V1.0 */ public class DOM4JXpathTest { /** * @Name: writeXML2Console * @Description: 将指定XML文件中的内容打印到控制台 * @Author: XXX * @Version: V1.0 * @CreateDate: XXX * @Parameters: * @Return: void */ @Test public void writeXML2Console() throws Exception { SAXReader reader = new SAXReader() ; String url = "src/books.xml" ; Document document = reader.read(url) ; OutputFormat format = OutputFormat.createPrettyPrint() ; XMLWriter writer = new XMLWriter(System.out, format) ; writer.write(document) ; } /** * @Name: findElementContent * @Description: 得到某个具体节点的内容 * 例如: * 得到第二本书节点中的售价节点的内容 * @Author: XXX * @Version: V1.0 * @CreateDate: XXX * @Parameters: * @Return: void */ @Test public void findElementContent() throws Exception { SAXReader reader = new SAXReader() ; String url = "src/books.xml" ; Document document = reader.read(url) ; Node salePrice = document.selectSingleNode("/书架/书[2]/售价") ; System.out.println(salePrice.getUniquePath() + "[" + salePrice.getText() + "]"); } /** * @Name: iteratorAllElement * @Description: 遍历所有元素节点 * @Author: XXX * @Version: V1.0 * @CreateDate: XXX * @Parameters: * @Return: void */ @Test public void iteratorAllElement() throws Exception { SAXReader reader = new SAXReader() ; String url = "src/books.xml" ; Document document = reader.read(url) ; Element rootElement = document.getRootElement() ; treeWalk(rootElement) ; } private void treeWalk(Element element) { System.out.println(element.getName()); for (int i = 0; i < element.nodeCount(); i++) { Node node = element.node(i) ; if(node instanceof Element) { treeWalk((Element) node) ; } } } /** * @Name: updateElementContent * @Description: 修改某个元素节点下的内容 * 例如: * 修改第二本书节点下售价节点的内容为300 * @Author: XXX * @Version: V1.0 * @CreateDate: XXX * @Parameters: * @Return: void */ @Test public void updateElementContent() throws Exception { SAXReader reader = new SAXReader() ; String url = "src/books.xml" ; Document document = reader.read(url) ; Element salePrice = (Element) document.selectSingleNode("/书架/书[2]/售价") ; salePrice.setText("300") ; OutputStream out = new FileOutputStream(url) ; OutputFormat format = OutputFormat.createPrettyPrint() ; format.setEncoding("UTF-8") ; XMLWriter writer = new XMLWriter(out, format) ; writer.write(document) ; } /** * @Name: addChildElement * @Description: 向指定元素节点增加子节点 * 例如: * 向第二本书节点的售价前增加内部价:<批发价 id="p2" name="pfj">800</批发价> * @Author: XXX * @Version: V1.0 * @CreateDate: XXX * @Parameters: * @Return: void */ @Test public void addChildElement() throws Exception { String url = "src/books.xml" ; Document document = DOM4JUtils.getDocument(url) ; Element secondBook = (Element) document.selectSingleNode("//书[2]") ; secondBook.addElement("批发价") .addAttribute("id", "p2") .addAttribute("name", "pfj") .addText("800") ; DOM4JUtils.writeBackXml(document, url) ; } /** * @Name: addSameLevelElement * @Description: 向指定元素节点下增加同级元素节点 * 例如: * 向第二本书节点的售价前增加内部价<内部价>200</内部价> * @Author: XXX * @Version: V1.0 * @CreateDate: XXX * @Parameters: * @Return: void */ @Test public void addSameLevelElement() throws Exception { String url = "src/books.xml" ; Document document = DOM4JUtils.getDocument(url) ; Element secondBook = (Element) document.selectSingleNode("/书架/书[2]") ; Element innerPrice = DocumentHelper.createElement("内部价") ; innerPrice.addText("200") ; //向第二本书节点的售价前增加内部价<内部价>200</内部价> secondBook.elements().add(2, innerPrice) ; DOM4JUtils.writeBackXml(document, url) ; } /** * @Name: deleteElement * @Description: 删除指定元素节点: * 例如: * 删除第二本书节点下的批发价节点 * @Author: XXX * @Version: V1.0 * @CreateDate: XXX * @Parameters: * @Return: void */ @Test public void deleteElement() throws Exception { String url = "src/books.xml" ; Document document = DOM4JUtils.getDocument(url) ; Element secondBook = (Element) document.selectSingleNode("/书架/书[2]") ; Element pfj = secondBook.element("批发价") ; //删除第二本书节点下的批发价节点 secondBook.remove(pfj) ; DOM4JUtils.writeBackXml(document, url) ; } /** * @Name: opeElementAttribute * @Description: 操作节点属性 * 例如: * 添加:向第二本书节点上添加属性:bookid="a2" * 删除:删除第二本书节点中批发价节点的name属性 * 修改:将第三本书节点的id属性改为:bookid="a33" * @Author: XXX * @Version: V1.0 * @CreateDate: XXX * @Parameters: * @Return: void */ @Test public void opeElementAttribute() throws Exception { String url = "src/books.xml" ; Document document = DOM4JUtils.getDocument(url) ; //向第二本书节点上添加属性:bookid="a2" Element secondBook = (Element) document.selectSingleNode("//书[2]") ; secondBook.addAttribute("bookid", "a2") ; //删除批发价中的name属性 Element pfj = secondBook.element("批发价") ; Attribute name = pfj.attribute("name") ; pfj.remove(name) ; //将第三本书节点的id属性改为:bookid="a33" Element thridBook = (Element) document.selectSingleNode("//书[3]") ; thridBook.setAttributeValue("bookid", "a33") ; DOM4JUtils.writeBackXml(document, url) ; } }使用DOM4J+XPATH解析XML实践:使用XML实现数据存储,将页面用户提交的数据存储到xml进行持久化,按照分层设计思想,使用Jsp+Servlet实现简单的用户注册系统。
(1)导入依赖包:dom4j-1.6.1.jar、jaxen-1.1-beta-6.jar、commons-beanutils-1.8.3.jar、commons-logging-1.1.1.jar。
(2)编写xml文件:users.xml
<?xml version="1.0" encoding="UTF-8"?> <users> <user username="admin" password="admin" birthday="2016-01-12" email="123@123.com"/> <user username="test01" password="test01" birthday="2016-01-12" email="123@123.com"/> <user username="test02" password="test02" birthday="2016-01-12" email="123@123.com"/> </users>(3)创建JavaBean:User.java
说明:JavaBean中的属性与xml文件中user节点的属性名称保持一致,以便将JavaBean属性值传入xml文档进行存储。
package com.study.java.domain; import java.io.Serializable; import java.util.Date; /** * @Name: User * @Description: PO类:用户信息类 * @Author: XXX * @CreateDate: XXX * @Version: V1.0 */ public class User implements Serializable { private static final long serialVersionUID = 5274992031371114394L; private String username ; private String password ; private Date birthday ; private String email ; public User() {} public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } @Override public String toString() { return "User [username=" + username + ", password=" + password + ", birthday=" + birthday + ", email=" + email + "]"; } }(1)编写DOM4JUtils工具类
package com.study.java.utils; import java.io.FileOutputStream; import java.io.OutputStream; import java.net.URL; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.io.OutputFormat; import org.dom4j.io.SAXReader; import org.dom4j.io.XMLWriter; /** * @Name: DOM4JUtils * @Description: XML-DOM4J解析工具包 * @Author: XXX * @CreateDate: XXX * @Version: V1.0 */ public class DOM4JUtils { private static String XMLPATH = "users.xml" ; static { ClassLoader loader = DOM4JUtils.class.getClassLoader() ; URL url = loader.getResource(XMLPATH) ; XMLPATH = url.getPath() ; } /** * @Name: getDocument * @Description: 获取xml-Document对象 * @Author: XXX * @Version: V1.0 * @CreateDate: XXX * @Return: Document */ public static Document getDocument() { Document document = null ; try { SAXReader reader = new SAXReader() ; document = reader.read(XMLPATH) ; } catch (DocumentException e) { e.printStackTrace(); } return document ; } /** * @Name: writeXML * @Description: 将内存中的xml数据写入到xml文件中 * @Author: XXX * @Version: V1.0 * @CreateDate: XXX * @Parameters: @param document * @Return: void */ public static void writeXML(Document document) { OutputStream out = null ; OutputFormat format = null ; XMLWriter writer = null ; try { out = new FileOutputStream(XMLPATH) ; format = OutputFormat.createPrettyPrint() ; format.setEncoding("UTF-8") ; writer = new XMLWriter(out, format) ; writer.write(document) ; } catch (Exception e) { throw new RuntimeException(e) ; } finally { if(writer != null) { try { writer.close() ; } catch (Exception e) { e.printStackTrace() ; } finally { writer = null ; } } if(out != null) { try { out.close() ; } catch (Exception e) { e.printStackTrace() ; } finally { out = null ; } } } } }(2)编写日期格式处理工具类:DateConverterUtils.java
package com.study.java.utils; import java.text.SimpleDateFormat; import java.util.Date; /** * @Name: DateConverterUtils * @Description: 日期-字符串转换工具类 * @Author: XXX * @CreateDate: XXX * @Version: V1.0 */ public class DateConverterUtils { private static final String FORMAT = "yyyy-MM-dd" ; private static SimpleDateFormat sdf = null ; static { sdf = new SimpleDateFormat(FORMAT) ; } /** * @Name: parse * @Description: 将给定的字符串转换成日期类型 * @Author: XXX * @Version: V1.0 * @CreateDate: XXX * @Parameters: @param str * @Return: Date */ public static Date parse(String str) { Date date = null ; try { date = sdf.parse(str) ; } catch (Exception e) { throw new RuntimeException(e) ; } return date ; } /** * @Name: format * @Description: 格式化日期类型到字符串 * @Author: XXX * @Version: V1.0 * @CreateDate: XXX * @Parameters: @param date * @Return: String */ public static String format(Date date) { String result = null ; try { result = sdf.format(date) ; } catch (Exception e) { throw new RuntimeException(e) ; } return result ; } }(1)开发UserDao接口
package com.study.java.dao; import com.study.java.domain.User; /** * @Name: UserDao * @Description: 用户信息操作DAO接口 * @Author: XXX * @CreateDate: XXX * @Version: V1.0 */ public interface UserDao { /** * @Name: getUserByUsername * @Description: 根据用户名获取用户信息 * @Author: XXX * @Version: V1.0 * @CreateDate: XXX * @Parameters: @param username * @Return: User */ User getUserByUsername(String username) ; /** * @Name: getUserByUsernameAndPassword * @Description: 根据用户名和密码获取用户信息 * @Author: XXX * @Version: V1.0 * @CreateDate: XXX * @Parameters: @param username * @Parameters: @param password * @Return: User */ User getUserByUsernameAndPassword(String username, String password) ; /** * @Name: addUser * @Description: 添加用户信息到xml * @Author: XXX * @Version: V1.0 * @CreateDate: XXX * @Parameters: @param user * @Return: void */ void addUser(User user) ; }(2)开发UserDao接口实现类(练习重点:使用XML解析技术实现数据的存储和读取)
package com.study.java.dao.impl; import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.dom4j.Node; import com.study.java.dao.UserDao; import com.study.java.domain.User; import com.study.java.utils.DOM4JUtils; import com.study.java.utils.DateConverterUtils; /** * @Name: UserDaoImpl * @Description: 用户信息操作DAO接口实现类 * @Author: XXX * @CreateDate: XXX * @Version: V1.0 */ public class UserDaoImpl implements UserDao { public User getUserByUsername(String username) { User user = null ; //1、获取domcument对象 Document document = DOM4JUtils.getDocument() ; //2、使用xpath获取指定的user节点元素 Element userElement = (Element) document .selectSingleNode("//user[@username='"+ username +"']") ; if(userElement != null) { //3、将获取到的user节点元素中的属性值放入到user-bean中 user = new User() ; user.setUsername(userElement.valueOf("@username")) ; user.setPassword(userElement.valueOf("@password")) ; //将字符串转换成日期类型 user.setBirthday(DateConverterUtils .parse(userElement.valueOf("@birthday"))) ; user.setEmail(userElement.valueOf("@email")) ; } //4、返回查询结果 return user; } public User getUserByUsernameAndPassword(String username, String password) { User user = null ; //1、获取domcument对象 Document document = DOM4JUtils.getDocument() ; //2、使用xpath获取指定的user节点元素 Element userElement = (Element) document .selectSingleNode("//user[@username='"+ username + "' and @password='"+ password +"']") ; if(userElement != null) { //3、将获取到的user节点元素中的属性值放入到user-bean中 user = new User() ; user.setUsername(userElement.valueOf("@username")) ; user.setPassword(userElement.valueOf("@password")) ; //将字符串转换成日期类型 user.setBirthday(DateConverterUtils .parse(userElement.valueOf("@birthday"))) ; user.setEmail(userElement.valueOf("@email")) ; } //4、返回查询结果 return user; } public void addUser(User user) { //1、获取document对象 Document document = DOM4JUtils.getDocument() ; //2、获取根节点元素 Element rootElement = document.getRootElement() ; //3、创建新user节点元素,将user-bean中的属性值设置到user节点的属性中 Element newUserElement = DocumentHelper.createElement("user") ; newUserElement.addAttribute("username", user.getUsername()) ; newUserElement.addAttribute("password", user.getPassword()) ; newUserElement.addAttribute("birthday", DateConverterUtils.format(user.getBirthday())) ; newUserElement.addAttribute("email", user.getEmail()) ; //4、加入新节点 rootElement.add(newUserElement) ; //5、写回到xml DOM4JUtils.writeXML(document) ; } }(1)开发UserService接口
package com.study.java.service; import com.study.java.domain.User; /** * @Name: UserService * @Description: 用户信息操作Service接口 * @Author: XXX * @CreateDate: XXX * @Version: V1.0 */ public interface UserService { /** * @Name: login * @Description: 登录操作 * @Author: XXX * @Version: V1.0 * @CreateDate: XXX * @Parameters: @param username * @Parameters: @param password * @Return: User */ User login(String username, String password) ; /** * @Name: register * @Description: 注册操作 * @Author: XXX * @Version: V1.0 * @CreateDate: XXX * @Parameters: @param user * @Return: boolean */ boolean register(User user) ; }(2)开发UserService接口实现类
package com.study.java.service.impl; import com.study.java.dao.UserDao; import com.study.java.dao.impl.UserDaoImpl; import com.study.java.domain.User; import com.study.java.service.UserService; /** * @Name: UserServiceImpl * @Description: 用户信息操作Service接口实现类 * @Author: XXX * @CreateDate: XXX * @Version: V1.0 */ public class UserServiceImpl implements UserService { private UserDao userDao = new UserDaoImpl() ; public User login(String username, String password) { User user = null ; try { user = userDao.getUserByUsernameAndPassword(username, password) ; } catch (Exception e) { e.printStackTrace() ; } return user; } public boolean register(User user) { //判断用户名是否已经存在 User u = userDao.getUserByUsername(user.getUsername()) ; if(u == null) { userDao.addUser(user) ; return true ; } return false; } }(1)编写WebFormBean:UserFormBean.java
package com.study.java.web.bean; import java.util.HashMap; import java.util.Map; import com.study.java.utils.DateConverterUtils; /** * @Name: UserFormBean * @Description: 表单VO类:用户表单信息类 * @Author: XXX * @CreateDate: XXX * @Version: V1.0 */ public class UserFormBean { private String username ; private String password ; private String repassword ; private String birthday ; private String email ; //校验错误信息集合 private Map<String, String> errorMsg = new HashMap<String, String>() ; public UserFormBean() {} /** * @Name: validate * @Description: 校验注册字段格式 * @Author: XXX * @Version: V1.0 * @CreateDate: XXX * @Parameters: * @Return: void */ public boolean validate() { if(username == null || "".equals(username.toString().trim())) { errorMsg.put("username", "用户名不能为空!") ; } else { if(!username.matches("^[a-zA-Z]{3,8}$")) { errorMsg.put("username", "用户名必须为3-8位的字母!") ; } } if(password == null || "".equals(password)) { errorMsg.put("password", "密码不能为空!") ; } else { if(!password.matches("^[a-zA-Z]{3,8}$")) { errorMsg.put("password", "密码必须为3-8位的字母!") ; } } if(!repassword.equals(password)) { errorMsg.put("repassword", "与原密码输入不一致!") ; } if(birthday == null || "".equals(birthday)) { errorMsg.put("birthday", "出生年月不能为空!") ; } else { try { DateConverterUtils.parse(birthday) ; } catch (Exception e) { errorMsg.put("birthday", "输入格式(yyyy-MM-dd)不正确!") ; } } if(email == null || "".equals(email)) { errorMsg.put("email", "邮箱不能为空!") ; } else { if(!email.matches("\\b^['_a-z0-9-\\+]+(\\.['_a-z0-9-\\+]+)*@[a-z0-9-]+(\\.[a-z0-9-]+)*\\.([a-z]{2}|aero|arpa|asia|biz|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|nato|net|org|pro|tel|travel|xxx)$\\b")) { errorMsg.put("email", "邮箱格式错误!") ; } } return errorMsg.isEmpty() ; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getRepassword() { return repassword; } public void setRepassword(String repassword) { this.repassword = repassword; } public String getBirthday() { return birthday; } public void setBirthday(String birthday) { this.birthday = birthday; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public Map<String, String> getErrorMsg() { return errorMsg; } public void setErrorMsg(Map<String, String> errorMsg) { this.errorMsg = errorMsg; } }(2)开发前端控制器:ControllerServlet.java
package com.study.java.web.controller; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import com.study.java.domain.User; import com.study.java.service.UserService; import com.study.java.service.impl.UserServiceImpl; import com.study.java.utils.WebUtils; import com.study.java.web.bean.UserFormBean; /** * @Name: ControllerServlet * @Description: 用户操作控制器 * @Author: XXX * @CreateDate: XXX * @Version: V1.0 */ public class ControllerServlet extends HttpServlet { private UserService userService = new UserServiceImpl() ; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String operate = request.getParameter("op") ; if("logout".equals(operate)) { logout(request, response) ; } if("login".equals(operate)) { login(request, response) ; } if("register".equals(operate)) { register(request, response) ; } } /** * @Name: register * @Description: 注册 * @Author: XXX * @Version: V1.0 * @CreateDate: XXX * @Parameters: @param request * @Parameters: @param response * @Parameters: @throws ServletException * @Parameters: @throws IOException * @Return: void */ private void register(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8") ; PrintWriter out = response.getWriter() ; //获取表单Bean实例对象 UserFormBean userFormBean = WebUtils.fillBean(request, UserFormBean.class) ; //对页面表单中输入的字段格式进行校验 if(!userFormBean.validate()) { request.setAttribute("userFormBean", userFormBean) ; request.getRequestDispatcher("/jsp/register.jsp").forward(request, response) ; return ; } //对象拷贝:UserFormBean -> UserBean User user = WebUtils.copyProperties(User.class, userFormBean) ; //注册,保存到xml boolean result = userService.register(user) ; if(result) { //将用户信息保存到session HttpSession session = request.getSession() ; session.setAttribute("user", user) ; out.write("注册成功,2秒后跳转到系统首页!!!") ; response.setHeader("Refresh", "2;URL=" + request.getContextPath()) ; } else { userFormBean.getErrorMsg().put("username", "用户名已存在!") ; request.setAttribute("userFormBean", userFormBean) ; request.getRequestDispatcher("/jsp/register.jsp").forward(request, response) ; } } /** * @Name: login * @Description: 登录 * @Author: XXX * @Version: V1.0 * @CreateDate: XXX * @Parameters: @param request * @Parameters: @param response * @Parameters: @throws ServletException * @Parameters: @throws IOException * @Return: void */ private void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8") ; PrintWriter out = response.getWriter() ; //获取页面请求参数 request.setCharacterEncoding("UTF-8") ; //设置请求参数内容编码,适用于post提交 String username = request.getParameter("username") ; String password = request.getParameter("password") ; User user = userService.login(username, password) ; if(user != null) { HttpSession session = request.getSession() ; session.setAttribute("user", user) ; out.write("登录成功,2秒后跳转到系统首页!!!") ; response.setHeader("Refresh", "2;URL=" + request.getContextPath()) ; } else { out.write("用户名或密码错误,登录失败,请重新登录!!!") ; response.setHeader("Refresh", "2;URL=" + request.getContextPath() + "/jsp/login.jsp") ; } } /** * @Name: logout * @Description: 注销 * @Author: XXX * @Version: V1.0 * @CreateDate: XXX * @Parameters: @param request * @Parameters: @param response * @Parameters: @throws ServletException * @Parameters: @throws IOException * @Return: void */ private void logout(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=utf-8") ; PrintWriter out = response.getWriter() ; HttpSession session = request.getSession() ; session.removeAttribute("user") ; out.write("注销成功,2秒后跳转到系统首页!!!") ; response.setHeader("Refresh", "2;URL=" + request.getContextPath()) ; } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } }(3)配置web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <display-name></display-name> <servlet> <servlet-name>ControllerServlet</servlet-name> <servlet-class>com.study.java.web.controller.ControllerServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>ControllerServlet</servlet-name> <url-pattern>/servlet/ControllerServlet</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>(1)系统首页:index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>首页</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> </head> <body> <h1>练习项目</h1> <hr/> <c:choose> <c:when test="${sessionScope.user == null }"> <a href="${pageContext.request.contextPath }/jsp/register.jsp">注册</a> <a href="${pageContext.request.contextPath }/jsp/login.jsp">登录</a> </c:when> <c:otherwise> 欢迎您!!!${sessionScope.user.username } <a href="${pageContext.request.contextPath }/servlet/ControllerServlet?op=logout">注销</a> </c:otherwise> </c:choose> </body> </html>(2)登录页面:login.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>登录</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> </head> <body> <form action="${pageContext.request.contextPath }/servlet/ControllerServlet?op=login" method="post"> 用户名:<input type="text" name="username"/><br/> 密 码:<input type="password" name="password"/><br> <input type="submit" value="登录"/> </form> </body> </html>(3)注册页面:register.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>注册</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <script type="text/javascript" src="${pageContext.request.contextPath }/js/Birthday-Calendar.js" ></script> </head> <body> <form action="${pageContext.request.contextPath }/servlet/ControllerServlet? op=register" method="post"> <table border="1" align="center"> <tr> <td>用户名:</td> <td> <input type="text" name="username" value="${userFormBean.username }"> ${userFormBean.errorMsg.username } </td> </tr> <tr> <td>密 码:</td> <td> <input type="password" name="password" value="${userFormBean.password }"> ${userFormBean.errorMsg.password } </td> </tr> <tr> <td>确认密码:</td> <td> <input type="password" name="repassword" value="${userFormBean.repassword }"> </td> </tr> <tr> <td>出生年月:</td> <td> <input type="text" name="birthday" onclick="new Calendar().show(this);" readonly="readonly"> ${userFormBean.errorMsg.birthday } </td> </tr> <tr> <td>邮 箱:</td> <td> <input type="text" name="email" value="${userFormBean.email }"> ${userFormBean.errorMsg.email } </td> </tr> <tr> <td colspan="2" align="center"> <input type="submit" value="提交" /> <input type="reset" value="重置" /> </td> </tr> </table> </form> </body> </html>Jsp+Servlet+Xml实现简单注册系统:http://git.oschina.net/li2chao/XMLRegisterSystem
