xml——简述、约束、解析
一、 Xml简介
1 概述.
a) Xml是可扩展性的标记语言,设计被用来格式化存储,传递数据,而不是像HTML一样显示数据。
b) Xml的标签没有预定义的,都需要自己定义
c) Xml必须有且只有一个根标签,且标签必须要正确的嵌套,必须闭合,标签是大小写敏感的。
d) Xml中的元素必须有关闭标签,但是Xml的声明没有关闭标签因为声明不属于xml本身的组成部分
2. Xml元素
a) 概述:xml元素是从开始标签到结束标签的部分,一个元素内可以包括其他元素,属性,文本。
b) 命名规则:不能以数字、标点符号、xml、XML、Xml等开始;不能包含空格;可以包含字母,数字,其他字符;尽量避免“-”减号,“:”冒号,”.”句号。
c) CDATA:CDATA中的文本不会被解析器解析,语法:<![CDATA[不希望被解析的文本内容]]>
3. Xml属性
a) 属性必须用引号包围,尽量避免使用属性(属性不能包含多个值,属性不能包含数据结构,属性不容易扩展),而用元素代替。当仅仅需要数据作为标识符,而不是数据的一部分时,建议使用属性。
二、 DTD约束
1. 概述:用来定义合法的xml文档构建模型
2. DTD的引用
a) Xml源文件内部dtd的引用:<!DOCTYPE root-element[ elements-declarations]>
b) 外部DTD文件的引用:<! DOCTYPE root-element SYSTEM “file-name”>
3. DTD元素
a) 元素的声明:<! ELEMENT emlemtName(element-content)>
b) 元素约束:
约束 |
关键字 |
格式 |
结果/解释 |
空元素 |
EMPTY |
<! ELEMENT br EMPTY> |
<br/> |
带任何内容的元素 |
ANY |
<! ELEMNET note ANY> |
该元素可以包含任何元素数据 |
子元素 |
(child1,child2) |
<! ELEMNET note (child1,child2,,,)> |
该元素必须包含这些子元素,且子元素由逗号分隔开的顺序进行声明 |
至少出现一次 |
+ |
<! ELEMNET note (child1+)> |
Child1子元素必须至少在note元素中出现一次 |
出现0次或多次 |
* |
<! ELEMNET note (child1*)> |
Child1子元素可以在note中出现0次或多次 |
0次或一次 |
? |
<! ELEMNET note (child1?)> |
Child1子元素可以在note中出现0次或一次 |
或 |
| |
<! ELEMNET note (child1|child2)> |
Note中出现一次child1或child2 |
4. DTD属性约束
i. 属性声明语法:<!ATTLIST element-name attribute-name attribute-typeattribute-value>
ii. 属性类型:
iii. 属性值约束:
5. DTD实体
a) 实体概述:用于定义引用普通文本或特殊字符串的快捷方式的变量
b) 实体的定义:<!ENTITY entity-name "entity-value">
c) 外部实体声明:<!ENTITY entity-name SYSTEM "URI/URL">
d) 实体的引用:&实体名;
三、 Xml schema
1. 概述:由xml文件编写的描述了xml的文档的结构,是dtd的替代。<xsd:schema>是每个xml schema的根节点
2. 元素
a) 简易元素
i. 概述:仅包含文本的元素,不会包含其他元素或属性
ii. 定义:<xs:element name=”xxx” type=”yyy” [default=”aaa” fixed=”bbb”]> 定义简易元素的名称,类型,默认值,固定值
iii. 常用元素类型:xs:string 、xs:decimal、xs:integer、xs:boolean、xs:date、xs:time
b) 复合元素
i. 概述:包含其他元素或属性或文本,<xs:complexType>
ii. 复合元素之间的扩展与引用:<xs:extension base="personinfo">,扩展引用personinfo这个元素
iii. 常用标签
标签 |
解释 |
<xs:sequence> |
该标签下的子元素必须按顺序出现 |
<xs:all> |
子元素可以按任意顺序出现,且有且仅出现一次 |
<xs:simpleContent> |
仅包含文本或属性的复合元素,必须在该标签下定义扩展或限定 |
<xs:choice> |
选择指示器:出现其中任意一个子元素 |
<xs:any/> |
可以使用未被规定的元素扩展xml文档 |
<xs:anyAttribute/> |
可以使未被规定的属性来扩展xml元素 |
<xs:element name="navn" substitutionGroup="name"/> |
声明navn元素可替换name元素 |
3. 属性
a) 概述:属性本身是简易类型
b) 定义:<xs:attribute name="xxx" type="yyy" [default=”aaa” fixed=”bbb” use=”required”] /> 定义属性名称,类型,默认值,固定值,是否必须
4. 限定(restriction)
a) 概述:为元素或属性定义可接受的值
b) 语法:
<xs:restriction base=”对哪种数据类型做限定”> <xs:限定类型 value=”限定值”/> </xs:restriction> |
c) 限定类型
四、 Xml解析
1. DOM解析(documentobject modal)
a) 概述:官方提供的平台无关的解析方式,操作读取xml之前需要加载分析整个xml文档将其转换为对象模型的集合(dom树),所以是比较耗内存的对机器性能要求比较高。但它提供随机访问的方式,使得开发更灵活
b) 实现
public class DOMTest { public static void main(String[] args) { //创建一个DocumentBuilderFactory的对象 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); //创建一个DocumentBuilder的对象 try { //创建DocumentBuilder对象 DocumentBuilder db = dbf.newDocumentBuilder(); //通过DocumentBuilder对象的parser方法加载books.xml文件到当前项目下 Document document = db.parse("books.xml"); //获取所有book节点的集合 NodeList bookList = document.getElementsByTagName("book"); //通过nodelist的getLength()方法可以获取bookList的长度 System.out.println("一共有" + bookList.getLength() + "本书"); //遍历每一个book节点 for (int i = 0; i < bookList.getLength(); i++) { System.out.println("=================下面开始遍历第" + (i + 1) + "本书的内容================="); //通过 item(i)方法获取一个book节点,nodelist的索引值从0开始 Node book = bookList.item(i); //获取book节点的所有属性集合 NamedNodeMap attrs = book.getAttributes(); System.out.println("第 " + (i + 1) + "本书共有" + attrs.getLength() + "个属性"); //遍历book的属性 for (int j = 0; j < attrs.getLength(); j++) { //通过item(index)方法获取book节点的某一个属性 Node attr = attrs.item(j); //获取属性名 System.out.print("属性名:" + attr.getNodeName()); //获取属性值 System.out.println("--属性值" + attr.getNodeValue()); } //解析book节点的子节点 NodeList childNodes = book.getChildNodes(); //遍历childNodes获取每个节点的节点名和节点值 System.out.println("第" + (i+1) + "本书共有" + childNodes.getLength() + "个子节点"); for (int k = 0; k < childNodes.getLength(); k++) { //区分出text类型的node以及element类型的node if (childNodes.item(k).getNodeType() == Node.ELEMENT_NODE) { //获取了element类型节点的节点名 System.out.print("第" + (k + 1) + "个节点的节点名:" + childNodes.item(k).getNodeName()); //获取了element类型节点的节点值 System.out.println("--节点值是:" + childNodes.item(k).getFirstChild().getNodeValue()); //System.out.println("--节点值是:" + childNodes.item(k).getTextContent()); } } System.out.println("======================结束遍历第" + (i + 1) + "本书的内容================="); } } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } |
2. JDOM解析
a) 概述:扩展方法,只适用于java平台,简化了与xml的交互,所以比dom方式快些。使用具体类而不是接口
b) 实现:
public class JDOMTest { private static ArrayList<Book> booksList = new ArrayList<Book>(); public static void main(String[] args) { // 1.创建一个SAXBuilder的对象 SAXBuilder saxBuilder = new SAXBuilder(); InputStream in; try { // 2.创建一个输入流,将xml文件加载到输入流中 in = new FileInputStream("src/res/books.xml"); InputStreamReader isr = new InputStreamReader(in, "UTF-8"); // 3.通过saxBuilder的build方法,将输入流加载到saxBuilder中 Document document = saxBuilder.build(isr); // 4.通过document对象获取xml文件的根节点 Element rootElement = document.getRootElement(); // 5.获取根节点下的子节点的List集合 List<Element> bookList = rootElement.getChildren(); // 继续进行解析 for (Element book : bookList) { Book bookEntity = new Book(); System.out.println("======开始解析第" + (bookList.indexOf(book) + 1) + "书======"); // 解析book的属性集合 List<Attribute> attrList = book.getAttributes(); // //知道节点下属性名称时,获取节点值 // book.getAttributeValue("id"); // 遍历attrList(针对不清楚book节点下属性的名字及数量) for (Attribute attr : attrList) { // 获取属性名 String attrName = attr.getName(); // 获取属性值 String attrValue = attr.getValue(); System.out.println("属性名:" + attrName + "----属性值:"+ attrValue); if (attrName.equals("id")) { bookEntity.setId(attrValue); } } // 对book节点的子节点的节点名以及节点值的遍历 List<Element> bookChilds = book.getChildren(); for (Element child : bookChilds) { System.out.println("节点名:" + child.getName() + "----节点值:"+ child.getValue()); if (child.getName().equals("name")) { bookEntity.setName(child.getValue()); } else if (child.getName().equals("author")) { bookEntity.setAuthor(child.getValue()); } else if (child.getName().equals("year")) { bookEntity.setYear(child.getValue()); } else if (child.getName().equals("price")) { bookEntity.setPrice(child.getValue()); } else if (child.getName().equals("language")) { bookEntity.setLanguage(child.getValue()); } } System.out.println("======结束解析第" + (bookList.indexOf(book) + 1) + "书======"); booksList.add(bookEntity); bookEntity = null; System.out.println(booksList.size()); System.out.println(booksList.get(0).getId()); System.out.println(booksList.get(0).getName());
} } catch (FileNotFoundException e) { e.printStackTrace(); } catch (JDOMException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } |
3. SAX解析(simpleAPIs for xml)
a) 概述:官方提供的平台无关的解析方式,sax解析方式有时不必解析整个文档,采用事件驱动模型,所以内存消耗相对dom较少,顺序的访问模式,所以很难同时访问xml中的多处不同数据
b) 实现:
public class SAXTest{ public static void main(String[] args) { //获得sax解析器工厂 SAXParserFactory factory = SAXParserFactory.newInstance(); try { //通过sax解析器工厂获取sax SAXParser parser = factory.newSAXParser(); //创建sax解析器的处理器,指定对xml文档的处理,该处理器继承DefaultHandler,实现自己的处理 SAXParserHandler handler = new SAXParserHandler(); //解析xml文件 parser.parse("books.xml", handler); System.out.println("~!~!~!共有" + handler.getBookList().size() + "本书"); for (Book book : handler.getBookList()) { System.out.println(book.getId()); System.out.println(book.getName()); System.out.println(book.getAuthor()); System.out.println(book.getYear()); System.out.println(book.getPrice()); System.out.println(book.getLanguage()); System.out.println("----finish----"); } } catch (ParserConfigurationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SAXException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } packagecom.xml.test; 自行脑补book |
4. DOM4J解析
a) 概述:性能最好,常用方式
b) 实现
File f = new File("data_10k.xml"); SAXReader reader = new SAXReader(); Document doc = reader.read(f); Element root = doc.getRootElement(); |