使用Xerces-J的DOM方式进行XML程序设计
--动态创建一个DOM树
- 简介与背景知识
- Xerces对DOM的实现
- 如何使用
- 动态创建一个DOM树
- 使用XMLSerializer序列化DOM对象
- 使用DOM的程序的实例
使用Xerces-J我们可以有两种方法动态创建DOM树,也就是说我们不需要从一个xml文本作为基础,而凭空创建一个DOM的树状模型。在后面我们还会介绍如何把这个DOM树状模型使用serialize的方式转化成xml文本。
第一种方法是使用Xerces的方法动态创建一个DOM树。这个方法不是DOM标准的,因此不能转换到其他的解析器上使用,但是功能要比标准的DOM方法强大,提供了一些很有用的功能。使用这个方法我们需要用到org.apache.xerces.dom.DocumentImpl类或者org.apache.xerces.dom.CoreDocumentImpl类。DocumentImpl类是CoreDocumentImpl类的子类,在这两个类中实现了org.w3c.dom.Document界面的全部方法,并且提供了一些其他的扩展方法。我们前面已经介绍过,Document界面是一个文档的基础,所有的内容(Element,Process
Instruction, Document Type等等)都包含在一个Document中,另外,在Document界面中还包括了动态创建,增添和删除这些内容的方法。但是首先我们要创建一个Document界面的实现,才能够动态的创建这些内容,而创建一个Document界面的实现我们可以使用DocumentImpl和CoreDocumentImpl这两个类的结构函数直接建立或者说直接创建一个CoreDocumentImpl或者DocumentImpl的对象就可以了。CoreDocumentImpl类实现了核心Document的功能。而DocumentImpl类则在CoreDocumentImpl类的基础上增加了Event,Range和Traversal的功能,这些功能我们目前先不准备介绍。下面我们介绍CoreDocumentImpl的结构方法和在Document界面之外的扩展,关于如何创建Element等内容的知识请参考Document界面的介绍。
CoreDocumentImpl类的结构方法及对Document界面的扩展和对于动态创建DOM树比较重要的方法。
方法名 |
使用说明
|
CoreDocumentImpl()
|
缺省结构函数,但是这个不是标准DOM函数。只能在Xerces中使用。 |
CoreDocumentImpl(boolean grammarAccess) |
这是一个结构函数。呵呵。Xerces文档上就是这么写的。好不负责任啊! |
CoreDocumentImpl(DocumentType doctype) |
这个方法调用DOMImplementation界面中的createDocument方法。 |
CoreDocumentImpl(DocumentType doctype, boolean grammarAccess)
|
同上。以上结构方法仅仅建立一个空的Document对象,这个对象是没有Document节点的。 |
Node adoptNode(Node source) |
从另外一个Document对象那里获得一个子节点以及这个子节点的所有子节点,另外的Document对象不在拥有这个子节点。返回值是获得的子节点的引用。具体操作可以这样理解:首先把想要引入的子节点的ownerNode从原来的引用改成新的引用。然后把这的子节点从原来的Document中remove。最后返回这个子节点的引用。注意这里是不负责子节点的插入位置的。 |
Node importNode(Node source, boolean deep) |
从另外一个Document对象获得一个子节点。可以选择是否同时获取这个子节点的子节点。同上面不同的是这个方法不从原来的Document中把这个子节点删除。其他同上。 |
void putIdentifier(java.lang.String idName, Element element)
|
给一个Element一个id这个方法在动态创建的DOM对象树要使用id的时候非常有用。但是这个方法不是标准的Document界面提供的方法。因此在其他的DOM实现中不一定能够使用。 |
下面的程序演示了如何使用这些方法以及importNode和adoptNode的不同之处。这里使用了org.apache.xml.serialize包中的内容。这些内容是为了显示xml文档而使用的,我们以后会进行介绍。
import org.apache.xerces.dom.*;
import org.w3c.dom.*;
import org.apache.xml.serialize.*;
public class testDOM{
public static void main( String [] a ){
CoreDocumentImpl oDoc = new CoreDocumentImpl();
oDoc.setEncoding("GB2312");
Element oElem = oDoc.createElement( "hello" );
Text oText = oDoc.createTextNode("你好");
oElem.appendChild( oText );
oDoc.appendChild( oElem );
XMLSerializer oXMLS = new XMLSerializer( new OutputFormat( "XML" , "GB2312", true ) );
oXMLS.setOutputByteStream( System.out );
try{
oXMLS.serialize( oDoc );
}catch( Exception e ){
e.printStackTrace();
}
oXMLS.reset();
CoreDocumentImpl oDoc2 = new CoreDocumentImpl();
Element oElem1 = oDoc2.createElement("what");
Text oText1 = oDoc2.createTextNode("Cawl");
oElem1.appendChild( oText1 );
oDoc2.appendChild( oElem1 );
oDoc2.setEncoding("UTF8");
XMLSerializer oXMLS1 = new XMLSerializer();
oXMLS1.setOutputByteStream( System.out );
try{
oXMLS1.serialize( oDoc2 );
}catch( Exception e ){
e.printStackTrace();
}
oXMLS1.reset();
oDoc.putIdentifier( "1" , oElem );
Element oElemByIdDoc = oDoc.getElementById( "1");
oDoc2.putIdentifier( "1" , oElem1 );
Element oElemByIdDoc2 = oDoc2.getElementById( "1" );
try{
oXMLS1.serialize( oElemByIdDoc2 );
}catch( Exception e ){
e.printStackTrace();
}
oXMLS1.reset();
Node oNode = oDoc.importNode( oElemByIdDoc2 , true );
oElemByIdDoc.appendChild( oNode );
try{
oXMLS.serialize( oDoc );
}catch( Exception e ){
e.printStackTrace();
}
oXMLS.reset();
try{
oXMLS1.serialize( oDoc2 );
}catch( Exception e ){
e.printStackTrace();
}
oXMLS1.reset();
oNode = null;
oNode = oDoc.adoptNode( oElemByIdDoc2 );
oElemByIdDoc.appendChild( oNode );
try{
System.out.println("\nthe last trial............");
oXMLS.serialize( oDoc );
oXMLS1.serialize( oDoc2 );
}catch( Exception e ){
e.printStackTrace();
}
}
}
动态创建DOM树的第二种方法是采用DOM提供的标准方法。这里我们需要使用org.apache.xerces.dom.DOMImplementation类或者org.apache.xerces.dom.CoreDOMImplementation类。这两个类实现了org.w3c.dom.DOMImplementation界面。这里面最重要的一个方法就是createDocument。这个方法可以创建一个Document对象,这个方法总共有三个参数,第一个是Document节点的名空间,第二个是Document节点的qualifiedName,
第三个是DocumentType。这样,我们在调用了createDocument方法之后就已经创建了一个根节点,这一点是同我们前面介绍过的使用CoreDocumentImpl类动态创建DOM树不同的,因此需要大家注意。下面的例子演示了如何使用DOMImplementationImpl动态创建一个DOM树。
import org.apache.xerces.dom.*;
import org.w3c.dom.*;
import org.apache.xml.serialize.*;
public class testDOM2{
public static void main( String [] a ){
CoreDOMImplementationImpl oDOM = new CoreDOMImplementationImpl();
Document oDoc = oDOM.createDocument("http://cyfer.topcool.net", "cyfer:hello", null);
//oDoc.setEncoding("GB2312");
Element oElem = oDoc.getDocumentElement();
Text oText = oDoc.createTextNode("你好");
oElem.appendChild( oText );
XMLSerializer oXMLS = new XMLSerializer( new OutputFormat( "XML" , "GB2312", true ) );
oXMLS.setOutputByteStream( System.out );
try{
oXMLS.serialize( oDoc );
}catch( Exception e ){
e.printStackTrace();
}
oXMLS.reset();
DOMImplementationImpl oDOM2 = new DOMImplementationImpl();
Document oDoc2 = oDOM2.createDocument("http://cyfer.topcool.net", "cyfer:what", null);
Element oElem1 = oDoc2.getDocumentElement();
Text oText1 = oDoc2.createTextNode("Cawl");
oElem1.appendChild( oText1 );
//oDoc2.setEncoding("UTF8");
XMLSerializer oXMLS1 = new XMLSerializer();
oXMLS1.setOutputByteStream( System.out );
try{
oXMLS1.serialize( oDoc2 );
}catch( Exception e ){
e.printStackTrace();
}
oXMLS1.reset();
Element oElemByIdDoc = oDoc.getDocumentElement( );
Element oElemByIdDoc2 = oDoc2.getDocumentElement();
try{
oXMLS1.serialize( oElemByIdDoc2 );
}catch( Exception e ){
e.printStackTrace();
}
oXMLS1.reset();
Node oNode = oDoc.importNode( oElemByIdDoc2 , true );
oElemByIdDoc.appendChild( oNode );
try{
oXMLS.serialize( oDoc );
}catch( Exception e ){
e.printStackTrace();
}
oXMLS.reset();
try{
oXMLS1.serialize( oDoc2 );
}catch( Exception e ){
e.printStackTrace();
}
oXMLS1.reset();
/* oNode = null;
oNode = oDoc.adoptNode( (Node)oElemByIdDoc2 );
oElemByIdDoc.appendChild( oNode );
try{
System.out.println("\nthe last trial............");
oXMLS.serialize( oDoc );
oXMLS1.serialize( oDoc2 );
}catch( Exception e ){
e.printStackTrace();
}*/
System.out.println( oDoc instanceof DocumentImpl );
System.out.println( oDoc2 instanceof DocumentImpl );
}
}
不知道为什么,我们没有通过setEncoding和adoptNode的测试,可能是classpath上面出了问题。从上面的例子我们还可以看出,CoreDOMImplementationImpl.createDocument方法实际上创建了一个CoreDocumentImpl对象,而DOMImplementation.createDocument方法创建了一个DocumentImpl对象。这就是两者的区别。