Bootstrap

DOM解析轻松入门(三)--.DOM Level 2 Tranversal 和Range

 /*java and xml 3nd学习笔记
DOM解析轻松入门(三)--DOM Level2 Modules
author:shine
*/
呵呵,既然题目是DOM Module,那么就先来大概看看DOM Level和Module(有个印象就行,后面会举例讲解几个常用的Moduel)
1.DOM有三个级别(Level):简单来说就是DOM规范不断完善的层次。(括号中的是Module的名字)
1)Level 1:“details the functionality and navigation of content within a document”意思就是说:提供了在document中一组基础的核心的节点,和

文档内容的导航的细节。
2)Level 2:在Level1的基础上,增加了几个针对特殊内容的DOM模型(Module),如:
a.DOM Level 2 Core (XML):扩展Level1的规范,处理了基本的DOM结构,如:ELement,Attr,Document等
b.DOM Level 2 View (View):基本上浏览器不支持View Module(略)
c.DOM Level 2 Event (Events):定义了一组标准化的HTML页面交互浏览器事件和XML文档节点树的事件。
d.DOM Level 2 CSS (CSS):为CSS提供了一个基于DOM Core 和DOM View规范的模型。
e.DOM Level 2 Tranversal and Range (Tranversal/Range):定义了一组用于遍历节点和处理XML或HTML文档范围的接口。
f.DOM Level 2 HTML (HTML):扩展DOM提供了把HTML文档结构作为XML处理的接口。
3)Level 3:在Level2的基础上,增加了两个新的Module
a.DOM Level 3 Core (XML):提供了bootstrapping和InfoSet 机制(其中bookstrapping 后面有提,infoSet就是指在Document接口中加入了

getXmlEncoding();getXmlStandalone();getXmlVersion();等控制XML Information的方法。)
b.DOM Level 3 Load & Save (LS):(顾名思义)
c.DOM Level 3 Validation (Validation):定义了根据DTD或Schema验证的接口。

2.现在的浏览器中,对DOM Level 的支持都不完全,一般支持Level1 Moduel,部分Level2 Moduel,部分Level3 Moduel,遗憾的是IE是这些浏览器中对

DOM Level支持最差的一个,它只是支持Level1 Moduel,和部分Level2 Moduel,,同样我们在解析XML使用的XML Parser也没有全部实现上面所有的

Level,所以在使用XML Parser时,是不是该检验(Verify)一下它到底支持哪几个Module呢?今天第一个例子就是干这个的。
package test;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.DOMImplementation;
public class DOMModuleChecker {
 private static Map module2Map; //DOM Level2 Level
 private static Map module3Map;  //DOM Level3 Level
 
 //把DOM Module的名字放入相应Level的Map中
 private static void loadModule() {
  module2Map = new HashMap();
  module3Map = new HashMap();

     // DOM Level 2
     module2Map.put("XML", "DOM Level 2 Core");
     module2Map.put("Views", "DOM Level 2 Views");
     module2Map.put("Events", "DOM Level 2 Events");
     module2Map.put("CSS", "DOM Level 2 CSS");
     module2Map.put("Traversal", "DOM Level 2 Traversal");
     module2Map.put("Range", "DOM Level 2 Range");
     module2Map.put("HTML", "DOM Level 2 HTML");

     // DOM Level 3
     module3Map.put("XML", "DOM Level 3 Core");
     module3Map.put("LS", "DOM Level 3 Load & Save");
     module3Map.put("Validation", "DOM Level 3 Validation");
 }
 
 //检查实现DOMImplementation接口的类实现了哪几个Module,第二个参数是此类的全名
 public void checkModule(DOMImplementation domImpl,String vendorImplementationClass) {
  System.out.println("For the DOM implementation class " +vendorImplementationClass + ":");
     //对Level2支持Module的检验
     Iterator iteratorLevel2 = module2Map.keySet().iterator();
     while(iteratorLevel2.hasNext()) {
      String name = (String)iteratorLevel2.next();
      String description = (String)module2Map.get(name);
         System.out.print("The " + description + " module is ");
         if(domImpl.hasFeature(name, "2.0")) {
          System.out.println("supported");
         }
         else {
          System.out.println("not supported");
         }
     }
    
     //对Level3支持Module的检验
     Iterator iteratorLevel3 = module3Map.keySet().iterator();
     while(iteratorLevel3.hasNext()) {
      String name = (String)iteratorLevel3.next();
      String description = (String)module3Map.get(name);
         System.out.print("The " + description + " module is ");
         if(domImpl.hasFeature(name, "3.0")) {
          System.out.println("supported");
         }
         else {
          System.out.println("not supported");
         }
     }
 }
 
 public static void main(String[] args) {
  
  String vendorImplementationClass1 = "org.apache.xerces.dom.DOMImplementationImpl";//实现DOMImpolementation的类

全名
  String vendorImplementationClass2 = "javax.xml.parsers.DocumentBuilderFactory";//实现DOMImpolementation的类全名
   
  loadModule();
  try { 
   //得到第一个实现DOMImplementation接口的类org.apache.xerces.dom.DOMImplementationImpl
   DOMImplementation  domImpl1 = (DOMImplementation  )Class.forName

(vendorImplementationClass1).newInstance();   
   
   //得到第二个实现DOMImplementation接口的类javax.xml.parsers.DocumentBuilderFactory
   DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
   DocumentBuilder db = dbf.newDocumentBuilder();
   DOMImplementation domImpl2 = db.getDOMImplementation();
   
   //开始检验
   DOMModuleChecker checker = new DOMModuleChecker();
   checker.checkModule(domImpl1, vendorImplementationClass1);
   System.out.println("-------------------------------------------------------");
   checker.checkModule(domImpl2, vendorImplementationClass2);
  } catch (InstantiationException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (IllegalAccessException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (ClassNotFoundException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (ParserConfigurationException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }
}

 

这个例子中通过DOMImplementation接口的hasFeature方法检查实现该类的Parser们到底都支持哪些Moduel。
运行一下,结果:
For the DOM implementation class org.apache.xerces.dom.DOMImplementationImpl:
The DOM Level 2 Traversal module is supported
The DOM Level 2 Range module is supported
The DOM Level 2 HTML module is not supported
The DOM Level 2 Views module is not supported
The DOM Level 2 CSS module is not supported
The DOM Level 2 Events module is supported
The DOM Level 2 Core module is supported
The DOM Level 3 Core module is supported
The DOM Level 3 Validation module is not supported
The DOM Level 3 Load & Save module is supported
-------------------------------------------------------
For the DOM implementation class import javax.xml.parsers.DocumentBuilderFactory:
The DOM Level 2 Traversal module is supported
The DOM Level 2 Range module is supported
The DOM Level 2 HTML module is not supported
The DOM Level 2 Views module is not supported
The DOM Level 2 CSS module is not supported
The DOM Level 2 Events module is supported
The DOM Level 2 Core module is supported
The DOM Level 3 Core module is supported
The DOM Level 3 Validation module is not supported
The DOM Level 3 Load & Save module is supported


结果显而易见,两个类对DOM Module的支持都不错。

3,第一次想到这里,我就又有一个疑问,我们能否指定“支持”呢?答案是肯定的。这就是在DOM Level3中大名鼎鼎的bootstrapping,"自举"机制。
但是有一个前提就是你本身的Parser要支持,也就是说只能从上面的结果中选啦。

.....
DOMImplementationRegistry register = DOMImplementationRegistry.newInstance();
DOMImplementation domImpl = register.getDOMImplementation("XML 3.0"); //指定支持XML3.0
domImpl.createDocument(null, "books", null);
......


4.常用DOM Module:
1)DOM Level 2 Tranversal:看到这个名字就该想到这个Module是关于DOM遍历的,这个Module是由org.w3c.dom.traversa包来实现的,其中有四

个接口:NodeIterator,DocumentTraversal,NodeFilter,TreeWalker。再看例子之前,大概了解一下他们:

a. DocumentTraversal是这个包中的核心接口(感觉上地位有点像Document),一般实现了Document接口的类就已经实现了DocumentTraversal,所

以可以:DocumentTraversal docTra = (DocumentTraversal)doc; 还有此接口两个核心方法createNodeIterator,createTreeWalker
b.NodeIterator和TreeWalker,负责遍历DOM,只不过是以不同的形式。(例子中解释)
c.NodeFilter:过滤器

先准备一个html:
<html>
<head>
</head>
<body>
Hi ! yaoyao <h1>how are you </h1>
<p>that's fine. do you?</p>
<h2>I'm fine too.</h2>
</body>
</html>


例一:NodeIterator(遍历上面的html)
package test;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

import org.apache.xerces.parsers.DOMParser;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.traversal.NodeIterator;
import org.w3c.dom.traversal.DocumentTraversal;
import org.w3c.dom.traversal.NodeFilter;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public class ItaratorTest {
 public void iteratorNode(String xmlPath) throws SAXException, IOException {
  //解析指定路径的xml文档,并得到doc
  BufferedReader br = new BufferedReader(new FileReader(xmlPath));
  InputSource inputSource = new InputSource(br);
  DOMParser parser = new DOMParser();
  parser.parse(inputSource);
  Document doc = parser.getDocument();
  
  //找到body元素
  Element root = doc.getDocumentElement();
  Node body = root.getElementsByTagName("body").item(0);
  
  //得到NodeIterator
  NodeIterator iterator = ((DocumentTraversal)doc).createNodeIterator(body, NodeFilter.SHOW_ALL, null, true);
  Node node;
  while((node = iterator.nextNode()) != null) {
   if(node.getNodeType() == Node.ELEMENT_NODE) {
    System.out.println("ElementName:"+node.getNodeName());
   }
   else if(node.getNodeType() == Node.TEXT_NODE) {
    System.out.println("TextContent:"+node.getNodeValue());
   }
  }
 }
 
 public static void main(String[] args) {
  String xmlURI = "D://workplace//a.html";  //自己的html文件路径
  ItaratorTest test = new ItaratorTest();
  try {
   test.iteratorNode(xmlURI);
  } catch (SAXException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 } 
}

output:
ElementName:body
TextContent:
Hi ! yaoyao
ElementName:h1
TextContent:how are you
TextContent:

ElementName:p
TextContent:that's fine. do you?
TextContent:

ElementName:h2
TextContent:I'm fine too.
TextContent:

例子注解:
NodeIterator iterator = ((DocumentTraversal)doc).createNodeIterator(body, NodeFilter.SHOW_ALL, null, true);
中createNodeIterator有四个参数:
a. 需要遍历的节点范围。(不包括body本身)
b. 需要遍历的节点种类。在这里是show_all,还可以是show_element,show_text;
c. 使用的过滤类(这里没有,所以为null)
d. 是否扩展实体引用(一般为true)


例二:NodeFilter
先写一个过滤器:
package test;
import org.w3c.dom.Node;
import org.w3c.dom.traversal.NodeFilter;
public class IteratorFilter implements NodeFilter{

 public short acceptNode(Node node) {  
  Node parent;
  if(node.getNodeType() == Node.TEXT_NODE) {   //对文本节点进行过滤
   parent = node.getParentNode();
   if((parent.getNodeName().equalsIgnoreCase("p")) ||
   (parent.getNodeName().equalsIgnoreCase("h2"))) {
    return NodeFilter.FILTER_ACCEPT;  //接受,即:当遇到p,h2时,把他们的文本进行遍历
   }
  }
  return NodeFilter.FILTER_SKIP; //跳过,即:当遇到非p,h2节点时,不对他们的文本遍历。
 } 
}

然后改一下例一:
NodeIterator iterator = ((DocumentTraversal)doc).createNodeIterator(body, NodeFilter.SHOW_ALL, new IteratorFilter(), true);

改完后run一下:
output:
TextContent:that's fine. do you?
TextContent:I'm fine too.
(并没有<h1>how are you </h1>)

注意:过滤器的过滤范围,NodeFilter是在createNodeIterator方法的第三个参数范围内进行过滤的(此处是NodeFilter.SHOW_ALL),如果改成

NodeFIlter.SHOW_ELEMENT,那么run后,不会output任何内容。


2)DOM Level 2 Range:顾名思义,肯定更DOM解析的范围有关。它是由org.w3c.dom.ranges来实现,其中有三个接口:
a. DocumentRange(地位和DocumentTranversal差不多)
b. Range
c. RangeException
比较容易看看例子就可以明白:

例三:Range   (还是以上面的html文件为基础,看看如何定制Range)
package test;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import org.apache.xerces.parsers.DOMParser;
import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.XMLSerializer;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.ranges.DocumentRange;
import org.w3c.dom.ranges.Range;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public class RangeTest {
 public static void main(String[] args) {
  String xmlURI = "D://workplace//a.html";
  DOMParser parser = new DOMParser();
  InputSource inputSource = new InputSource(xmlURI);
  try {
   parser.parse(inputSource);
   //得到Range
   Document doc = parser.getDocument();
   Range range = ((DocumentRange)doc).createRange();
   //设置范围
   Node body = doc.getElementsByTagName("body").item(0);
   range.setStartBefore(body.getFirstChild());
   range.setEndAfter(body.getLastChild());
   //删除range中的内容:
   range.deleteContents();
   //释放range
   range.detach();
   //把内存中的改变存入文件
   RangeTest test = new RangeTest();
   test.save(doc, xmlURI);
  } catch (SAXException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }
 //把内存中的改变写入文件,在这里不是重点,不太明白没多大影响
 public void save(Document doc,String path) {
  OutputFormat format = new OutputFormat(doc);
  try {
   OutputStream os = new FileOutputStream(path);
   XMLSerializer serializer = new XMLSerializer(os,format);
   serializer.asDOMSerializer();
   serializer.serialize(doc.getDocumentElement());
  } catch (FileNotFoundException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  
 }
}

//例四:(以下面类似“剪切”的例子,看看如何取得range中的内容)
......
Node body = doc.getElementsByTagName("body").item(0);
range.setStartBefore(body.getFirstChild());
range.setEndAfter(body.getLastChild());
DocumentFragment list = range.extractContents();  //获得了body中的“片段”,操作DocumentFragment和操作NodeList差不多
range.deleteContents();
......

/*
DOM解析轻松入门(四)--DOM Level 3 Load and Save 2008-2-21
*/

 

 

;