文档对象模型
slideSample01.xml 上。(可浏览的版本是 slideSample01-xml.html)先来看看应用程序的基本逻辑,确保命令行上带有一个参数:
public class DomEcho {
public static void main(String argv[])
{
if (argv.length != 1) {
System.err.println(
"Usage: java DomEcho filename");
System.exit(1);
}
}// main
}// DomEcho
导入所需的类本节中将看到所有的类都是单独命名的。这样,在引用API文档时就能知道每个类的出处。在你自己的应用程序中,你可能希望使用短格式javax.xml.parsers.*来替换如下所示的导入语句。
添加如下代码以导入要使用的JAXP API:
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
想在解析XML文档时抛出异常,添加下面几行:
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
添加下面几行来读取示例XML文件并识别错误:
import java.io.File;
import java.io.IOException;
最后,为DOM和DOM异常导入W3C定义:
import org.w3c.dom.Document;
import org.w3c.dom.DOMException;
注意:仅在遍历或操作DOM时才会抛出DOMException 。使用下面介绍的不同机制来报告解析过程中出现的错误。
声明 DOMorg.w3c.dom.Document 类是文档对象模型(DOM)的W3C名。不管解析XML文档还是创建一个XML文档,都会产生一个文档实例。在教程的后面将在另一个方法中引用该对象,所以,在这里将它定义成全局对象:
public class DomEcho
{
static Document document;
public static void main(String argv[])
{
它必须是static的,因为你需要在很短时间内从main方法生成它的内容。
处理错误下一步,插入错误处理逻辑。该逻辑基本上跟SAX教程的使用非验证解析器处理错误中的代码相同,所以在这里就不详细介绍了。在这里要特别提醒的是,当解析XML文档遇到困难时,需要JAXP-conformant 文档构造器来报告SAX异常。实际上DOM解析器不需要在内部使用SAX解析器,但是由于早就有了SAX标准,看来可以用它来报告错误。结果,DOM和SAX应用程序的错误处理代码就非常简单:
public static void main(String argv[])
{
if (argv.length != 1) {
...
}
try {
} catch (SAXParseException spe) {
//
Error generated by the parser
System.out.println("\n** Parsing error"
+ ", line " + spe.getLineNumber()
+ ", uri " + spe.getSystemId());
System.out.println(" " + spe.getMessage() );
// Use the contained exception, if any
Exception x = spe;
if (spe.getException() != null)
x = spe.getException();
x.printStackTrace();
} catch (SAXException sxe) {
//
Error generated during parsing
Exception x = sxe;
if (sxe.getException() != null)
x = sxe.getException();
x.printStackTrace();
} catch (ParserConfigurationException pce) {
// Parser with specified options can't be built
pce.printStackTrace();
} catch (IOException ioe) {
// I/O error
ioe.printStackTrace();
}
}// main
实例化工厂接着,添加下面的代码,得到工厂的一个实例,该实例能够给出一个文档构造器:
public static void main(String argv[])
{
if (argv.length != 1) {
...
}
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
try {
获得解析器并解析文件现在,添加下面的代码以获得构造器的一个实例,并用它来解析指定的文件:
try {
DocumentBuilder builder = factory.newDocumentBuilder();
document = builder.parse( new File(argv[0]) );
} catch (SAXParseException spe) {
保存该文件!
到现在,你可能觉得启动每个JAXP应用程序的方法几乎相同。的确如此!保存该版本的文件,将它作为模板。后面将要使用它,它是XSLT转换应用程序的基础。
运行程序在整个DOM教程中,将使用SAX段中看到的示例幻灯片显示。尤其是,你将使用slideSample01.xml(它是一个简单的XML文件,内部没有什么内容)和slideSample10.xml(是一个更加复杂的例子,引入了DTD、处理指令、实体引用和CDATA段)。
关于如何编译并运行程序的说明,请查看SAX教程的编译和运行程序 。以"DomEcho"替代"Echo"作为程序的名字。
在slideSample01.xml上运行该程序。如果运行没有出错,你就成功地解析了一个XML文档并且构建了一个DOM。恭喜!
注意:目前你只能听从我的建议,因为这时你没有任何办法来显示结果。但是在不久的将来...
其他信息既然你已经成功地读取了一个DOM,要高效使用DocumentBuilder 必须知道一到两点。即:
· 配置Factory
· 处理验证错误
配置工厂默认情况下,工厂返回非验证解析器,对命名空间一无所知。要获得一个验证解析器,并且/或能理解命名空间,请使用下面的命令来设置一个或多个参数,以配置该工厂:
public static void main(String argv[])
{
if (argv.length != 1) {
...
}
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
factory.setValidating(true);
factory.setNamespaceAware(true);
try {
...
注意:不要求JAXP-conformant解析器支持这些参数的所有的结合,虽然引用解析器支持。如果你指定了一个无效的参数结合,在获得解析器实例时factory产生ParserConfigurationException 。
在DOM教程的最后一节使用命名空间中将详细介绍如何使用命名空间。本节要结束了,虽然你仍然希望知道…
处理验证错误记住,在你阅读SAX教程时,你所要做的事情就是构建一个DOM?这里,那些信息起作用了。
记住对验证错误的默认反应(由SAX标准提出)就是什么不也做。JAXP标准要求抛出SAX异常,所以使用跟SAX应用程序中几乎相同的错误处理机制。尤其需要使用DocumentBuilder的setErrorHandler方法提供实现SAX ErrorHandler 接口的对象。
注意:也可以使用DocumentBuilder 中的setEntityResolver 方法。
下面的代码使用匿名内部类来定义ErrorHandler。下面的代码确保验证错误产生异常。
builder.setErrorHandler(
new org.xml.sax.ErrorHandler() {
// ignore fatal errors (an exception is guaranteed)
public void fatalError(SAXParseException exception)
throws SAXException {
}
// treat validation errors as fatal
public void error(SAXParseException e)
throws SAXParseException
{
throw e;
}
// dump warnings too
public void warning(SAXParseException err)
throws SAXParseException
{
System.out.println("** Warning"
+ ", line " + err.getLineNumber()
+ ", uri " + err.getSystemId());
System.out.println(" " + err.getMessage());
}
);
本段代码使用匿名内部类来产生实现ErrorHandler 接口的对象实例。由于它没有类名字,所以是“匿名”的。你可以将它看作"ErrorHandler"实例,虽然技术上它是实现指定接口的没有名字的实例。这些代码本质上跟使用非验证解析器处理错误中的相同。要了解验证问题的更多知识,请参照使用验证解析器。
展望未来下节中将在Jtree中显示DOM结构,并且开始展示它的结构。例如,你将看到实体引用和CDATA段是如何出现在DOM中的。可能更加重要的是,你将看到如何将文本节点(它包含实际的数据)放在DOM中的元素节点下。
显示DOM层次结构要创建或操纵一个文档对象层次结构 (DOM),必须要清楚地了解DOM中节点的结构。本节中将展示DOM的内部结构。
回送树节点现在你所需要的是展示DOM中节点的方法,这样你就能看到节点内究竟包含什么。要实现这一点,将DOM转换成JTreeModel 并且在Jtree中显示完整的DOM。这些需要大量的工作,但是它不仅将产生你将来要使用的诊断工具,而且可以帮助你了解DOM结构。
将DomEcho 转换为GUI 应用程序由于DOM是树,并且Swing JTree 组件都跟显示树有关,所以有必要将DOM放入Jtree,以便查看。该过程的第一步是处理DomEcho 程序,让它成为一个GUI 应用程序。
注意:本节讨论的代码在DomEcho02.java中。
添加Import语句首先导入建立应用程序和显示Jtree需要的GUI组件:
// GUI components and layouts
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
DOM教程的后面部分将设计DOM显示,以产生Jtree显示的用户友好版本。用户选择树中的元素时,子元素将显示在邻近的编辑器面板中。所以,进行安装工作时,需要导入建立分割视图(JSplitPane)和显示子元素文本(JEditorPane)所需的组件:
import javax.swing.JSplitPane;
import javax.swing.JEditorPane;
添加一些你需要的支持类:
// GUI support classes
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.WindowEvent;
import java.awt.event.WindowAdapter;
最后,导入一些类来建立别致的边框:
// For creating borders
import javax.swing.border.EmptyBorder;
import javax.swing.border.BevelBorder;
import javax.swing.border.CompoundBorder;
(这些是可选的。如果想要简化代码,可以跳过它们以及相关代码。)
创建GUI框架下一步是将应用程序转换为GUI应用程序。为此,静态main方法将创建main类的一个实例,它将成为GUI面板。
首先扩展Swing JPanel 类,将该类变成一个GUI面板:
public class DomEcho02 extends JPanel
{
// Global value so it can be ref'd by the tree-adapter
static Document document;
...
定义一些用来控制窗口大小的常量:
public class DomEcho02 extends JPanel
{
// Global value so it can be ref'd by the tree-adapter
static Document document;
static final int windowHeight = 460;
static final int leftWidth = 300;
static final int rightWidth = 340;
static final int windowWidth = leftWidth + rightWidth;
现在,在main方法中,调用创建GUI面板所在的外部框架的方法:
public static void main(String argv[])
{
...
DocumentBuilderFactory factory ...
try {
DocumentBuilder builder = factory.newDocumentBuilder();
document = builder.parse( new File(argv[0]) );
makeFrame();
} catch (SAXParseException spe) {
...
然后,需要定义makeFrame方法本身。它包含创建框架的标准代码,并能很好地处理退出条件,给出main面板的实例,定制它的大小,最后将其定位于屏幕上并使之可视化:
...
} // main
public static void makeFrame()
{
// Set up a GUI framework
JFrame frame = new JFrame("DOM Echo");
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e)
{System.exit(0);}
});
//
Set up the tree, the views, and display it all
final DomEcho02 echoPanel = new DomEcho02();
frame.getContentPane().add("Center", echoPanel );
frame.pack();
Dimension screenSize =
Toolkit.getDefaultToolkit().getScreenSize();
int w = windowWidth + 10;
int h = windowHeight + 10;
frame.setLocation(screenSize.width/3 - w/2,
screenSize.height/2 - h/2);
frame.setSize(w, h);
frame.setVisible(true)
} // makeFrame
添加显示组件将程序转换成GUI应用程序的工作只剩下创建类构造函数并让它创建面板的内容。下面是构造函数:
public class DomEcho02 extends JPanel
{
...
static final int windowWidth = leftWidth + rightWidth;
public DomEcho02()
{
} // Constructor
这里,使用前面导入的边框类建立常用边框(可选):
public DomEcho02()
{
// Make a nice border
EmptyBorder eb = new EmptyBorder(5,5,5,5);
BevelBorder bb = new BevelBorder(BevelBorder.LOWERED);
CompoundBorder cb = new CompoundBorder(eb,bb);
this.setBorder(new CompoundBorder(cb,eb));
} // Constructor
然后,创建一棵空树并且将它放入JScrollPane ,这样当它变大时,用户就能看到它的内容:
public DomEcho02(
{
...
//
Set up the tree
JTree tree = new JTree();
// Build left-side view
JScrollPane treeView = new JScrollPane(tree);
treeView.setPreferredSize(
new Dimension( leftWidth, windowHeight ));
} // Constructor
现在,创建不可编辑的JEditPane ,它将最终保存选中的JTree 节点指向的内容:
public DomEcho02(
{
....
// Build right-side view
JEditorPane htmlPane = new JEditorPane("text/html","");
htmlPane.setEditable(false);
JScrollPane htmlView = new JScrollPane(htmlPane);
htmlView.setPreferredSize(
new Dimension( rightWidth, windowHeight ));
} // Constructor
构建了左边的JTree 和右边的JEditorPane 后,创建一个JSplitPane 来存放它们:
public DomEcho02()
{
....
// Build split-pane view
JSplitPane splitPane =
new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
treeView, htmlView );
splitPane.setContinuousLayout( true );
splitPane.setDividerLocation( leftWidth );
splitPane.setPreferredSize(
new Dimension( windowWidth + 10, windowHeight+10 ));
} // Constructor
该代码建立了带有垂直分割线的JSplitPane 。它将在树和编辑器面板之间产生“水平分割线”。(实际上,更是水平布局)你也要设置分割线的位置,这样树能够得到它要的宽度,将剩下的窗口宽度分配给编辑器面板。
最后,指定面板的布局并且添加split pane:
public DomEcho02()
{
...
// Add GUI components
this.setLayout(new BorderLayout());
this.add("Center", splitPane );
} // Constructor
恭喜!该程序现在是一个GUI应用程序。现在可以运行它,看看屏幕上的总体布局是怎样的。为了引用,这里有完整的构造函数:
public DomEcho02()
{
// Make a nice border
EmptyBorder eb = new EmptyBorder(5,5,5,5);
BevelBorder bb = new BevelBorder(BevelBorder.LOWERED);
CompoundBorder CB = new CompoundBorder(eb,bb);
this.setBorder(new CompoundBorder(CB,eb));
// Set up the tree
JTree tree = new JTree();
// Build left-side view
JScrollPane treeView = new JScrollPane(tree);
treeView.setPreferredSize(
new Dimension( leftWidth, windowHeight ));
// Build right-side view
JEditorPane htmlPane = new JEditorPane("text/html","");
htmlPane.setEditable(false);
JScrollPane htmlView = new JScrollPane(htmlPane);
htmlView.setPreferredSize(
new Dimension( rightWidth, windowHeight ));
// Build split-pane view
JSplitPane splitPane =
new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
treeView, htmlView )
splitPane.setContinuousLayout( true );
splitPane.setDividerLocation( leftWidth );
splitPane.setPreferredSize(
new Dimension( windowWidth + 10, windowHeight+10 ));
// Add GUI components
this.setLayout(new BorderLayout());
this.add("Center", splitPane );
} // Constructor
创建适配器以便在Jtree中显示DOM现在已经有一个GUI框架来显示JTree ,下一步是获得Jtree以显示DOM。但是JTree 希望显示TreeModel。 DOM 是树,但它不是TreeModel。所以需要创建一个适配器使得DOM
文档对象模型
816-7869-10
本文地址:http://com.8s8s.com/it/it13845.htm