第四章 路徑表示式檢索實作說明
第二節 一般路徑檢索(General Path Query)
這 類 的 檢 索 支 援 了 萬 用 字 元(Wild Cards)與 常 規 表 示 式 (Regular Expressions),因此在路徑條件的檢索上比Simple Path Query來的強大。對於萬 用字元,我們實作了「%」與「#」的功能,其中「%」的意義如同Simple Path Query 的近似搜尋,但情況發生於元素節點上,如圖 13 中的節點 PLAYER 下有兩個 子節點為 SURNAME 與 G_NAME,當路徑條件下某個節點為%NAME 時,則 SURNAME 與 G_NAME 皆會被挑出以進行路徑比對。而另一個符號「#」則表 示從某個節點開始,中間可經過0個以上的節點以到達另一個節點,「#」符號常 用 在 使 用 者 不 知 道 文 件 結 構 的 情 況 下 。 如 路 徑 條 件
「SEASON.#.PLAYER.G_NAME」則表示從節點「SEASON」開始,不管中間經 過幾個節點,只要最後節點路徑為「PLAYER.G_NAME」即滿足條件。
至於常規表示式,我們實作了Optional Node —「(.node)?」的功能,表示路 徑 中 可 出 現 0 次 或 1 次 的 「node」 節 點 。 舉 例 來 說 , 若 路 徑 條 件 為
「PLAYER(.NAME)?.G_NAME」, 則 進 行 路 徑 檢 索 時 , 須 比 對 兩 個 路 徑
「PLAYER.NAME.G_NAME」或「PLAYER.G_NAME」是否滿足條件。下列即 對「#」、「%」與「(.node)?」三種功能之演算法做說明。
IF (pathNodeElement = ){
// 取出 queryPath 中 wildcard 前的 Element 節點資訊
nodeElementBfWildCard = GetElementBfWildCard(queryPath);
// 透過 DID 與 UID 來找出其父節點資訊,直到父節點與WildCard 前 的節點資訊相同時再做最後的 PathCheck
While (nodeValue != nodeElementBfWildCard){
IF (nodeValue = elmSelectPattern){ //判斷是否為欲挑選的節點 //若 matchedEleSeqId 中沒出現過 node SeqId
//則將 nodeSeqId 加入 matchedEleSeqId
IF (!CheckContain(matchedEleSeqId, nodeSeqId)) matchedEleSeqId.addElement(nodeSeqId);
}
pUID = (UID-2)/MaxBranch + 1;
ResultSet node = SelectNode(DID, pUID);
nodeSeqId = node.getBigDecimal("seqId");
nodeValue = node.getString("value");
}
subPath = GetSubQueryPathBfWildCard(queryPath);
PathCheck(DID, pUID, subPath, elmtPattern);
}
"#"
圖 18:WildCardOperation("#") 路徑檢查演算法
若路徑條件為「SEASON.LEAGUE.#.G_NAME」,當進行路徑比對中發現目 前的節點為「#」時,此時將萬用字元前的節點以 nodeElementBfWildCard 記錄 之,接著遞迴進行上層父節點比對直到該節點為萬用字元前的節點後,再做最後 的路徑比對以檢查是否滿足路徑條件。往上層父節點尋找的過程中,若有出現欲 挑選的節點時,則須將節點的SeqId記錄之。以前述之路徑條件而言,以下即為 處理符號「#」的步驟:
1. 開始進行路徑比對時,由滿足檢索條件值的 UID 得知其父節點為 G_NAME,路徑條件中最外部的節點確實為 G_NAME。滿足路徑條件 後繼續進行上一層路徑「SEASON.LEAGUE.#」比對。
2. 出現符號「#」,此時nodeElementBfWildCard設為LEAGUE。接著由節 點G_NAME之UID往上層父節點推導,直到節點為LEAGUE止。
3. 接著,再由節點LEAGUE進行更上層路徑「SEASON.LEAGUE」比對。
「%」:演算法如圖 19 所示。
IF (percentOccur){
IF (percentAtHead) {
//WildCard %出現在 Element 首與尾,如%NAME%
pathNodeElement = RemovePercentAtHead(pathNodeElement);
IF (pathNodeElement End With percent) {
pathNodeElement = RemovePercentAtTail(pathNodeElement);
IF (nodeValue Contains Substring pathNodeElement){
//目前節點資料滿足路徑條件則繼續遞迴比較上一層父節點是否 亦滿足
pUID = (UID-2)/MaxBranch + 1;
subPath = GetSubQueryPath(queryPath);
PathCheck(DID, pUID, subPath, elmtPattern);
}
} ELSE IF (nodeValue Ends With Substring pathNodeElement){
//WildCard %出現在 Element 首,如%NAME
//目前節點資料滿足路徑條件則繼續遞迴比較上一層父節點是 否亦滿足
pUID = (UID-2)/MaxBranch + 1;
subPath = GetSubQueryPath(queryPath);
PathCheck(DID, pUID, subPath, elmtPattern);
} } ELSE {
//WildCard %出現在 Element 尾,如 NAME%
pathNodeElement = SubStringRemoveWildCard(pathNodeElement);
IF (nodeValue Begins With pathNodeElement) {
//目前節點資料滿足路徑條件則繼續遞迴比較上一層父節點是否 亦滿足
pUID = (UID-2)/MaxBranch + 1;
subPath = GetSubQueryPath(queryPath);
PathCheck(DID, pUID, subPath, elmtPattern);
} } }
19 WildCardOperation("%")
路徑比對的過程中,若路徑條件中的節點出現符號「%」時,只有當該節點 滿足近似搜尋所述的三種情況下,才會繼續進行上一層的路徑條件比對。舉例而 言,路徑條件若為「DIVISION.PLAYER.%NAME」,則開始進行路徑比對時,由 滿足檢索條件值的UID得知其父節點為G_NAME,該節點確實由NAME結尾。
因此滿足路徑條件接著繼續進行上一層路徑「DIVISION.PLAYER」比對。
「(.node)?」:演算法如圖 20 所示。
IF (questionMarkOccur){ //出現 Optional 的情況 如 a(.b)?.c //分兩種情形繼續遞迴搜尋
subPath = GetPathContainOptionalNode(queryPath);
PathCheck(DID, pUID ,subPath, elmtPattern); //Optional 的節點有出現 subPath = GetPathNotContainOptionNode(queryPath);
PathCheck(DID, pUID, subPath, elmtPattern); //Optional 的節點沒有出現 }
,
圖 20:OptionalNodeOperation( ) 路徑檢查演算法
當Optional Node的條件出現時,路徑條件將分成包含Optional Node與不包 含Optional Node的情況繼續進行上一層的路徑比對。舉例而言,假設路徑條件 為「DIVISION.PLAYER(.NAME)?.G_NAME」,當比對到節點 G_NAME 時,發 現路徑條件中出現Optional Node –「NAME」。此時,路徑條件可為兩種情形,
一條路徑為包含Optional Node,即「DIVISION.PLAYER.NAME.G_NAME」
,另一條則否,即「DIVISION.PLAYER.G_NAME」。接著再以這兩種路徑條件 個別進行路徑比對。