top
Loading...
XML介紹系列篇九
XML介紹系列之十七---如何使用XSL和正則表達式來驗證數據的有效性(一)

翻譯:Batman
系列之十七:如何使用XSL和正則表達式來驗證數據的有效性
XSL現在正在逐漸的成為XML中的類似與SQL在數據庫設計中的地位。
雖然Microsoft's XSL僅僅是實現了其中的某一些部分的功能
但是你已經能夠實現非常復雜的查詢了
雖然現在的XSL僅僅還只是一種基于純粹文本和字符串方式
的查詢語言
在下面介紹的例子中,將大量使用到文本內的字符串方式的搜索,
你會發現在XML中對數據的處理很大一部分都是要使用到文本內的查詢的。
這在XSL的編寫中是一件非常普及的功能。
正是因為這樣,你應該了解一些正則表達式應該如何來使用。

正則表達式的簡單介紹
正則表達式大部分都是來自與Unix世界的需要。
在Unix中許多編程語言幾乎整個都是圍繞著正則表達式進行的(例如Perl, Python, Tcl)
但是令人感到奇怪的是正則表達式好象是最近才使用在Windows系列中的,
特別是大量的使用在腳本語言中,例如JavaScript和VBScript,
盡管你也可以將它們使用在Visual Basic或則Java中,但是顯然它們似乎在
腳本語言中更加有吸引力。也許是這個緣故把,大家平時似乎都很少使用正則表達式把。

使用正則表達式,你可以根據你想查詢的內容建立一個匹配模板(英文叫pattern)
一旦你使用正則表達式建立了一個模板,你就可以使用它來測試你的字符串了,
使用它可以完成很多功能:
例如判斷一個字符串是否在另外一個字符串中(或則在另外一個字符串中的什么位置)
例如使用一個字符串來替換另外一個字符串
例如返回所有滿足模板條件的字符串列表
例如。。。等等等等

上面我介紹了有關正則表達式的基本概念,有關它的詳細說明和語法可以查閱MSDN和
JavaScript中的有關幫助。
在VB中如果你想引用正則表達式的話,你需要在項目中引用"Microsoft VBScript Regular Expressions"。但是如果你要是使用腳本的話就不必要了,因為在腳本里面這已經是一個
內在的對象供你引用了。
當然你需要在你的機器上安裝IE4以上羅。
這個對象(在JavaScript中)叫RegExp
下面還是讓代碼來說明問題把,現在假設你想查看一個文擋里面是否包含一個特定的
字符串(例如"regular expressions")
代碼見下:
代碼使用VB寫成。
Public Function IsTermInDocument(filePath As String,_
expr As String) As Boolean
Dim fs As FileSystemObject
Dim ts As TextStream
Dim re As RegExp
Dim text As String

Set fs = New FileSystemObject
Set ts = fs.OpenTextFile(filePath, ForReading)
text = ts.ReadAll
Set re = New RegExp
re.Pattern = expr
IsTermInDocument = re.Test(text)
End Function

Debug.print IsTermInDocument("c:inmyPage.htm",_
"regular expression")
上面的那個函數將根據文擋里面是否有滿足條件的字符串返回True/False.
注意我加粗的部分:
第一句是建立一個正則表達式的對象
第二句是指定該正則表達式的模板
第三句就是根據模板執行查詢了
呵呵,如果正則表達式的功能僅僅是這么簡單的話,也許你會說
VB中的instr()不就能夠代替了嗎?

但是,在進行XML的數據格式化的時候,對字符串的處理遠比這個復雜得多。
例如:假設你要確保你要驗證的字段中是否包含一個well-formed的zip編碼
(well-formed意味著它是一個有效的編碼,
也許它對于某個給定的地方或則區域或則國家又是無效的
這種界于well-formed和valid的表達式將是本文里面討論的重點)
如果你要是使用VB來進行這種判斷的話將非常的難看
你需要判斷是否表達式有5位或則10位數字,或則是否為字母,
然后第6位字母又必須得是一個破則號
但是如果是使用正則表達式的話,將會是這樣的簡單:

Set IsZipCode = New RegExp
IsZipCode.Pattern = "^d{5}(-d{4})?$"
if IsZipCode.test("32545-2198") then

下面將簡單解釋一下其中模板的含義:
^ 說明在這個表達式之前沒有任何其它的字符串,
意味著要驗證的表達式不是某個字符串中間的一部分,而是它的開頭
d 表示下一個字符必須是0-9中的一個數字
d{5} 并且必須是連著的5個數字
-d{4} 4個數字必須出現在字符"-"的后面
(-d{4})? 這4個數字是可選的,即可有也可以沒有
$ 這個表達式后面應該不會再有其它的什么東西了

最有意思的是一旦你定義好了這么一個模板,你就可以將它使用在
任何其它的正則表達式對象中,而不需要再重新建立一個正則表達式對象了了。
使用這個辦法,你甚至可以把一個近2000行代碼的JavaScript程序
減少到只有幾百行,設置當你把一些模板組合在一起的時候,就能夠完成
正則表達式本來不可能完成的東東了。

下面我再舉一個用來驗證數據有效性的例子:
例如你現在想驗證一個電話號碼數據是否有效
對于通用一個電話號碼一般下面這幾種寫法都是有效的:
(800)555-1212
1(800) 555-1212
1-800-555-1212
1.800.555.1212
等等.

如果你使用腳本來寫一段滿足上面所有要求的代碼將非常的復雜。
但是如果你使用正則表達式的話,將非常的簡單,只有下面這兩句代碼:
Set IsPhoneNumber=new RegExp
IsPhoneNumber.pattern="^[01]?s*[(.-]?(d{3})[).-]?s*(d{3})[.-](d{4})$"

你可以仔細體會上面這個代碼的意義。
首先它驗證第一個字符是否為0或則是否為1或則根本就沒有。
然后再進行下面的驗證,大家可以自己琢磨其它部分的意思把,呵呵。

查詢和替換數據
當然,驗證數據的有效性僅僅是它能夠做的一件小事而已,
但是更有用的是:如果你能夠把上面那么多種電話號碼的表達方式轉換
成一種統一的方式顯示出來。
例如我要把上面的電話號碼格式化成XML中的一個片段如下:

<phoneNumber>
<areacode>123</areacode>
<exchange>456</exchange>
<local>7890</local>
</phoneNumber>

這時的電話號碼的模板分成三個部分:
(d{3}), (d{3}), (d{4}), 分別表示area code, exchange, 和local number
. 在正則表達式中,正則解釋器會自動
將匹配的字符賦值給變量 $1, $2, $3,等.
這樣你使用下面的代碼就能夠實現

re.Replace("1(352)351-4159", "<phoneNumber><areacode>$1</areacode><exchange>$2</exchange><local>$3</local></phoneNumber>")

如果你覺得這個Replace使用起來很不舒服的話,下面將給出一個
類似與VB中的Replace并且擴展了它的函數

Public Function Replacex(sourceStr as String, oldStr as _
String, newStr as String, optional ignoreCase as _
Boolean = False,optional isGlobal as Boolean = True)
Dim re As New RegExp
re.Pattern = oldStr
re.Global = isGlobal
re.IgnoreCase = ignoreCase
Replacex = re.Replace(sourceStr, newStr)
End Function

下面給出使用它的一些例子:
Debug.Print Replacex("This is a test","is","at")
--> "That at a test"
最精彩的還是使用正則表達式了
Debug.Print Replacex("This is a test","ws","at")
--> "That at a tatt"
甚至還可以這樣
Debug.Print Replacex("This is a test","(ws)","at$1")
--> "Thatis atis a tatist"

正則表達式的replace方法還有兩個參數。
在默認的情況時正則表達式在找到了一個滿足條件的時候就會停下來
但是如果你要是將isGlobal參數設置為True的話,它就會全文替換
在默認的情況下正則表達式是區分大小寫的
但是如果你將ignoreCase設置為False的話,它將不區分大小寫

獲得XML的節點
現在,我們將一起來看看正則表達式在XML中是如何運用的。
首先,在Microsoft's XML 2.0解釋器里面有兩大難題:
第一, 這個XML解釋器在裝載XML文擋的時候必須要保證入口
滿足定義在DTD的范圍之內。這是一個大麻煩,因為就目前的情況來看,
XML更改頻繁,不時會多出一些標準,不時又會產生新的標志。
第二,如果使用XSL的話不能夠操縱DTD,甚至當你使用腳本語言也是一件很費力的事情。
經常要做的是你需要在XSL使用XSL的結構表達式中設置一些變量,例如
瀏覽器的類型或則ASP的參數呀
這時你可以使用正則表達式來解決這些問題。
當你想獲取一個XML元素的時候,也許這個對象有可能并不是你想要的東東。
例如:假設一個很簡單的XML結構,一個圖書目錄.
XML的代碼如下:
<catalog>
<book>
<title>XML for Beginners</title>
<author>Fred Fnord</author>
<description>A book on XML for programming neophytes.</description>
</book>
<book>
<title>Pair-O-Dice Lost</title>
<author>U. Wajer</author>
<description>Techniques for throwing the game.</description>
</book>
<book>
<title>The Fields of Oberon</title>
<author>Alan Landis</author>
<description>The wee folk are back, and they aren't happy.</description>
</book>
<book>
<title>Distributed Computing on a Budget</title>
<author>Fred Fnord</author>
<description>Using XML and related techniques for managing distributed applications.</description>
</book>
</catalog>