写出 DOM 作为 XML 文件

构造 DOM(通过解析 XML 文件或以编程方式构建它)之后,您通常希望将其另存为 XML。本节向您展示如何使用 Xalan 转换包进行此操作。

使用该包,您将创建一个变压器对象,以将DOMSource连接到StreamResult。然后,您将调用转换器的transform\(\)方法以将 DOM 作为 XML 数据写出。

读取 XML

第一步是通过解析 XML 文件在内存中创建 DOM。现在,您应该已经熟悉了该过程。

Note:

本节中讨论的代码在文件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) {
            // 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 by this application
            // (or a parser-initialization error)
            Exception x = sxe;
            if (sxe.getException() != null)
                x = sxe.getException();
            x.printStackTrace();
        }
        catch (ParserConfigurationException pce) {
            // Parser with specified options 
            // cannot be built
            pce.printStackTrace();
        }
        catch (IOException ioe) {
            // I/O error
            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.*;

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

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

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

    // Use a Transformer for output
    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构造结果对象。然后,您告诉转换器对源对象进行操作并输出到结果对象。

在这种情况下,“变压器”实际上并没有改变任何东西。在 XSLT 术语中,您使用的是恒等变换,这意味着“变换”将生成源的副本,且保持不变。

Note:

您可以为变压器对象指定各种输出属性,如 W3C 规范中的http://www.w3.org/TR/xslt#output所定义。例如,要获得缩进输出,可以调用以下方法:

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

最后,以下突出显示的代码catch了可能产生的新错误:

} 
catch (TransformerConfigurationException tce) {
    System.out.println("* Transformer Factory error");
    System.out.println(" " + tce.getMessage());

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

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

Notes

  • TransformerExceptions被转换器对象抛出。

  • TransformerConfigurationExceptions被工厂抛出。

  • 要保留 XML 文档的DOCTYPE设置,还必须添加以下代码:

import javax.xml.transform.OutputKeys;
...
if (document.getDoctype() != null) {
    String systemValue = (new File (document.getDoctype().getSystemId())).getName();
    transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, systemValue);
}

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

运行 TransformationApp01 示例

  • 导航到samples目录.
% cd install-dir/jaxp-1_4_2-release-date/samples.
% cd xslt
  • 编译TransformationApp01示例.

键入以下命令:

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

在以下情况下,在解压缩 samples 包后,在xslt/data目录中的文件foo\.xml上运行TransformationApp01

% 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 的子树上进行操作。在本节中,您将try使用该选项。

Note:

本部分讨论的代码在 TranformationApp02.java 中。如果尚未这样做,请下载 XSLT 示例并将其解压缩到 install-dir /jaxp\-1_4_2\- release-date /samples目录中。

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

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); 
}

创建一个变压器中,通过以下代码从整个文档中构造源对象

DOMSource source = new DOMSource(document);

但是,下面突出显示的代码行构造了一个源对象,该源对象由植根于特定节点的子树组成。

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

运行 TranformationApp02 示例

  • 导航到samples目录.
% cd install-dir/jaxp-1_4_2-release-date/samples.
cd xslt
  • 编译TranformationApp02示例.

键入以下命令:

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

在以下情况下,在解压缩 samples 包后,在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。