文档对象模型

类别:Java 点击:0 评论:0 推荐:

文档对象模型

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 。使用下面介绍的不同机制来报告解析过程中出现的错误。

声明 DOM

org.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