從XML到Java的數據綁定之三

      從文本到字節碼
  本數據綁定系列的第三部分演示瞭如何使用“JSR-031:數據綁定,Sun 數據綁定規範申請”中指定的方法,將 XML 元素和屬性轉換成 Java 對象。這部分主要講述從數據的XML 表示移到應用程序代碼易於使用的 Java 實例。第三部分論及通過將 XML 文檔中的嵌套元素取消編組成 Java 對象、測試和用某些實際示例來使用新的工具。
  本系列的目標是演示如何將 XML 元素轉換成 Java 對象,然後可以使用 Java 語言 accessor 和 mutator 方法直接處理 XML 數據。第一部分比較了數據綁定和 Java 應用程序中其它處理 XML 數據的方法,分析了設計決策,還定義了示例 Web 服務配置文檔的 XML 模式。第二部分說明了如何從 XML 模式生成接口和實現,以便符合 XML 模式的 XML 文檔可以轉換成這些生成類的實例。
  在第三部分(共四部分)中,將完成基礎知識的講解,並且描述瞭如何精心設計代碼以執行取消編組,取消編組將完成將 XML 轉換成 Java 對象的過程。執行了取消編組後,可以使用測試類(已包括在內)來檢查是否所有部分都已正確組合在一起。本系列的每一部分都建立在其它部分的基礎之上,所以如果您還沒有看過第一和第二部分,您也許會看不懂本文中的一些描述。如果要回顧專門的詞彙表,請參閱術語解釋側欄。
  使用第一部分中爲 WebServiceConfiguration 定義的 XML 模式(請參閱更新版本)和第二部分中的接口,即將創建爲配置數據的特定實例提供數據的 XML 文檔。任何符合模式的 XML 文檔都可以編組成 Java 對象。這些對象應該是使用 SchemaMapper 類生成的類的實例。當然,最終結果就是數據綁定。
  製作 XML 實例文檔
  創建符合模式的 XML 文檔 -- 通常叫做 XML 實例 -- 很簡單。文檔必須只提供與模式中定義的約束相匹配的數據值,如清單 1 所示。
  清單 1. 符合示例 XML 模式的 XML 實例文檔
  <?
xml version="1.0"?>
  <webServiceConfiguration
xmlns="http://www.enhydra.org"
         
xmlns:xsi="http://www.w3.org/1999/XMLSchema/instance"
         xsi:schemaLocation="http://www.enhydra.org
         configuration.xsd"
         version="1.1"
         name="Unsecured Web Listener" >
  <port number="80" protocol="http" protectedPort="false" />
  <document root="/usr/local/enhydra/html" index="*.html,*.
xml"       error="error.html" />
  </webServiceConfiguration>
  清單 1 中的示例完整地顯示了 WebServiceConfiguration 的實例。實例文檔包括了兩個名稱空間聲明。第一個是缺省名稱空間聲明,請參考 http://www.enhydra.org。這表示所有沒有前綴的元素會分配到此名稱空間。雖然,在本示例中不需要聲明缺省名稱空間,它還給予了文檔一些身份。這個缺省名稱空間有助於將該文檔與其它有相似或等同元素名稱的 XML 文檔區分出來。
  定義的另一個名稱空間分配給 xsi 前綴,所以帶該前綴的所有元素都分配到此名稱空間。它 (http://www.w3.org/1999/XMLSchema/instance) 引用“XML 模式實例規範”的 URI。該規範依次定義了 XML 文檔如何引用文檔符合的 XML 模式。最後,schemaLocation 屬性引用 XML 模式。該屬性的第一個變量是受到約束的名稱空間(示例缺省名稱空間,它包括文檔中的每個元素)。第二個變量,用空格與第一個變量分開,引用 XML 模式的實際位置。本例中,模式 configuration.xsd 是一個本地文件,它與文檔在同一個目錄中。也可以通過使用 URL 來引用網絡上任意位置的模式。
  在缺省名稱空間中,附加屬性(因爲它們沒有前綴)定義了版本 (1.1) 和名稱 (Unsecured Web Listener)。
  接着,聲明瞭模式中的 Port 對象,並定義了它的數據:端口號爲 80,協議是 http。正確取消編組成 Java 代碼後,該文檔就變成了 WebServiceConfigurationImpl 類的實例。然後,Java 代碼可以使用本系列第二部分中設計的接口 WebServiceConfiguration,以使用基本 XML 文檔中的數據。(請注意,可能會在應用程序中執行驗證,如模式驗證側欄中所概述的。)
  模式驗證
  較新的 XML 語法分析器,如 Apache Xerces 語法分析器的當前發行版,允許對 XML 實例文檔執行模式驗證。驗證允許在程序格式上確保 XML 文檔符合它引用的 XML 模式。請與語法分析器供應商聯繫或參考文檔,以確定語法分析器是否支持模式驗證,其驗證範圍,以及如何打開驗證。
  打開前門
  正式開始之前,需要提供入口點以取消編組 XML 文檔,該文檔作爲返回 Java 對象的方法的輸入。(由於您會憶起,本例中取消編組的結果只是 Java 對象。)然後,該對象可以轉換成適當的接口,其實,您已經生成了該接口(在本系列第二部分中)。
  對於示例 SchemaMapper 類,允許傳入 URL 是最有意義的。由於可以使用網絡資源作爲輸入,而不是隻允許文件名,這就提供了更多選擇。知道了這一點後,下一步就從 URL 創建 JDOM 文檔對象 (org.jdom.Document),然後處理文檔。請查看清單 2 中執行該操作的代碼。
  清單 2. 將字符串映射成 Java 指定的類型 /**
  *
  * This method is the public entry point for unmarshalling an object from
  * an XML instance document.
  *
  *
  * @param instanceURL URL for the instance document.
  * @return Object - the created Java Object, or
  * null if problems occur in a way that does not
  * generate an Exception.
  * @throws IOException when errors in binding occur.
  */
  public static Object unmarshall(URL instanceURL) throws IOException {
  // Read in the document
  SAXBuilder builder = new SAXBuilder();
  
  try {
  Document doc = builder.build(instanceURL);
  Element rootElement = doc.getRootElement();
  Unmarshaller unmarshaller = new Unmarshaller();
  return unmarshaller.getJavaRepresentation(rootElement);
  } catch (JDOMException e) {
  throw new IOException (e.getMessage());
  }
  }
  清單 2 中的方法是靜態的,允許直接調用它而無需實例化類的實例。由於對 unmarshall 方法的多個調用之間沒有需要共享的數據,因此該方法可以是靜態的。一旦處理了 XML,就將文檔的根元素(以 JDOM 表示)就被傳到執行從 XML 到 Java 對象轉換的內部方法。
  轉換數據
  我不打算逐行解釋取消編組中使用的完整代碼。可以查看類的完整源碼清單,它基本上是不需加以說明的。但是,在入口點示例中,有一些值得強調的事情。如果創建了適當類的新實例,將使用 XML 文檔提供的值調用 mutator 方法(全都名爲 setXXX)。當然,這將使 XML 數據在實例的 Java 方法中隨處都可用。清單 3 顯示了處理這種查找方法以及隨後調用的代碼片段。
  清單 3. unmarshaller 類的入口點
  
  // For each attribute, get its name and call mutator
  List attributes = rootElement.getAttributes();
  Method[] methods = objectClass.getMethods();
  
  for (Iterator i = attributes.iterator(); i.hasNext(); ) {
   Attribute att = (Attribute)i.next();
  
   // Only w
ant attributes for this namespace
   if ((!att.getNamespace().equals(ns)) &&
     (!att.getNamespace().equals(Namespace.NO_NAMESPACE))) {
       continue;
     }
  
   // Determine method to call
   String methodName = new StringBuffer()
        .append("set")
        .append(BindingUtils.initialCaps(att.getName()))
        .toString();
  
   // Find the method to call, and its parameter type
   for (int j=0; j
  找到了根元素的屬性,並確定了每個屬性的適用方法。然後,就是處理實際的 java.lang.reflect.Method 對象。XML 屬性的值已確定,並作爲調用的參數傳送到方法。但是,需要解決一個映射問題;XML 文檔中的所有數據都作爲 String 抽取,但傳遞時必須是適當的 Java 類型。清單 4 將一個方法添加到 DataMapping 輔助類中,以滿足轉換的需要。
  清單 4 將字符串映射成 Java 特定的類型
  /**
  *
  * This will take the String value supplied and convert it
  * to an Object of the type specified in paramType.
  *
  *
  * @param value String value to convert.
  * @param paramType Class with type to convert to.
  * @return Object - value in correct type.
  */
  public static Object getParameter(String value, Class paramType) {
  Object ob = null;
  String type = paramType.getName();
  
  if (type.equals("java.lang.String")) {
  ob = value;
  } else if ((type.equals("int")) || (type.equals("java.lang.Integer"))) {
  ob = Integer.valueOf(value);
  } else if ((type.equals("long")) || (type.equals("java.lang.Long"))) {
  ob = Long.valueOf(value);
  } else if ((type.equals("float")) || (type.equals("java.lang.Float"))) {
  ob = Float.valueOf(value);
  } else if ((type.equals("double")) || (type.equals("java.lang.Double"))) {
  ob = Double.valueOf(value);
  } els 
 
發佈了13 篇原創文章 · 獲贊 4 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章