XML那点事儿

XML那点事儿

一. XML简介

        1.概念

2.XML文档结构

        3. DTD和schema

        4. 显示XML

        5. XSL

        6. XPATH

二. XML处理模型

1.XML文档处理模型

2.SAX和DOM比较

3.小结

三. SAX

四. DOM

五. Dom4J

 

一. XML简介

      1. 概念

      XML(Extensible Markup Language,可扩展标记语言)是一个用于构造其他语言的元语言。XML描述了创造这些语言的规则,每种语言都互不相同,但都使用标签来标记内容。XML定义的语言的一个例子是XHTML,相当于是XML的词汇。目前,XML已经成为一种通用的数据交换格式,是一种用于描述结构化信息的技术,它具有平台无关性,语言无关性,系统无关性,为数据交换带来了极大的便利。

      2. XML文档结构

 

XML那点事儿_第1张图片

1.1 XML文档结构图

 

 

      3. DTD和schema

      DTD和schema包含了用于解释文档是如何构成的规则,通过DTD或schema可以定义XML词汇。这些规则定义了每个元素的子元素和属性。可以根据DTD或schema来验证一个文档是否是合法的。由于DTD和schema内容比较多,这里不做详细介绍。

      (1) DTD Document Type Defination

      DTD描述的是文档的结构,它指明一个元素可以出现多少次、是否可选以及它是否包含属性等,这样就定义了一个文档的类型。可以直接将DTD写入一个XML文件,或DTD为一个独立的文件,然后在XML文件中通过文档声明对其引用。

      (2) schema

      schema也用于定义XML文档的结构,但它的功能更强,结构也更复杂。schema也是XML词汇的一种,完全符合XML的规则。

      4. 显示XML

      可以通过CSS或XSL将XML的内容可视化地展现出来,这样就可以显示在Web浏览器或者打印出来。CSS可以按照应用于XHTML的方式应用于XML,但是XML中引入CSS的方法只有一种:就是通过处理指令将样式表关联到XML文档中,

      <?xml-stylesheet type="text/css" href="style.css"?>

      CSS有一个缺点就是它是按照元素在XML文档中出现的顺序来呈现他们,不能够对它们进行排序,过滤。CSS大家比较熟悉,这里不做深入探讨。下面将介绍一下XSL,另一种功能更强大的显示XML的技术。

      5. XSL

      XSL(Extensible Sheet Language, 可扩展样式表语言)分为两 部分:XSLT(XSL转换)和XSL-FO(XSL格式对象)。XSLT将XML源文档转换为另一个XML文档(结果树)。XSL-FO为结果树添加格式。因为XHTML是XML的一个词汇(XML定义的语言),所以XSLT可以将XML转换为XHTML,并XHTML添加样式表,然后显示在Web浏览器中,从而实现XML的显示。

XML那点事儿_第2张图片

      下面的例子,将实现XML文档转换为XHTML然后在Web浏览器中显示

      XML文档为:DVD.xml

      <?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet type="text/xsl" href="XSLDemo.xsl"?><!--引入XSL样式表--> <library> <DVD id="1"> <title>Breakfast at Tiffany's</title> <format>Movie</format> <genre>Classic</genre> </DVD> <DVD id="2"> <title>Contact</title> <format>Movie</format> <genre>Science fiction</genre> </DVD> <DVD id="3"> <title>Little Britain</title> <format>TV Series</format> <genre>Comedy</genre> </DVD> </library>

      XSL样式表

      <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="html" version="4.0"/> <!--输出的目标文档为html--> <xsl:template match="/"><!--匹配根元素--> <html> <head> <title>DVD Library Listing</title> </head> <body> <table width="40%" border="1"> <tr> <th>Title</th> <th>Format</th> <th>Genre</th> </tr> <xsl:for-each select="/library/DVD"><!--遍历每个DVD元素,通过XPATH选择节点--> <xsl:sort select="genre"/><!--按照genre列排序--> <tr> <td><xsl:value-of select="title"/></td> <td><xsl:value-of select="format"/></td> <td><xsl:value-of select="genre"/></td> </tr> </xsl:for-each> </table> </body> </html> </xsl:template> </xsl:stylesheet> 

      用浏览器打开XML文件会看到使用样式后的效果。

      6. XPATH

      XPATH用于定位XML文档的特定部分,可以通过XPATH表达式得到一个单独的节点,一组节点等等,从而避免遍历DOM树节点进行查找。XPATH将XML文档看作是由节点构成的层次树,每棵树包括元素节点、属性节点、文本节点、处理指令、注释和命名空间,通过相应的路径来定位相应的节点。根节点是XML文档树的起始点,一个XML文档就是根节点,"/"代表根节点。下面以DVD.xml为例,接单介绍一下XPATH的使用。

      (1) /library/DVD

           定位library的所有DVD子元素,得到一组节点

      (2) /library/DVD[2]

           定位library的第2个DVD子元素,得到一个节点

      (3) /library/DVD/@id

           得到所有DVD的id属性

      (4) /library/DVD[2]/@id

           得到第2个DVD的id属性

      (5) /library/DVD[genre='Comedy'] 

           过滤条件,定位genre等于Comedy的DVD

      (6) count(/library/DVD)

           得到DVD的数量

      JDK5.0中增加了API来处理XPATH,下面例子是通过XPATH来查询DVD.xml

      /** * */ package com.killer.xml; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; /** * @author chosen0ne * * 2010-6-10 下午03:52:29 */ public class XPathTest { /** * @param args * @throws ParserConfigurationException * @throws IOException * @throws SAXException * @throws XPathExpressionException */ public static void main(String[] args) throws ParserConfigurationException, IOException, XPathExpressionException { // TODO Auto-generated method stub String file="xml/XSLDemo.xml"; XPathFactory factory=XPathFactory.newInstance(); XPath path=factory.newXPath(); InputSource source=new InputSource(new FileInputStream(file)); String query="/library/DVD"; NodeList nodeList=(NodeList) path.evaluate(query, source,XPathConstants.NODESET); System.out.println(query+" 结果节点的个数:"+nodeList.getLength()); for(int i=0;i<nodeList.getLength();i++){ Node n=nodeList.item(i); Node attrNode=n.getAttributes().getNamedItem("id"); System.out.println(n.getNodeName()+" "+attrNode.getNodeName()+" "+attrNode.getNodeValue()); } source=new InputSource(new FileInputStream(file));//需要重新读取XML文件,否则出现reader error query="/library/DVD[2]"; Node node=(Node) path.evaluate(query, source, XPathConstants.NODE); System.out.println(query+": "+node.getNodeName()+" "+node.getAttributes().getNamedItem("id").getNodeValue()); source=new InputSource(new FileInputStream(file)); query="/library/DVD[genre='Comedy']"; node=(Node) path.evaluate(query, source, XPathConstants.NODE); System.out.println(query+": "+node.getNodeName()+" "+node.getAttributes().getNamedItem("id").getNodeValue()); source=new InputSource(new FileInputStream(file)); query="/library/DVD/@id"; nodeList=(NodeList) path.evaluate(query, source, XPathConstants.NODESET); System.out.println(query+": 结果节点个数"+nodeList.getLength()); for(int i=0;i<nodeList.getLength();i++){ Node n=nodeList.item(i); System.out.println(n.getNodeName()+" "+n.getNodeValue()); } source=new InputSource(new FileInputStream(file)); query="count(/library/DVD)"; double count=(Double)path.evaluate(query, source, XPathConstants.NUMBER); System.out.println(query+": "+count); } }  

 

二. XML处理模型

      1. XML文档处理模型

      应用程序需要通过XML处理程序从XML文档中提取信息。XML处理程序通常被称为XML解析器。

      XML有两种处理模式:基于树和基于事件。基于树的解析器通常称为DOM(Document Object Model,文档对象模型)解析器,而基于事件的解析器通常称为SAX(Simple API for XML,XML简单应用编程接口)解析器。DOM是W3C推荐的标准,允许通过编程语言或脚本语言(JavaScript)访问这些元素以及它们的值。SAX是以一串事件的形式展现XML文档,必须为每个事件(比如,开始或是结束某个元素)编写 处理程序,当事件触发处理程序会产生相应的结果,由于SAX是以事件处理机制为基础的,所以在有良好事件处理机制的语言中很实用。

      2. SAX和DOM比较

      (1). DOM提供了对整个XML文档的完整的读写访问,并且可以通过遍历文档树对文档内的节点进行访问。基于DOM的解析会将整个XML读入内存,在内存中构造整棵XML树,所以当遇到较大XML文档时,DOM解析会变慢。

      (2). SAX是串行操作的,一个节点被处理后就被丢弃了,并且不会再被处理。整个文档不是一次性读入内存,从而避免了较大XML文档引起的处理问题。如果只是对某些节点感兴趣,而不关心其上下文,这种情况应该用SAX(例如,网络爬虫只关心<a>标签所以适合用SAX解析)。但是,SAX模型不会记录已经丢弃的节点的信息,所以必须由开发人员自己来维护XML文档中的可供后续使用的信息。从而SAX使用起来比较繁琐。

      3. 小结

      DOM提供了对XML的读写,XPATH查询,文档验证等功能,SAX只是提供简单的解析功能。SAX和DOM属于操作XML文档较低层的类库,目前已有很多类库实现了这两种方式,并对其进行封装,使用户用起来更加方便。比如Dom4J,JDom等。下文将对Dom4J进行介绍。

 

三. SAX

      SAX解析器在解析XML文件时,如果遇到XML构件(例如:标签)就会触发相应的事件,但它不会以任何方式存储文档,由事件处理程序决定是否建立数据结构存储信息。实际上,DOM解析器是建立在SAX解析器的基础之上的,在读入XML信息时接受相应的时间然后建立DOM树。

      在使用SAX解析器时,需要建立一个事件处理器来处理不同事件。ContentHandler接口定义了多个回调方法来处理相应的事件,其中比较重要的方法有:

       startDocument()  在文档开始时调用

       endDocument()  在文档结束时调用

       startElement(String uri, String localName, String qName, Attributes attributes)  在元素开始时调用

       endElement(String uri, String localName, String qName)  在元素结束时调用

       characters(char[] ch, int start, int length)  每当遇到字符数据时调用

      处理器必须覆盖这些方法,完成在解析文件时要执行的动作。

      这里给出示例程序,打印一个XHTML文件中的所有<a href=...>元素:

      package com.killer.xml; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; /** * @author chosen0ne * * 2010-6-8 下午04:59:37 */ public class SAXTest { /** * 打印一个XHTML文件中的所有超链接 * @param filePath * @throws SAXException * @throws ParserConfigurationException * @throws IOException * @throws FileNotFoundException */ public static void printATag(String filePath) throws ParserConfigurationException, SAXException, FileNotFoundException, IOException { SAXParserFactory factory=SAXParserFactory.newInstance(); factory.setNamespaceAware(true);//打开命名空间处理特性 SAXParser parser=factory.newSAXParser(); XMLReader reader=parser.getXMLReader(); reader.setContentHandler(new DefaultHandler(){ /** * uri 命名空间 * localName 本地名 * qName alias:localName的限定名,随时可用 * 如果命名空间处理特性打开,则uri和localName可用,否则都为空 * SAXParserFactory.setNamespaceAware(true)将命名空间处理特性打开 */ @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { // TODO Auto-generated method stub super.startElement(uri, localName, qName, attributes); if(localName.equalsIgnoreCase("a")&&attributes!=null){ String href=attributes.getValue("href"); if(href!=null) System.out.println(href); } } }); reader.parse(new InputSource(new FileInputStream(filePath))); } /** * @param args * @throws SAXException * @throws ParserConfigurationException * @throws IOException * @throws FileNotFoundException */ public static void main(String[] args) throws ParserConfigurationException, SAXException, FileNotFoundException, IOException { // TODO Auto-generated method stub printATag("xml//XHTMLDemo.xml"); } }  

 

四. DOM

      DOM(Document Object Model, 文档对象模型)解析器将读入的XML文档转化为树结构。DOM解析器的接口已经被W3C标准化,org.w3c.dom包中包含了所有的接口,例如:Document和Element等。Document对象是文档树在内存中的表现,可以通过它访问该树的节点,它由实现Node接口及其多个子接口的对象构成。接口Node的层次结构如下:

      

 

      下面例子是通过DOM操作DVD.xml显示详细信息: 

      /** * */ package com.killer.xml; import java.io.File; import java.io.IOException; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; 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; import org.xml.sax.SAXException; /** * @author chosen0ne * * 2010-6-9 下午08:34:24 */ public class DomTest { /** * @param args * @throws ParserConfigurationException * @throws IOException * @throws SAXException */ public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException { // TODO Auto-generated method stub DocumentBuilder builder=DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document doc=builder.parse(new File("xml/XSLDemo.xml")); Element root=doc.getDocumentElement(); NodeList children=root.getChildNodes(); for(int i=0;i<children.getLength();i++){ Node n=children.item(i); if(n instanceof Element){ NamedNodeMap attr=n.getAttributes(); System.out.println("DVD "+attr.getNamedItem("id").getNodeValue()); NodeList dvdItems=n.getChildNodes(); for(int j=0;j<dvdItems.getLength();j++){ Node item=dvdItems.item(j); if(item instanceof Element){ System.out.println(item.getNodeName()+":"+item.getTextContent()); } } } } } }  

五. Dom4J

      Dom4J对SAX和DOM进行了封装,使其用起来更加方便。

      /** * */ package com.killer.xml; import java.io.File; import java.util.Iterator; import java.util.List; import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.Node; import org.dom4j.io.SAXReader; /** * @author chosen0ne * * 2010-6-8 下午04:11:46 */ public class Dom4JTest { /** * @param args */ @SuppressWarnings("unchecked") public static void main(String[] args) { // TODO Auto-generated method stub String path="xml//XSLDemo.xml"; SAXReader reader=new SAXReader(); try { Document doc=reader.read(new File(path)); Element rootElement=doc.getRootElement(); System.out.println(rootElement.getName()+"--"+rootElement.getTextTrim()); visitElement(rootElement); //以xpath方式访问节点 System.out.println("以xpath形式访问节点"); List<Node> nodes=doc.selectNodes("/library/DVD/title"); for(Node n: nodes){ System.out.println(n.getName()+":"+n.getText()+""); } } catch (DocumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } } @SuppressWarnings("unchecked") public static void visitAttribute(Element el) { Iterator<Attribute> iterator=el.attributeIterator(); while(iterator.hasNext()){ Attribute attribute=iterator.next(); System.out.println(attribute.getName()+"--"+attribute.getText()); } } @SuppressWarnings("unchecked") public static void visitElement(Element el) { Iterator<Element> iterator=el.elementIterator(); while(iterator.hasNext()){ Element element=iterator.next(); System.out.println("Element:"); System.out.println(element.getName()+"-"+element.getTextTrim()); System.out.println("Attribute:"); visitAttribute(element); visitElement(element); } } }  

 

你可能感兴趣的:(xml,XHTML,query,文档,XSL,attributes)