文档

Java™ 教程
隐藏目录
将DOM作为XML文件写出
路径: Java XML处理API(JAXP)
课程: 可扩展样式表语言转换

将DOM作为XML文件写出

在构建了DOM(无论是通过解析XML文件还是通过编程构建)之后,您经常希望将其保存为XML。本节将向您展示如何使用Xalan transform包来实现这一目标。

使用该包,您将创建一个transformer对象,将DOMSource连接到StreamResult。然后,您将调用transformer的transform()方法将DOM写出为XML数据。

读取XML

第一步是通过解析XML文件在内存中创建一个DOM。到现在为止,您应该对这个过程感到很熟悉。


注意: 

This section中讨论的代码在文件TransformationApp01.java中。 下载XSLT示例并将其解压缩到install-dir/jaxp-1_4_2-release-date/samples目录中。


以下代码提供了一个基本的模板供参考。它基本上与文档对象模型课程开始时使用的代码相同。

import javax.xml.parsers.DocumentBuilder; 
import javax.xml.parsers.DocumentBuilderFactory; 
import javax.xml.parsers.FactoryConfigurationError; 
import javax.xml.parsers.ParserConfigurationException; 
import org.xml.sax.SAXException; 
import org.xml.sax.SAXParseException; 

import org.w3c.dom.Document;
import org.w3c.dom.DOMException;

import java.io.*;

public class TransformationApp01 {

    static Document document; 

    public static void main(String argv[]) {
        if (argv.length != 1) {
            System.err.println("Usage: java TransformationApp01 filename");
            System.exit (1);
        }

        DocumentBuilderFactory factory =
        DocumentBuilderFactory.newInstance();

        try {
            File f = new File(argv[0]);
            DocumentBuilder builder =
            factory.newDocumentBuilder();
            document = builder.parse(f);
  
        } 
        catch (SAXParseException spe) {
            // 解析器生成的错误
            System.out.println("\n** 解析错误"
                               + ",行 " + spe.getLineNumber()
                               + ",uri " + spe.getSystemId());
            System.out.println("  " + spe.getMessage() );
  
            // 如果有的话,使用包含的异常
            Exception x = spe;
            if (spe.getException() != null)
                x = spe.getException();
            x.printStackTrace();
        }
        catch (SAXException sxe) {
            // 由此应用程序生成的错误(或解析器初始化错误)
            Exception x = sxe;
            if (sxe.getException() != null)
                x = sxe.getException();
            x.printStackTrace();
        }
        catch (ParserConfigurationException pce) {
            // 无法构建带有指定选项的解析器
            pce.printStackTrace();
        }
        catch (IOException ioe) {
            // I/O错误
            ioe.printStackTrace();
        }
    }
}

创建转换器

下一步是创建一个转换器,用于将XML传输到System.out。首先,需要添加以下导入语句。

import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.dom.DOMSource; 
import javax.xml.transform.stream.StreamResult;
import java.io.*;

在这里,您添加了一系列的类,这些类现在应该形成一个标准的模式:一个实体(Transformer),用于创建它的工厂(TransformerFactory),以及可能由每个生成的异常。因为转换始终具有源和结果,所以您随后导入了使用DOM作为源(DOMSource)和用于结果的输出流的类(StreamResult)。

接下来,添加执行转换的代码:

try {
    File f = new File(argv[0]);
    DocumentBuilder builder = factory.newDocumentBuilder();
    document = builder.parse(f);

    // 为输出使用转换器
    TransformerFactory tFactory =
    TransformerFactory.newInstance();
    Transformer transformer = 
    tFactory.newTransformer();

    DOMSource source = new DOMSource(document);
    StreamResult result = new StreamResult(System.out);
    transformer.transform(source, result);
}

在这里,您创建了一个转换器对象,使用DOM构造了一个源对象,并使用System.out构造了一个结果对象。然后,您告诉转换器在源对象上操作,并输出到结果对象。

在这种情况下,"transformer"实际上没有改变任何内容。在XSLT术语中,您使用的是身份转换,这意味着"转换"生成了源的副本,没有改变。


注意: 

您可以为转换器对象指定多种输出属性,这些属性在W3C规范中定义,详见http://www.w3.org/TR/xslt#output。例如,要获取缩进的输出,可以调用以下方法:

% transformer.setOutputProperty(OutputKeys.INDENT, "yes");

最后,以下突出显示的代码捕获可能生成的新错误:

} 
catch (TransformerConfigurationException tce) {
    System.out.println("* 转换器工厂错误");
    System.out.println(" " + tce.getMessage());

    Throwable x = tce;
    if (tce.getException() != null)
        x = tce.getException();
    x.printStackTrace(); 
} 
catch (TransformerException te) {
    System.out.println("* 转换错误");
    System.out.println(" " + te.getMessage());

    Throwable x = te;
    if (te.getException() != null)
        x = te.getException();
    x.printStackTrace();
} 
catch (SAXParseException spe) {
    // ...
}

注意事项

要了解更多关于配置工厂和处理验证错误的信息,请参阅将XML数据读入DOM中

运行TransformationApp01示例

  1. 导航至samples目录。
    % cd install-dir/jaxp-1_4_2-release-date/samples.
    
  2. 通过点击此链接下载XSLT示例并将其解压到install-dir/jaxp-1_4_2-release-date/samples目录。
  3. 导航至xslt目录。
    % cd xslt
    
  4. 编译TransformationApp01示例。

    输入以下命令:

    % javac TransformationApp01.java
    
  5. 在XML文件上运行TransformationApp01示例。

    在下面的例子中,TransformationApp01在解压示例包后的xslt/data目录中的foo.xml文件上运行。

    % java TransformationApp01 data/foo.xml
    

    您将看到以下输出:

    <?xml version="1.0" 
        encoding="UTF-8" 
        standalone="no"?><doc>
      <name first="David" last="Marston"/>
      <name first="David" last="Bertoni"/>
      <name first="Donald" last="Leslie"/>
      <name first="Emily" last="Farmer"/>
      <name first="Joseph" last="Kesselman"/>
      <name first="Myriam" last="Midy"/>
      <name first="Paul" last="Dick"/>
      <name first="Stephen" last="Auriemma"/>
      <name first="Scott" last="Boag"/>
      <name first="Shane" last="Curcuru"/>
    

    创建转换器中所述,该转换器实际上并未更改任何内容,而是执行了身份转换,生成源的副本。真正的转换将在从任意数据结构生成XML中执行。

编写DOM子树

也可以对DOM的子树进行操作。在本节中,您将尝试使用该选项。


注意: 

本节讨论的代码在TranformationApp02.java中。如果您还没有这样做,下载XSLT示例并将其解压缩到install-dir/jaxp-1_4_2-release-date/samples目录中。


唯一的区别是现在您将使用DOM中的一个节点来创建DOMSource,而不是整个DOM。第一步是导入需要获取的节点的类,如下面突出显示的代码所示:

import org.w3c.dom.Document;
import org.w3c.dom.DOMException;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList; 

下一步是找到一个好的节点进行实验。下面突出显示的代码选择了第一个<name>元素。

try {
    File f = new File(argv[0]);
    DocumentBuilder builder = factory.newDocumentBuilder();
    document = builder.parse(f);

    NodeList list = document.getElementsByTagName("name");
    Node node = list.item(0); 
}

创建Transformer中,源对象是通过以下代码行从整个文档构建的

DOMSource source = new DOMSource(document);

然而,下面突出显示的代码行构建了一个由特定节点为根的子树组成的源对象。

DOMSource source = new DOMSource(node);
StreamResult result = new StreamResult(System.out);
transformer.transform(source, result);

运行TranformationApp02示例

  1. 导航到samples目录。
    % cd install-dir/jaxp-1_4_2-release-date/samples.
    
  2. 点击此链接下载XSLT示例,并将其解压缩到install-dir/jaxp-1_4_2-release-date/samples目录。
  3. 导航到xslt目录。
    cd xslt
    
  4. 编译TranformationApp02示例。

    输入以下命令:

    % javac xslt/TranformationApp02.java
    
  5. 在XML文件上运行TranformationApp02示例。

    在下面的示例中,当你解压缩示例包后,在xslt/data目录中找到文件foo.xml,然后运行TranformationApp02

    % java TranformationApp02 data/foo.xml
    

    你将看到以下输出:

    <?xml version="1.0" encoding="UTF-8" 
        standalone="no"?><doc><name 
        first="David" last="Marston"/>
    

    这次只打印了第一个<name>元素。

    到此为止,你已经学会了如何使用转换器将DOM写入输出,并如何使用DOM子树作为转换的源对象。在下一节中,你将学习如何使用转换器从任何可解析的数据结构中创建XML。


上一页: XPath的工作原理
下一页: 从任意数据结构生成XML