XMLBean

XMLBean

编写使用这些接口的 Java 代码

通过在您的应用程序中使用 XMLBean 接口,可以编写使用新类型的代码,以便基于该 Schema 对 XML 进行处理。下面的示例将提取有关订购单 XML 中的每个订购商品的信息,并计算商品的数量,然后计算其价格总和。请特别注意基于 Schema 生成的类型以及作为 org.openuri.easypo 包的一部分而导入的类型的使用情况。

printItems 方法接收包含订购单 XML 文件的 File 对象。

package docs.xmlbeans;

import java.io.File;
import com.bea.xml.*;
import org.openuri.easypo.PurchaseOrderDocument;
import org.openuri.easypo.PurchaseOrder;
import org.openuri.easypo.LineItem;

public class POHandler 
{
    public static void printItems(File po) throws Exception 
    {
        /*
         * 所有 XMLBean Schema 类型都提供嵌套的 Factory 类,您可以使用它
         * 将 XML 绑定到该类型,或者创建该类型的新实例。
         * 请注意,像该类型一样的“Document”类型是 XMLBean
         * 构造,用于表示全局元素。它为您提供了一种
         * 获取和设置整个元素的内容的方法。
         *
         * 此外,只有在所解析的 XML 遵守
         * Schema 的情况下,parse 方法才会成功。
         */
        PurchaseOrderDocument poDoc =
            PurchaseOrderDocument.Factory.parse(po);

        /*
         * PurchaseOrder 类型表示 purchase-order 元素的
         * 复杂类型。
         */
        PurchaseOrder po = poDoc.getPurchaseOrder();

        /*
         * 当某个元素可能作为子元素出现多次时,
         * Schema 编译器将生成引用该元素
         * 的多个实例的方法。line-item 元素
         * 的 maxOccurs 特性值指定为“unbounded”,这意味着
         * 它可以根据需要在一个实例中出现多次。
         * 因此存在 getLineItemArray 和 setLineItemArray 等方法。 
         */
        LineItem[] lineitems = po.getLineItemArray();
        System.out.println("Purchase order has " + lineitems.length + " line items.");

double totalAmount = 0.0;
        int numberOfItems = 0;

        /*
         * 循环遍历 line-item 元素,方法是使用所生成的存取程序
         * 获取子元素的值,如 description、quantity 以及
         * price。
         */
        for (int j = 0; j < lineitems.length; j++) 
        {
            System.out.println(" Line item:" + j);
            System.out.println(
                "   Description:" + lineitems[j].getDescription());
            System.out.println("   Quantity:" + lineitems[j].getQuantity());
            System.out.println("   Price:" + lineitems[j].getPrice());
            numberOfItems += lineitems[j].getQuantity();
            totalAmount += lineitems[j].getPrice() * lineitems[j].getQuantity();
        }
        System.out.println("Total items:" + numberOfItems);
        System.out.println("Total amount:" + totalAmount);
    }
}

请注意,基于 Schema 所生成的类型反映了 XML 中的内容:

  • PurchaseOrderDocument,表示全局根元素。
  • getPurchaseOrder 方法,返回包含子元素(其中包括 line-item)的 PurchaseOrderDocument.PurchaseOrder 类型。 getLineItemArray 方法,返回包含 line-item 元素的 LineItem 数组。
  • 其他方法(如 getQuantitygetPrice 等等)是根据 Schema 的描述自然得出的,其作用是返回 line-item 元素的相应子元素。
  • 包含这些类型的包的名称是从 Schema 的目标名称空间派生得到的。

所生成的类型名称的大小写和标点符号遵从 Java 约定。此外,当该示例解析文件中的 XML 时,其他 parse 方法支持 Java InputStream 对象、Reader 对象等等。

前面的 Java 代码将在控制台中打印下列内容:

Purchase order has 3 line items.
 Line item 0
   Description:Burnham's Celestial Handbook, Vol 1
   Quantity: 2
   Price: 21.79
 Line item 1
   Description:Burnham's Celestial Handbook, Vol 2
   Quantity: 2
   Price: 19.89
Total items: 4
Total amount: 41.68

基于 Schema 创建新的 XML 实例

您已经看到 XMLBean 提供一个 "factory" 类,您可以使用该类来创建新的实例。下面的示例创建新的 purchase-order 元素,并添加 customer 子元素。然后它会插入 nameaddress 子元素,从而创建元素,并通过仅调用一次它们的 set 方法来设置它们的值。

public PurchaseOrderDocument createPO()
{
    PurchaseOrderDocument newPODoc = PurchaseOrderDocument.Factory.newInstance();
    PurchaseOrder newPO = newPODoc.addNewPurchaseOrder();
    Customer newCustomer = newPO.addNewCustomer();
    newCustomer.setName("Doris Kravitz");
    newCustomer.setAddress("Bellflower, CA");
    return newPODoc;
}

下面是生成的 XML。请注意,XMLBean 通过使用 "ns1"(或 "namespace 1")前缀,并基于 Schema 来分配正确的名称空间。在实际工作中,前缀本身并不是真的很重要,它只是用来定义名称空间的名称空间 URI (http://openuri.org/easypo)。前缀仅仅是表示它的一个标记。

<ns1:purchase-order xmlns:ns1="http://openuri.org/easypo">
    <ns1:customer>
        <ns1:name>Doris Kravitz</ns1:name>
        <ns1:address>Bellflower, CA</ns1:address>
    </ns1:customer>
</ns1:purchase-order>

请注意,所有类型(包括基于 Schema 生成的类型)都是对 XmlObject 的继承,因此都提供了 Factory 类。有关适合使用 XmlObject 的类型系统的概述,请参阅 XMLBean 对内置 Schema 类型的支持。有关参考信息,请参阅 XmlObject Interface。

XMLBean 层次

上面的示例中使用的生成类型实际上是 XMLBean 类型的层次的一部分。这种层次是 XMLBean 用来直观展现 Schema 视图的一种方法。层次的顶部是 XmlObject,即 XMLBean 类型的基础接口。在该级别的下面,有两个主要的类型类别:生成类型(表示用户派生的 Schema 类型)和包括类型(表示内置 Schema 类型)。

本主题已介绍了生成类型。有关详细信息,请参阅 从用户派生的 Schema 类型生成的 Java 类型。

内置类型支持

除了基于指定的 Schema 所生成的类型以外,XMLBean 还提供了 46 种特别的 Java 类型,这些类型是对 XML Schema 规范所定义的 46 种内置类型的镜像。例如,Schema 定义了 xs:stringxs:decimalxs:int,而 XMLBean 提供了 XmlStringXmlDecimalXmlInt。其中的每个类型也是继承自 XmlObject,该类型与内置 Schema 类型 xs:anyType 对应。

通过 XMLBean,您就可以将 XML 数据作为这些内置类型进行处理。如果您的 Schema 包括一个类型为 xs:int 的元素,XMLBean 将提供一个可以返回 XmlInt 的生成方法。此外,就像您在前面的示例中所看到的,对于大多数类型来说,还将有一个返回纯 Java 类型(如 int)的方法。下面的两行代码返回 quantity 元素的值,但将其作为其他类型返回。

// 返回以“x”开头的简单类型的方法。
XmlInt xmlQuantity = lineitems[j].xgetQuantity();
// 返回纯 Java 类型的方法。
int javaQuantity = lineitems[j].getQuantity();

在某种意义上,这两种 get 方法均导航至 quantity 元素;getQuantity 方法更深入一步,在返回元素值之前,将其转换为最适合的纯 Java 类型。(XMLBean 还为您提供了一种在使用 XML 的同时对它进行验证的方法。)

如果您对 XML Schema 有所了解,那么您会觉得 XMLBean 类型看起来非常直观。如果您对 XML Schema 知之甚少,可以使用您自己的 Schema 以及基于它们的 XML 实例来对 XMLBean 进行试验,以了解详细的信息。

有关基于 Schema 生成的类型的方法的详细信息,请参阅 从 Schema 生成的类型的方法。有关 XMLBean 如何表示内置 Schema 类型的详细信息,请参阅 XMLBean 对内置 Schema 类型的支持。

使用 XQuery 表达式

使用 XMLBean,可以通过 XQuery 查询 XML 中特定的数据块。XQuery 有时也称为“用于 XML 的 SQL”,因为它提供了一种直接从 XML 文档访问数据的机制,这与 SQL 所提供的、访问传统数据库数据的机制十分类似。

XQuery 的一些语法是从 XPath 借鉴来的,后者是一种用于在 XML 中指定嵌套数据的语法。下面的示例返回 price 子元素的值小于或等于 20.00 的所有 line-item 元素:

PurchaseOrderDocument doc = PurchaseOrderDocument.Factory.parse(po);

/*
 * XQuery 表达式是由下面两个字符串组成的。为方便起见,
 * 在这里分别对它们进行声明。第一个字符串声明
 * 在查询表达式中使用的名称空间前缀;第二个字符串
 * 声明表达式本身。
 */
String nsText = "declare namespace po = 'http://openuri.org/easypo'";
String pathText = "$this/po:purchase-order/po:line-item[po:price <= 20.00]";
String queryText = nsText + pathText;

XmlCursor itemCursor = doc.newCursor().execQuery(queryText);
System.out.println(itemCursor.xmlText());

上述代码在文档的开头创建一个新的光标。从那里,它使用 XmlCursor 接口的 execQuery 方法执行查询表达式。在本例中,该方法的参数是 XQuery 表达式,该表达式仅仅指出“从我当前的位置,在 purchase-order 元素中导航,并检索值小于或等于 20.00 的那些 line-item 元素”。$this 变量意味着“当前的位置”。

有关 XQuery 的详细信息,请参阅 W3C 网站中的 XQuery 1.0:An XML Query Language。

使用 XML 光标

在前面的示例中,您可能已经注意到 XmlCursor 接口。除了提供一种执行 XQuery 表达式的方法外,XML 光标还提供一种用于操作数据的细粒度模型。XML 光标 API 与 DOM 的对象 API 类似,它只是一种指向特定数据块的方式。因此,就像光标有助于在字处理文档中导航一样,XML 光标则定义了 XML 中的一个位置,您可以在该位置对选定的 XML 执行操作。

当没有可用的 Schema 时,光标是一种在 XML 文档中移动的理想方法。一旦光标到达了您需要的位置,您就可以使用它执行各种操作。例如,可以设置和获取值、插入和删除 XML 的片段、将 XML 的片段复制到文档的其他部分,以及对 XML 文档进行其他细粒度更改。

下面的示例使用 XML 光标导航到 customer 元素的 name 子元素。

PurchaseOrderDocument doc = 
    PurchaseOrderDocument.Factory.parse(po);

XmlCursor cursor = doc.newCursor();
cursor.toFirstContentToken();
cursor.toFirstChildElement();
cursor.toFirstChildElement();
System.out.println(cursor.getText());

cursor.dispose();

上述代码执行了哪些操作呢?与前面的示例一样,代码加载 File 对象中的 XML。加载文档之后,代码在它的起始位置处创建一个光标。移动光标几次,使它到达嵌套的 name 元素。一旦光标到达该元素,getText 方法便会检索该元素的值。

你可能感兴趣的:(XMLBean)