CMarkup定位解釋 深入Markup分析器

2021-04-13 13:54:34 字數 4402 閱讀 1893

cmarkup定位解釋

三年前,我寫過一篇關於

cmarkup

定位的解釋,現在我用這篇文章代替那篇。

int nstart;

int nlength;

int ntaglengths;

int nflags;

int ielemparent;

int ielemchild;

int ielemnext;

int ielemprev;

前三個整數告訴我們了在文件中,元素的起始位置,它的長度以及開始和結束標籤的長度,因為

nstart

是乙個32bit

的整數,所以文件

的最大尺寸可以有

2g,並且同樣,最大元素的長度是一樣的。整數

ntaglengths

被分成兩部分,

22bit(4m)

用於開始標籤(開始標籤可以包含屬性),另外

10bit(1k

)用於結束標籤。在下列元素中,開始標籤的長度是

14,結束標籤是

8.,整個元素的長度是29.

<

topic id

="5">triumph

topic

>

整數nflags

的低16

位實際儲存的是元素的深度或層次,高

16位是特殊標識。根元素是

0層,根元素的孩子是

1層等等

,特殊標識告訴我們元素是第乙個兄弟或最後乙個兄弟、或空元素、以及如果這個元素已經被刪除了(這樣的結構能夠被恢復) 四個

ielem

ielemparent

指向父元素,

ielemchild

指向第乙個子元素,

ielemnext

指向下乙個元素,當這個元素是最後乙個兄弟時,

ielemnext是0

,當元素不是第乙個兄弟元素時,

ielemprev

指向其前乙個兄弟元素,如果元素是第乙個兄弟元素,

ielemprev

指向最後乙個兄弟元素。因此,順著

ielemchild

的鏈結以及從那裡沿著

ielemprev

的鏈結,可以得到父元素的最後乙個子元素。

如果你熟悉像這樣用樹結點鏈結在一起的工作方式,你將明白這個地圖的效果。這個設計對於樹層次的回來操作是有效的,再通過兄弟元素形成乙個環,但是,對於隨機訪問第

n個子元素將需要先迴圈這個元素之前的所有兄弟元素。一旦被建立起來,在文件中隨意的導航將不再需要費時的分析。

當乙個文件被分析時,就產生了這些資訊,因此當文件被修改時,這些資訊也修改。例如,增加乙個屬性,開始標籤的長度改變了,元素的長度改變了,以及所有後面的和包含的元素都要被調整。如果刪除乙個元素,領銜值改變了,還有其前乙個元素的

ielemnext

也被修改以繞過刪除的元素等等。

深入markup分析器

雖然markup

經常被叫做是「分析器」,但是分析保是

cmarkup

功能中的一部分,另外

cmarkup

還支援文件的導航、建立和修改,還有其它如檔案

i/o、字符集及

64位編碼轉換等功能。然而分析器是

cmarkup

乙個最重要的功能,因為這樣可以匯入和訪問現有

xml檔案。

分析器在

setdoc

和load

方法中分析文件,並建立定位陣列,這是乙個非驗證的分析器,這表明它不會依照著

dtd和

schema

來檢查文件的正確性。它只會檢查格式的好壞,如果結束標籤不匹配開始標籤它會產生乙個錯誤,如果沒有根元素存在會產生乙個錯誤,或者其它一些不正確的結點樣式它也會產生乙個錯誤。 在

7.0版 本中,分析器使用了新的分析方法,不再使用遞迴實現。在以前的版本中,使用遞迴方法實現時,每次在另乙個元素中發現乙個元素就呼叫自己,當它到達父結點的 結束標籤時返回。因為每次巢狀呼叫都要增加區域性變數和引數到堆疊中,但是在堆疊的尺寸是有限的任何平台上,例如掌上作業系統,這時,遞迴就成為乙個問題 了。雖然大多數的檔案不會大於

10個元素的深度(巢狀),也許在棧中只需要

500bytes

,然而,這仍是乙個潛在的危險。新的分析器使用了乙個叫

nodestack

的小陣列,它就像乙個棧,但是它在堆裡的。

它保持著一直到當前深度的所有被巢狀的元素的標籤名。

分析函式x_parseelem實際上相當簡單,它通過呼叫

x_parsenode

查詢和檢查下乙個結點來迴圈所有的結點,直到文件的結束。關於結點型別的討論可以看在nodes的文章。元素的結束標籤被表示成0的結點型別,因為它是元素結點的結束。

nodestack 用來記錄被巢狀的元素,當乙個起始標籤被遇到時,它將呆在nodestack中,直到相對應的結束標籤被發現。如果乙個元素a包含其它一些元素,那麼這些 元素將會放到nodestack中,並且置於元素a的上面,在恢復父元素(元素a)之前,需要匹配它們的結束標籤然後從nodestack中刪除。

x_parsenode

函式是根據在文件中給定結點起始字元的偏移量來識別乙個結點。出於對速度和簡單考慮,結點被分析只是從第乙個字元前進做乙個簡單的迴圈,在結點的型別被確定前,保持乙個位元標誌狀態。

如果第一字元是小於號「

<」,

它就是乙個標籤「

<..>」(

對於文字和空格

),如果是標籤,檢查第二個字元,它可能是元素標籤名的起始、或者乙個斜線(結束標籤)、或者是乙個感嘆號(是注釋、

cdata

段或doctype

)或是問號(

pi),如果是感嘆號,你必須要得到下乙個字元來判斷結點的型別。一旦知道了結點型別,分析器就可以正確掃瞄這種結點型別相應的結束字串。

如果第乙個字元不是小於號「

<

」,同時也不空格,那麼它是乙個文字結點,並且這個結點一直要到乙個小於號

」<」

或者到文件的結束。如果第乙個字元是乙個空格,那麼它也要一直到小於號

」<」

或文件結束,但是當看到第乙個非空格就表明它是乙個文字結點。如果到結點的結束都沒有遇到非空格,那麼,它就是乙個空格結點。

現在,讓我們這樣的步驟來處理下面的簡單

xml文件。

<?

xml version

="1.0"?><

test

>hello world

test

>

首先呼叫

x_parsenode

,開始字元是文件的第乙個字元,如果是小於號,表明是標籤,所以

opentag

位被設定,下乙個字元是乙個問號,那麼在

opentag

狀態中,表明這是乙個處理指令(

pi),現在知道了結點型別,不需要設定

opentag

位了。它會掃瞄

pi的結束字串

?>,

再返回。

第二步,呼叫

x_parsenode

,開始字元是測試元素的第乙個字元,是小於號,表明這是乙個標籤,所以設定

opentag

位,下乙個字元是乙個有效字元,是元素標籤名的第乙個字元,那麼在

opentag

狀態中,意味著這是乙個文字結點。現在知道了結點型別,就不需要再設定

opentag

位了。它會掃瞄到元素標籤的結束字元

」>」,

接著返回。

第三步,呼叫

x_parsenode

,起始字元是「

hello world

」的第乙個字元,這不是小於號了,它是乙個空格,所以

textorws

(文字或空格

)位要被設定。下乙個字元是文字字元,所以在

extorws

狀態中,就意味著這是乙個文字結點,現在,解析器知道了結點型別,就不用再設定

textorws

位了,它會掃瞄小於號或文件的結束,然後返回。

第四步,呼叫

x_parsenode

,,開始字元是測試元素結束標籤的第乙個字元,這是乙個小於號,表明它是標籤,所以要設定

opentag

位,下乙個字元是斜線,在

opentag

狀態中,這意味著它是乙個結束標籤,現在知道標籤的型別了,不用設定

opentag

位了,它會掃瞄結束標籤的結束字元「>」,然後返回。

select COUNT 語句深入解釋

select count 只統計不是null的列數,所以count 列名 count 常量 count 的區別就是 count 列名 中的列可能是null,於是不被統計入內 其餘兩個倒是統計所有符合條件的行數,且是標準的統計行數的方法,mysql已經做了一些優化,所以推薦 區分為myisam和inn...

漏洞可解釋性定位

利用可解釋性做定位,用可解釋的方法來做定位。首先在建模的時候要包括能體現漏洞的特徵,結合汙點分析的原理,可以這樣說,如果在source和sink中間沒有sanitizer操作,這才可能會導致漏洞發生,資料完整性或資料私密性被破壞。都說借助自然語言的處理方法來對程式處理,是為了程式的語義資訊。可是,程...

深入理解浮動定位 float

css網頁布局有兩種方式 一種是浮動式布局 另外一種是定位布局。這兩種方式的核心都脫離於文件流的控制。前提 文件流 document flow 對於乙個xhtml網頁,body元素下的任意元素,根據其前後順序,組成了乙個個上下關係,簡單說這就是文件流。瀏覽器根據這些元素的順序去顯示它們在網頁中的位置...