將多個路徑字串轉換成XML文件樹
假設有下面的字串:
1
2
3
4
5
6
7
|
/home/usr/abc/def/文字.txt /home/usr/desktop/音樂.mp3 /etc/init.d/mysql/mysql /etc/profile /tmp/垃圾.tmp /usr/bin/open-jdk7/java ... |
給定一個根節點名字root和葉子節點名字leaf,如何將它們轉換成一顆像下面這樣的XML文件樹呢?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
< root >
< home >
< usr >
< abc >
< leaf >文字.txt</ leaf >
</ abc >
< desktop >
< leaf >音樂.mp3</ leaf >
</ desktop >
</ usr >
</ home >
< etc >
< init.d >
< mysql >
< leaf >mysql</ leaf >
</ mysql >
</ init.d >
< leaf >profile</ leaf >
</ etc >
< tmp >
< leaf >垃圾.tmp</ leaf >
</ tmp >
< usr >
< bin >
< open-jdk7 >
< leaf >java</ leaf >
</ open-jdk7 >
</ bin >
</ usr >
</ root >
|
對於這個問題,一個解決的思路是:先建立一顆以root作為根標籤的XML文件樹,再迴圈迭代每個字串,將其按照`/`切開(Split),然後依次對每個資料夾名字建立一個XML節點(Node),並搜尋整棵樹,如果該節點存在,則直接pass掉,否則將節該點追加到某個父節點下。但是此種方法太麻煩,因為每次增加一個節點,你就需要去遍歷一次。有很多情況下,前幾層節點是存在的,這樣判斷就不那麼高效了。舉個例子,現在有一條深度為10的資料夾路徑(比如/a/b/c/d/e/f/g/h/i/j/**.sh),為了插入這條路徑,首先需要判斷/a是否存在,存在就pass掉,不存在就建立/a;之後判斷/a/b是否存在;之後是/a/b/c是否存在。。。
很顯然,這樣做,越到後面效率越低。而且,直接操作Xml文件會佔用很多資源。
那麼,有沒有一種簡單又高效的方式呢?答案是肯定的,這就是寫這篇部落格的原因了。這只是一種方案,也許還有更好的,有興趣的同學可以自行研究,哈哈……
首先,我們可以將這些資料夾路徑進行預處理────轉換成中間格式進行儲存。這裡,我們可以先定義一個Map結構,Key用於儲存當前節點名字和節點的XPath,中間可用特殊字元隔開;Value用於儲存當前節點的父節點的名字和父節點的XPath(根節點root的父親為null),中間也用相同的特殊字元隔開,像下面這樣:
1
2
|
< home #/root, root#null>
< user #/root/home, home#/root>
|
第一行表示:當前的home節點XPath為/root,其父節點root的xPath為null,同理,第二行表示:當前節點user的XPath為/root/home,而其父節點home的XPath為/root。把Key設計成這樣有一個好處是,當一條路徑中的多層裡有相同名字的資料夾時,也可以輕易分辨。比如有一條路徑為:/home/home/home,那麼在建立節點時,會建立以下幾個鍵值對:
1
2
3
|
<home#/root, root# null >
<home#/root/home, home#/root> <home#/root/home/home, home#/root/home> |
就是說,在同一個XPath(例如/root/home)下,只會存在一個名為home的資料夾。如果以後的資料夾路徑中還包含/home/home/home這樣的地址,那麼這些資料夾的子資料夾將會被放在已經存在的/root/home/home/home路徑下。再通俗一點:每個Key-Value都是唯一的,它唯一表示了一條路徑的存在。
有人可能會問:為什麼Value也要設計成一樣的結構呢?
答案很簡單,便於在以後的處理中直接使用這個值,後面會提到。
通過這樣的轉換,我們可以看出,第二行的value實際上就是第一行的key,這樣我們就可以表示一條一條的子孫——祖宗鏈,都是由子節點指向父節點。
轉換之後的Map像下面這樣:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
< home #/root, root#null>
< user #/root/home, home#/root>
< abc #/root/home/user, user#/root/home>
< def #/root/home/user/abc, abc#/root/home/user>
<文字.txt#/root/home/user/abc/def, def#/root/home/user/abc/def> <!-- 第二個URL中的home資料夾和user資料夾對應的key就是第一個key, 已經存在,則不會在增加這個key了 --> < desktop #/root/home/user, user#/root/home>
<音樂.mp3#/root/home/user/desktop, desktop#/root/home/user> < etc #/root, root#null>
< init.d #/root/etc, etc#/root>
< mysql #/root/etc/init.d, init.d#/root/etc>
< mysql #/root/etc/init.d/mysql, mysql#/rot/etc/init.d>
... |
細心的同學可能已經看見了,第5行以後,處理第二個URL時,home和user兩個資料夾已經存在,則直接pass掉,接著處理desktop資料夾了。還有desktop資料夾對應的value是user#/root/home,這和第3行的value相同,因此資料夾desktop和abc屬於同一級,都在/root/home/user下。
轉換後,我們可以做以下幾件事:
-
直接遍歷這個Map,先找出根目錄(即value為root#null的)root下的所有節點(這裡是home, etc, tmp, usr,當然也可能直接就是一個檔案了)。判定的標準為:所有的value都為root#null的。
-
迴圈遍歷root的子節點集合,判定每個子節點是否為葉子節點(即檔案),若是,則加上<leaf>節點名字<leaf>,可以考慮使用StringBuilder.append();,若不是,則對每個子節點做以下幾件事:
-
加上節點開始標記<節點名字>
-
做第1步,只是當前目錄不是根目錄而已(遞迴了)
-
加上節點結束標誌<節點名字>
-
這樣遞迴下去,就會形成多顆以資料夾路徑開始的資料夾作為根目錄的XML樹,最後將所有得到的小樹都新增到新建立的<root></root>根標籤中,到此,文件生成完成。
程式碼就不寫了,思路已經相當清晰了,哈哈
使用這種方式,雖然迭代次數可能比較多,但是使用Map來儲存樹的結構以及使用字串來生成XML的資源消耗都不大,而且效率都相當高。至於有多高,我用以上資料做了個測試,執行時間在1~3ms,感興趣的親們可以試試。
後記
開始的一個版本是:將Map中的Key和Value都表示為當前【節點名字#深度】,但是當我按照這種思路寫完後,立刻發現生成的XML不是我想要的,因為我的測試資料中存在多個【節點名字】和【深度】都相同的節點,但是其根節點不同。。。。究其原因,是因為我們設計時可能存在同樣的Key,於是後面的同深度且同名的資料夾名字則被pass掉了,導致該深度下所有同名的資料夾都被新增到了第一顆根節點下。
後來想了半天,才把這個【節點名字#深度】替換為【節點名字#XPath】,這個必須是唯一的了。
相關文章
- 將字串轉換成Bitmap型別 或者 將Bitmap轉換成字串字串型別
- XSLT實現XML文件轉換成HTML文件XMLHTML
- 將整數轉換成字串字串
- oracle行列轉換-字串轉換成多列Oracle字串
- oracle行列轉換-多列轉換成字串Oracle字串
- 將soap報文(或xml)轉換成物件XML物件
- javascript如何將字串轉換成陣列JavaScript字串陣列
- 將json字串轉換成list<T>JSON字串
- js將字串轉換為xml物件程式碼例項JS字串XML物件
- python如何將相對路徑轉換為絕對路徑?Python
- 使用Javascript將相對路徑地址轉換為絕對路徑JavaScript
- T-SQL——將字串轉換為多列SQL字串
- simplexml_load_string 將xml轉換成物件XML物件
- 將xml佈局轉換成View的幾種方式XMLView
- 替換空格 將一個字串中的空格替換成“ ”字串
- javascript如何將字串轉換成json格式物件JavaScript字串JSON物件
- oracle行列轉換-多行轉換成字串Oracle字串
- WPS演示將演示文件轉換成Flash檔案
- pdf轉換成word文件
- html5中將圖片的絕對路徑轉換成檔案物件HTML物件
- 將PPT文件轉換為Word文件
- JavaScript:如何將JSON物件轉換成JSON字串呢JavaScriptJSON物件字串
- 關於XML字串和XML Document之間的轉換薦XML字串
- C語言atoi()函式:將字串轉換成int(整數)C語言函式字串
- 如何將Powerpoint文件轉換為Word文件
- C# 將PDF文件轉換為Markdown文件C#
- excel表格怎麼轉換成word文件 表格資料轉換到文件Excel
- Word文件批次轉換成TXT文字
- 字串:怎樣將數字型別轉換為字串 (轉)字串型別
- InputStream流轉換成String字串字串
- pdf如何轉換成excel文件?這3個方法免費!Excel
- 如何將Word文件轉成Excel表格?Excel
- C# 解析16進位制字串。將16進位制字串轉換成明文字串C#字串
- 學習 XSLT:XML文件轉換的關鍵XML
- xml字串轉JSON字串XML字串JSON
- Thymeleaf將字串轉換為數字字串
- JavaScript將陣列轉換為字串JavaScript陣列字串
- Java學習--xml文字轉換成Java物件JavaXML物件