XML
eXtensible Markup Language,主要用于自定义标记。
相较于它的兄弟HTML,XML语法十分严谨,不像HTML能够交叉嵌套,甚至有些标签可以省略掉结束标签。由于其语法的严谨性,能保证使用一个
统一的解析器进行解析,从而能确保跨平台的实现,以及互操作性。
常用解析器包括:MSXML、OpenXML、IBM XML4J、Apache Xerces、Oracel XML Parser等。
应用范围
数据交换
web service
数据管理(数据库)
系统配置
技术体系
校验(DTD+Schema)
显示与转换(XSL)
查询(XPath)
API(DOM+SAX)
链接(XLinker+XPointer)
构成
XML文档声明
<?xml version="1.0" encoding = "utf-8"? standalone="yes">
文档声明有以下两个规范。
1.声明放在XML文档的开头。
2.声明一般包括三部分:
version
版本,目前常用XML1.0。
encoding
字符编码,默认为UTF-8。
standalone
文档定义是否在同一个文件内。
*处理指令:
以“<?”开始,以“?>”结束,用于被解析器解析。
文档类型声明
DOCTYPE,紧随XML声明,包含实体声明等DTD内容。
<!DOCTYPE 根元素 [ <!ENTITY 实体名 "实体内容"> ]>
实体
相当于全局变量的作用,置于文档类型声明中。
实体定义格式为:
<!ENTITY 实体名 实体内容>
预定义实体:
<:<
>:>
&:&
":"
':'
引用实体:
&实体名;,例:
<!DOCTYPE currencyType [ <!ENTITY dollar "$"> ]> <currencyType >$</currencyType >
根元素
每个XML文档的根元素有且仅有一个。
文本内容
PCDATA(Parsed Character Data)。文本内容中的特殊字符,需要用实体代替。
<![PCDATA[content]]>
其中的标签字符将被解析器当做元素处理,实体将展开。
纯文本内容
CDATA(Character Data),全部当做文本处理,其中的任何字符都不被解析器解析。
<![CDATA[content]]>
注释
<!--注释内容-->
注释不能嵌套,不能出现在标记内部。
属性
属性值用引号包住,不能包含特殊符号(需转义)。
良构
一个良构的XML文档能够被解析器正确解析。良构需要满足以下两方面的要求。
结构规范
1.必须有声明语句。
2.必须有且仅有一个根元素。
3.属性值用引号包含。
4.标记成对,无交叉嵌套,空标记正确关闭。
元素规范
1.不能以数字和下划线开头。
2.不能以任何大小写xml开头。
3.不能包含空格。
4.不能包含冒号。
如下是一个良构的XML。
<?xml version="1.0" encoding = "utf-8" standalone="yes"?> <person> <job> <name>CEO</name> <type>IT</type> <money>$10</money> </job> <family> <wife sex="female"></wife> <house area="200" money="$3000000"></house> <cars> <car brand="benz"></car> <car brand="landroller"></car> </cars> </family> </person>
DTD
Document Type Definition,一套用于校验、规范XML的规,能够指示XML文档的良构。
DTD不能跨平台,Schema弥补了这一缺陷。
定义位置
1.XML文档内部
<!DOCTYPE person[...]>
2.引用外部DTD
<!DOCTYPE person SYSTEM "person_dtd.dtd">
3.引用公共DTD
<!DOCTYPE person PUBLIC "url">
元素规范
用于规范元素的结构、内容,定义在文档类型声明中,其格式为:
<!ELEMENT 元素名 (规范内容)>
例:
<?xml version="1.0"?> <!DOCTYPE books[ <!ELEMENT books (book+)> <!ELEMENT book (price?,name?)> <!ELEMENT price (#PCDATA)> <!ELEMENT name (#PCDATA)> ]>
上例中的规范意义如下:
#PCDATA:元素内容可为任意字符串,但不再包含子元素。
EMPTY:元素必须为空。
ANY:元素内容可包含任意在DTD中定义的元素。
其中,符号的意义为:
?:出现且仅出现一次。
+:出现不少于一次。
*:不出现或出现任意次。
():给子元素分组。
|:选择一个子元素。
,:指定元素出现的顺序。
属性规范
用于规范属性的值,格式如下:
<!ATTLIST 元素 属性名1 属性类型/属性值 约束 属性名2 属性类型/属性值 约束 ...... >
约束包括:
#REQUIRED:必填属性。
#IMPLIED:属性可有可无。
#FIXED:属性值必须为属性类型指定的内容。
"默认值":为属性提供默认值。
例:
<!ATTLIST person name CDATA #REQUIRED age CDATA #REQUIRED sex (male|female) #REQUIRED occupation CDATA #IMPLIED nationality "CHINESE" #FIXED salary CDATA "0.0" >
实例
如下的XML文档(books.xml)将被下文使用。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE books [
<!ELEMENT books (category+)>
<!ELEMENT category (book+)>
<!ELEMENT book (title?,author?)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT author (#PCDATA)>
<!ATTLIST category
id CDATA #REQUIRED
name CDATA #REQUIRED>
<!ATTLIST book
id CDATA #REQUIRED
price CDATA "0.0">
]>
<books>
<category id="01" name="Novel">
<book id="0101" price="100.5">
<title>War And Peace</title>
<author>Tolstoy</author>
</book>
<book id="0102" price="101">
<title>Gone With The Wind</title>
<author>Margaret</author>
</book>
<book id="0103" price="101.5">
<title>The Old Man And The Sea</title>
<author>Hemingway</author>
</book>
</category>
<category id="02" name="Economics">
<book id="0201" price="50">
<title>The Currency Wars</title>
<author>Song</author>
</book>
<book id="0202" price="60">
<title>Principle Of Economics</title>
<author>Mankiw</author>
</book>
</category>
<category id="03" name="Psychology">
<book id="0301" price="40">
<title>Psychology And Life</title>
<author>Gerrig</author>
</book>
<book id="0302" price="45">
<title>Social Psychology</title>
<author>Miles</author>
</book>
</category>
</books>
Java解析XML
DOM4J
一次性读取整个XML文档,可以访问任意节点,适用于小型XML文档。JAR
dom4j-1.6.1.jar
API
SAXReader类
read
Document doc = new SAXReader().read(inputStream);
由SAXReader对象读取指定的XML文件,获取Document类对象。
Document类
selectNodes / selectObject
List<Element> selectNodes(nodePath);
读取指定路径的元素,包括其所有子元素,返回一个树形结构的元素List。
两者虽然名字不同,但在我的使用过程中并未发现任何不同。
元素路径nodePath包含三类定义:
1.绝对路径:如"a/b/c",指向a->b->c元素。
2.查找路径:"//c",获取所有的c元素。
3.属性值过滤:如"//c[@id!=1]",获取所有id属性值不为1的c元素。
Element类
getName
String getName();
获取元素名。
attributeValue
String attributeValue(attributeName);
获取指定名称的属性值。
element
Element element(childNodeName);
获取指定名称的子元素对象。
elements
List<Element> elements();
获取所有子元素。
getText
String getText();
获取元素内的文本内容。
getPath
String getPath();
获取元素路径。
getParent
Element getParent();
获取父元素对象。
实例
如下是一个利用DOM4J对上文中的books.xml进行解析的实例。
public class TestDom4j { public static void main(String[] args) { SAXReader reader = new SAXReader(); try { Document doc = reader.read(new FileInputStream("xml/books.xml")); List<Element> categories = (List<Element>) doc.selectNodes("//category"); for (Element element : categories) { System.out.println(element.getName()+element.attributeValue("id")+":"+element.attributeValue("name")); List<Element> books = element.elements(); for (Element element2 : books) { Element bookTitle = element2.element("title"); Element bookAuthor = element2.element("author"); String bookPrice = element2.attributeValue("price"); System.out.println("\t<<"+bookTitle.getText()+">> by "+bookAuthor.getText()+" of $"+bookPrice); } } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (DocumentException e) { e.printStackTrace(); } } }
SAX
SAX(Simple API for XML),适用于大文件,从上至下解析。解析时多次读取,由事件驱动。
JAR
jaxen-1.1-beta-7.jar
限于篇幅,这里仅放出示例代码。
/** * SAX事件驱动解析方式 * @author hsdsmljj * */ public class SAX_XML { /** * @param args */ public static void main(String[] args) { try { //取得一个解析工厂实例 SAXParserFactory factory=SAXParserFactory.newInstance(); //得到解析器 SAXParser parse=factory.newSAXParser(); //开始解析[1:文件 2:事件] parse.parse("xml/books.xml", new ParseHandler()); } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } /** * 定义一个默认事件驱动 * @author hsdsmljj * */ class ParseHandler extends DefaultHandler{ static int i=0; List<Book> books=new ArrayList<Book>(); Book book; String bookAuthor=""; String bookPrice=""; String bookTitle=""; String qName=""; @Override public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException { //如果在book元素的开始时 if(qName.equals("book")){ bookAuthor=attrs.getValue(0); bookPrice=attrs.getValue(1); book=new Book(); book.setName(bookAuthor); book.setPrice(bookPrice); } //记录当前在解析哪个元素 this.qName=qName; } @Override public void characters(char[] ch, int start, int length) throws SAXException { if(qName.equals("title") && book.getTitle()==null){ System.out.println("============"+qName); book.setTitle(String.valueOf(ch, start, length)); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { System.out.println("------"+this.bookTitle); //当book节点结束时就进行扫尾处理 if(qName.equals("book")){ books.add(book); this.bookAuthor=""; this.bookPrice=""; this.bookTitle=""; this.qName=""; book=null; } } //文档结束 @Override public void endDocument() throws SAXException { for (Book book : books) { //自动调用toString方法 System.out.println(book); } } }
JS解析XML
由于XML与HTML同根同源,因此解析XML时与解析HTML并无太大区别,诸如getElementById、getElementsByTagName等均能直接使用于XML元素节点上。function loadxml(xmlFile){
var xmlDoc;
if(window.ActiveXObject){
//创建组件对象
xmlDoc=new ActiveXObject('Microsoft.XMLDOM');
//是否异步加载xml文件 如果为ture,程序不论xml文件是否全部载入就开始运行下面程序,所以如果接下来就操作xml文件可能出错
xmlDoc.async = false;
//加载xml
xmlDoc.load(xmlFile);
}else if(document.implementation && document.implementation.createDocument) {
xmlDoc = document.implementation.createDocument('', '', null); xmlDoc.load(xmlFile);
}else{
return null;
}
return xmlDoc;
}