国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 編程 > Java > 正文

Java 中的 XML:Java 文檔模型的用法

2019-11-17 06:34:03
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

簡(jiǎn)要探討 java 中不同 xml 文檔模型的工作原理

Dennis M. Sosnoski(dms@sosnoski.com)
總裁,Sosnoski Software Solutions, Inc.
2002 年 2 月

 

在本系列的第一篇文章中,我研究了一些用 Java 編寫(xiě)的主要的 XML 文檔模型的性能。但是,在開(kāi)始選擇這種類(lèi)型的技術(shù)時(shí),性能只是問(wèn)題的一部分。使用方便至少是同樣重要的,并且它已是一個(gè)主要理由,來(lái)支持使用 Java 特定的模型,而不是與語(yǔ)言無(wú)關(guān)的 DOM 。

為切實(shí)了解哪個(gè)模型真正的作用,您需要知道它們?cè)诳捎眯猿潭壬鲜侨绾闻琶摹1疚闹校覍L試進(jìn)行這個(gè)工作,從樣本代碼開(kāi)始,來(lái)演示如何在每個(gè)模型中編碼公共類(lèi)型的操作。并對(duì)結(jié)果進(jìn)行總結(jié)來(lái)結(jié)束本文,而且提出了促使一種表示比另一種更輕易使用的一些其它因素。

請(qǐng)參閱以前的文章(請(qǐng)參閱參考資料或本文“內(nèi)容”下的便捷鏈接)來(lái)獲取這個(gè)對(duì)比中使用的各個(gè)模型的背景資料,包含實(shí)際的版本號(hào)。還可以參閱“參考資料”一節(jié)中關(guān)于源代碼下載、到模型主頁(yè)的鏈接以及其它相關(guān)信息。

代碼對(duì)比
在對(duì)不同文檔表示中用法技術(shù)的這些對(duì)比中,我將顯示如何在每種模型中實(shí)現(xiàn)三種基本操作:

  • 根據(jù)輸入流構(gòu)建文檔
  • 遍歷元素和內(nèi)容,并做一些更改:
    • 從文本內(nèi)容中除去前導(dǎo)和尾隨的空白。
    • 假如結(jié)果文本內(nèi)容為空,就刪除它。
    • 否則,將它包裝到父元素的名稱(chēng)空間中一個(gè)名為“text”的新元素中。
  • 將已修改的文檔寫(xiě)入輸出流

這些示例的代碼是以我在上篇文章中使用的基準(zhǔn)程序?yàn)榛A(chǔ)的,并進(jìn)行了一些簡(jiǎn)化。基準(zhǔn)程序的焦點(diǎn)是為了顯示每個(gè)模型的最佳性能;對(duì)于本文,我將嘗試顯示在每種模型中實(shí)現(xiàn)操作的最簡(jiǎn)便方法。

我已經(jīng)將每個(gè)模型的示例結(jié)構(gòu)化為兩個(gè)獨(dú)立的代碼段。第一段是讀取文檔、調(diào)用修改代碼和編寫(xiě)已修改文檔的代碼。第二段是真正遍歷文檔表示和執(zhí)行修改的遞歸方法。為避免分散注重力,我已在代碼中忽略了異常處理。

您可以從本頁(yè)底部參考資料一節(jié)鏈接到下載頁(yè),以獲取所有樣本的完整代碼。樣本的下載版本包括一個(gè)測(cè)試驅(qū)動(dòng)程序,還有一些添加的代碼用于通過(guò)計(jì)算元素、刪除和添加的個(gè)數(shù)來(lái)檢查不同模型的操作。

即使您不想使用 DOM 實(shí)現(xiàn),但還是值得瀏覽下面對(duì) DOM 用法的描述。因?yàn)?DOM 示例是第一個(gè)示例,所以與后面的模型相比,我用它來(lái)探究有關(guān)該示例的一些問(wèn)題和結(jié)構(gòu)的更具體信息。瀏覽這些內(nèi)容可以補(bǔ)充您想知道的一些細(xì)節(jié),假如直接閱讀其它模型之一,那么將錯(cuò)過(guò)這些細(xì)節(jié)。

DOM
DOM 規(guī)范涵蓋了文檔表示的所有類(lèi)型的操作,但是它沒(méi)有涉及例如對(duì)文檔的語(yǔ)法分析和生成文本輸出這樣的問(wèn)題。包括在性能測(cè)試中的兩種 DOM 實(shí)現(xiàn),Xerces 和 Crimson,對(duì)這些操作使用不同的技術(shù)。清單 1 顯示了 Xerces 的頂級(jí)代碼的一種形式。

清單 1. Xerces DOM 頂級(jí)代碼
 1  // parse the document from input stream ("in") 2  DOMParser parser = new DOMParser(); 3  parser.setFeature("http://xml.org/sax/features/namespaces", true); 4  parser.parse(new InputSource(in)); 5  Document doc = parser.getDocument(); 6  // recursively walk and modify document 7  modifyElement(doc.getDocumentElement()); 8  // write the document to output stream ("out") 9  OutputFormat format = new OutputFormat(doc);10  XMLSerializer serializer = new XMLSerializer(out, format);11  serializer.serialize(doc.getDocumentElement());

正如我在注釋中指出的,清單 1 中的第一塊代碼(第 1-5 行)處理對(duì)輸入流的語(yǔ)法分析,以構(gòu)建文檔表示。Xerces 定義了 DOMParser 類(lèi),以便從 Xerces 語(yǔ)法分析器的輸出構(gòu)建文檔。InputSource 類(lèi)是 SAX 規(guī)范的一部分,它能適應(yīng)供 SAX 分析器使用的幾種輸入形式的任何之一。通過(guò)單一調(diào)用進(jìn)行實(shí)際的語(yǔ)法分析和文檔構(gòu)造,假如成功完成了這一操作,那么應(yīng)用程序就可以檢索并使用已構(gòu)造的 Document

第二個(gè)代碼塊(第 6-7 行)只是將文檔的根元素傳遞給我馬上要談到的遞歸修改方法。這些代碼與本文中所有文檔模型的代碼在本質(zhì)上是相同的,所以在剩余的示例中我將跳過(guò)它,不再做任何討論。

第三個(gè)代碼塊(第 8-11 行)處理將文檔作為文本寫(xiě)入輸出流。這里,OutputFormat 類(lèi)包裝文檔,并為格式化生成的文本提供了多種選項(xiàng)。XMLSerializer 類(lèi)處理輸出文本的實(shí)際生成。

Xerces 的 modify 方法只使用標(biāo)準(zhǔn) DOM 接口,所以它還與任何其它 DOM 實(shí)現(xiàn)兼容。清單 2 顯示了代碼。

清單 2. DOM Modify 方法
 1  PRotected void modifyElement(Element element) { 2    // loop through child nodes 3    Node child; 4    Node next = (Node)element.getFirstChild(); 5    while ((child = next) != null) { 6      // set next before we change anything 7      next = child.getNextSibling(); 8      // handle child by node type 9      if (child.getNodeType() == Node.TEXT_NODE) {10        // trim whitespace from content text11        String trimmed = child.getNodeValue().trim();12        if (trimmed.length() == 0) {13          // delete child if nothing but whitespace14          element.removeChild(child);15        } else {16          // create a "text" element matching parent namespace17          Document doc = element.getOwnerDocument();18          String prefix = element.getPrefix();19          String name = (prefix == null) ? "text" : (prefix + ":text");20          Element text = 21            doc.createElementNS(element.getNamespaceURI(), name);22          // wrap the trimmed content with new element23          text.appendChild(doc.createTextNode(trimmed));24          element.replaceChild(text, child);25        }26      } else if (child.getNodeType() == Node.ELEMENT_NODE) {27        // handle child elements with recursive call28        modifyElement((Element)child);29      }30    }31  }

清單 2 中顯示的方法所使用的基本方法與所有文檔表示的方法相同。 通過(guò)一個(gè)元素調(diào)用它,它就依次遍歷那個(gè)元素的子元素。假如找到文本內(nèi)容子元素,要么刪除文本(假如它只是由空格組成的),要么通過(guò)與包含元素相同的名稱(chēng)空間中名為“text”的新元素來(lái)包裝文本(假如有非空格的字符)。假如找到一個(gè)子元素,那么這個(gè)方法就使用這個(gè)子元素,遞歸地調(diào)用它本身。

對(duì)于 DOM 實(shí)現(xiàn),我使用一對(duì)引用:childnext 來(lái)跟蹤子元素排序列表中我所處的位置。在對(duì)當(dāng)前子節(jié)點(diǎn)進(jìn)行任何其它處理之前,先裝入下個(gè)子節(jié)點(diǎn)的引用(第 7 行)。這樣做使得我能夠刪除或替代當(dāng)前的子節(jié)點(diǎn),而不丟失我在列表中的蹤跡。

當(dāng)我創(chuàng)建一個(gè)新元素來(lái)包裝非空白的文本內(nèi)容(第 16-24 行)時(shí),DOM 接口開(kāi)始有點(diǎn)雜亂。用來(lái)創(chuàng)建元素的方法與文檔關(guān)聯(lián)并成為一個(gè)整體,所以我需要在所有者文檔中檢索當(dāng)前我正在處理的元素(第 17 行)。我想將這個(gè)新元素放置在與現(xiàn)有的父元素相同的名稱(chēng)空間中,并且在 DOM 中,這意味著我需要構(gòu)造元素的限定名稱(chēng)。根據(jù)是否有名稱(chēng)空間的前綴,這個(gè)操作會(huì)有所不同(第 18-19 行)。利用新元素的限定名稱(chēng),以及現(xiàn)有元素中的名稱(chēng)空間 URI,我就能創(chuàng)建新元素(第 20-21 行)。

一旦創(chuàng)建了新元素,我只要?jiǎng)?chuàng)建和添加文本節(jié)點(diǎn)來(lái)包裝內(nèi)容 String,然后用新創(chuàng)建的元素來(lái)替代原始文本節(jié)點(diǎn)(第 22-24 行)。

清單 3. Crimson DOM 頂級(jí)代碼
 1  // parse the document from input stream 2  System.setProperty("javax.xml.parsers.DocumentBuilderFactory", 3      "org.apache.crimson.jaXP.DocumentBuilderFactoryImpl"); 4  DocumentBuilderFactory dbf = DocumentBuilderFactoryImpl.newInstance(); 5  dbf.setNamespaceAware(true); 6  DocumentBuilder builder = dbf.newDocumentBuilder(); 7  Document doc = builder.parse(in); 8  // recursively walk and modify document 9  modifyElement(doc.getDocumentElement());10  // write the document to output stream11  ((XmlDocument)doc).write(out);

清單 3 中的 Crimson DOM 示例代碼使用了用于語(yǔ)法分析的 JAXP 接口。JAXP 為語(yǔ)法分析和轉(zhuǎn)換 XML 文檔提供了一個(gè)標(biāo)準(zhǔn)化的接口。本示例中的語(yǔ)法分析代碼還可以用于 Xerces(對(duì)文檔構(gòu)建器類(lèi)名稱(chēng)的特性設(shè)置有適當(dāng)?shù)母模﹣?lái)替代較早給定的 Xerces 特定的示例代碼。

在本示例中,我首先在第 2 行到第 3 行中設(shè)置系統(tǒng)特性來(lái)選擇要構(gòu)造的 DOM 表示的構(gòu)建器工廠(chǎng)類(lèi)(JAXP 僅直接支持構(gòu)建 DOM 表示,不支持構(gòu)建本文中討論的任何其它表示)。僅當(dāng)想選擇一個(gè)要由 JAXP 使用的特定 DOM 時(shí),才需要這一步;否則,它使用缺省實(shí)現(xiàn)。出于完整性起見(jiàn),我在代碼中包含了設(shè)置這個(gè)特性,但是更普遍的是將它設(shè)置成一個(gè) JVM 命令行參數(shù)。

接著我在第 4 行到第 6 行中創(chuàng)建構(gòu)建器工廠(chǎng)的實(shí)例,對(duì)使用那個(gè)工廠(chǎng)實(shí)例構(gòu)造的構(gòu)建器啟用名稱(chēng)空間支持,并從構(gòu)建器工廠(chǎng)創(chuàng)建文檔構(gòu)建器。最后(第 7 行),我使用文檔構(gòu)建器來(lái)對(duì)輸入流進(jìn)行語(yǔ)法分析并構(gòu)造文檔表示。

為了寫(xiě)出文檔,我使用 Crimson 中內(nèi)部定義的基本方法。不保證在 Crimson 未來(lái)版本中支持這個(gè)方法,但是使用 JAXP 轉(zhuǎn)換代碼來(lái)將文檔作為文本輸出的替代方法需要諸如 Xalan 那樣的 XSL 處理器的。那超出了本文的范圍,但是要獲取具體信息,可以查閱 Sun 中的 JAXP 教程。

JDOM


發(fā)表評(píng)論 共有條評(píng)論
用戶(hù)名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 灵武市| 柏乡县| 田阳县| 上蔡县| 郸城县| 无为县| 搜索| 大英县| 宝山区| 邛崃市| 台北市| 辽宁省| 田林县| 江永县| 平南县| 常德市| 中牟县| 文昌市| 灵璧县| 铜川市| 平南县| 乐亭县| 富宁县| 沂水县| 宁夏| 成武县| 苍梧县| 客服| 房产| 嘉荫县| 芜湖县| 浦县| 新安县| 湘潭市| 涡阳县| 尖扎县| 齐河县| 巫山县| 平和县| 普洱| 阜南县|