到目前為止,我撰寫了很多關於 XML 及相關內容的文章和書籍,當回頭重新審視這些文字的時候,結果卻令我很吃驚。雖然我是一位程序員,喜歡深入到比特和字節(上大學的時候非常喜歡匯編語言),喜歡那種絕對控制的感覺,但總的來看,我的文章、技巧和著作關於 XML 本身討論得越來越少,關於操作 XML 的 API、包裝這些 API 的 API 以及根本不觸及 XML 的其他 API 討論得越來越多。
因此結果就是一個共性的問題:是否還記得如何實際編寫好的 XML 文檔?還知道如何區分 XML 好壞的標准麼?本文回顧了幾篇 XML 101 技巧系列的文章,希望我們在擁有各種工具的同時不會遺忘那些基本的原理。
第一步:正確使用不同的 XML 成分
最突出的顯著問題之一是 XML 作者(從寬泛的意義上講)將各種各樣的內容都填塞到元素中。屬性、處理指令 — 變成了過去時。
元素
元素在 XML 中最容易使用,很大程度上是因為 XML 作者傾向於完全 依靠元素。當然,這是錯誤 的,而且有很嚴重的副作用。XML 中的元素最適合表示具有某種層次結構或者可能 具有某種層次結構的數據(當然也有例外,不過這裡討論的是最佳用法)。首先舉一個反例,人名(不含姓和中間名等)永遠不可能有層次結構,它就是一個單詞,如此而已。但是如果選擇使用 name
元素,可能 也不錯:至少能分解成名和姓,可能還有中間名、頭銜和其他成分。因此下面這樣使用元素實際上是不正確的:
<firstName>Bob</firstName>
應該用:
<name firstName="Bob" lastName="Zemeckis" title="Mr." />
如果還不明白為何不在 name 元素中嵌套 firstName
、lastName
以及 title
元素,請仔細閱讀 上一段。下一節介紹 屬性 時還將進一步討論。
一般而言,如果一個元素不可能在文檔的同一個地方出現多次(比如可能有家庭和辦公兩個不同類型的 address
元素,圖書可能存在兩個 author
元素),則應盡量使用屬性。並不是說每次使用元素時都必須 出現兩次,僅僅是可以 出現兩次。
元素最適合文本數據這種說法也不正確,很多例子中元素只有屬性而沒有文本內容(建議閱讀討論屬性的 下一節)。最重要的是要記住 XML 不僅僅 有元素,還有其他結構。
屬性
盡管看起來像是廢話,但無論如何只能對單值數據使用 XML 屬性。比方說,如果使用關於人的元素,那些關於這個人的單值信息就是潛在的屬性。社會保障號碼、ID,可能還有出生日期 — 都是合適的候選屬性。
當然和其他規則相比,屬性規則有更多的例外。實際上,我認為屬性的應用和應該達到的程度相比少得多。開發人員往往喜歡元素比較清晰的外觀:
<person> <ssn>489098723</ssn> </person>
但是這樣做毫無意義 — 社會保障號碼絕對是單值數據。更糟的是,這樣把數字當成元素會影響性能。像這種情況下訪問元素的子元素時,必須首先取得元素節點然後遍歷所有的子元素節點。社會保障號碼可能是第一個節點,但也可能是最後一個節點,不能確定。得到那個 節點的子元素後再訪問其值,該例中包括一個文本節點。中間要經過多個步驟:
person
元素)。ssn
元素)。使用屬性的話就簡單多了:
person
元素)。ssn
)。這種方法避免了規范化(屬性只能有單一的文本值),也不需要處理子元素。我發現訪問元素的屬性幾乎總比訪問特定的子元素快。因此性能上的優勢很明顯,特別是對於成千上萬次迭代的情況。
我的觀點是,盡管看起來不太好看,XML 應這樣使用:
<person ssn="489098723" firstName="Bobby" lastName="McKenza" > <occupation> <occupation-type status="part-time" job="author" /> <occupation-type status="part-time" job="programmer" /> </occupation> <address type="home" street="112 E. Harney Way" city="New York" state="NY" zip="10012" /> <!-- etc... --> </person>
對大多數人來說可能有點奇怪,因為基本上所有信息都用屬性表示。但是我相信這種方法更好,訪問 10,000 或更多次時能夠可觀地提高效率(訪問次數多可以將細微的性能改進疊加起來)。
處理指令
通常不使用處理指令或者 PI。但是,令人苦惱的是現在很多 XML 處理 API 要求把特殊代碼或指令放在注釋中、或者使用特殊的名稱空間以及各種專用元素,甚至使用包含指令的元素。如果 XML 需要為處理 API 或者工具提供信息,這些信息就是處理指令,XML 有專門的機制。
以前肯定遇到過,特別是在 XSL 中:
<?xml version="1.0"?> <?XML-stylesheet href="classic.xsl" type="text/Html"?> <?xml-stylesheet href="alternate.xsl" type="text/XML" alternate="yes"?> <article> <!-- etc ... --> </article>
這裡 PI 告訴 XSLT 處理程序應用於 XML 文檔的樣式表在哪裡。不用考慮那些忽略該機制的 API(盡管首先想到的就是 JAXB),應該充分利用該機制,無論如何要比下面這種方法強:
<?xml version="1.0"?> <!-- XML-stylesheet url="classic.xsl" document-type="text/Html" --> <!-- xml-stylesheet url="alternate.xsl" document-type="text/XML" --> <article> <!-- etc ... --> </article>
我經常看到這樣的代碼。注釋是沒有意義的,使用注釋並將其中的信息作為指令處理的 API 是危險的。Javadoc 和文檔生成 API 使用注釋,但至少作為文檔而不是具有實際意義的指令使用。顯然,如果選擇的 API 要求這種標記,您可能繼續使用,但應該認識到這並非按照 XML 本來的方式使用 XML。我相信 XML 規范的作者在這個問題上說得很明確了。
回頁首
結束語
也許我早應該討論這些問題,但我並不是 XML 純粹論者。事實上我認為 XML 的很多東西愚蠢無聊、本末倒置或者是完全錯誤的。但是我的確 認為,既然選擇使用 XML,一些基本的概念對於正確使用是必須的,否則何必選擇 XML 呢?如果多值數據或者長數據不用元素,如果根本不使用屬性,如果濫用或者不用處理指令,某個時候就會發現最好離開 XML 去編寫自己的私有語言或解析器來處理您的數據。否則就得忍受 XML 的枷鎖 — 冗長、奇形怪狀的文檔、編碼問題等等 — 而沒有任何好處 — 專用的高速解析器。
因此不要為了正確地使用 XML 或者取悅語義主宰者而考慮這些建議。對於您的編程生涯來說這些都不是恰當的理由。如果將其看作更有效地利用 XML、提高軟件性能的辦法,就是合情合理的了。繼續前進吧,打破那些規則 —— 但必須有充分的理由!