In 清单 2 中,可以看到对于每个作为自变量传递的 XML schema,main 方法都调用生成过程。首先,方法会生成类。将文件名转换为 URL,并传递到 generateClasses(URL schemaURL)。然后,通过 writeClasses(File dir) 方法将类写到当前目录中(转换成 Java File: new File("."))。
任何其它 Java 类都可以在运行时进行相同的调用,并生成类。例如,一个定制类装入器也许能发现需要打包,确定仍要生成的接口和实现,并使用 SchemaMapper 类来执行该任务。所有这一切都在运行时完成。因为 generateClasses() 方法需要一个 URL,所以在网络上使用这个类非常简单。例如,可以使用它来请求从 HTTP 上公开可用的 XML schema 生成类。
由于对如何使用类做了尽量少的假设,因此它是一个普通类;程序可以同时在本地和远程使用它。并且这个类可以当作一组 Java 语言和 XML 实用程序类的一部分,而不是必须以某种特殊形式使用的专用类。这种可重用性原则对 XML 特别关键,因为在不同系统上进行网络访问和通信是 XML 的基本前提。
生成类
构建好类的框架后,就可以添加类的主体了。
我已经提到过生成过程具有递归性质。请记住这一点,需要填充 generateClasses() 方法才能开始。可以使用 JDOM 读取 XML schema,然后从 schema 中抽取每个 complexType 元素。对于这些元素中的每一个,如清单 3 所示,递归进程从 handleComplexType() 调用处开始(以后将进一步讨论)。
清单 3. The generateClasses() 方法
public void generateClasses(URL schemaURL) throws IOException {
/**
* Create builder to generate JDOM representation of XML Schema,
* without validation and using Apache Xerces.
*/
SAXBuilder builder = new SAXBuilder();
try {
Document schemaDoc = builder.build(schemaURL);
// Handle complex types
List complexTypes = schemaDoc.getRootElement()
.getChildren("complexType",
schemaNamespace);
for (Iterator i = complexTypes.iterator(); i.hasNext(); ) {
// Iterate and handle
Element complexType = (Element)i.next();
handleComplexType(complexType);
}
} catch (JDOMException e) {
throw new IOException(e.getMessage());
}
}
为简便起见,将强调一些重点,而不是详细阐述将 schema 转换为 Java 类的整个过程。可以联机查看完整的 SchemaMapper 类,或者可以下载它。
生成器必须确定在 XML schema 中找到的每个 complexType 元素是显式的(具有“类型”属性),还是隐式的(没有“类型”属性)。如果类型是显式的,则类型将成为接口名称,并且首字母大写。如果类型是隐式的,那么将根据特性名称构造接口名称。清单 4 中显示了处理这个逻辑的代码段。(如要了解更多数据绑定的定义,请参阅侧栏,术语解释。)
清单 4. 确定接口名称 // Determine if this is an explict or implicit type
String type = null;
// Handle extension, if needed
String baseType = null;
try {
// Assume that we are dealing with an explicit type
type = complexType.getAttribute("name")
.getValue();
} catch (NoS