将多个路径字符串转换成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下。

转换后,我们可以做以下几件事:

  1. 直接遍历这个Map,先找出根目录(即value为root#null的)root下的所有节点(这里是home, etc, tmp, usr,当然也可能直接就是一个文件了)。判定的标准为:所有的value都为root#null的。
  2. 循环遍历root的子节点集合,判定每个子节点是否为叶子节点(即文件),若是,则加上<leaf>节点名字<leaf>,可以考虑使用StringBuilder.append();,若不是,则对每个子节点做以下几件事:
    1. 加上节点开始标记<节点名字>
    2. 做第1步,只是当前目录不是根目录而已(递归了)
    3. 加上节点结束标志<节点名字>

这样递归下去,就会形成多颗以文件夹路径开始的文件夹作为根目录的XML树,最后将所有得到的小树都添加到新创建的<root></root>根标签中,到此,文档生成完成。

代码就不写了,思路已经相当清晰了,哈哈

使用这种方式,虽然迭代次数可能比较多,但是使用Map来保存树的结构以及使用字符串来生成XML的资源消耗都不大,而且效率都相当高。至于有多高,我用以上数据做了个测试,执行时间在1~3ms,感兴趣的亲们可以试试。

后记

    开始的一个版本是:将Map中的Key和Value都表示为当前【节点名字#深度】,但是当我按照这种思路写完后,立刻发现生成的XML不是我想要的,因为我的测试数据中存在多个【节点名字】和【深度】都相同的节点,但是其根节点不同。。。。究其原因,是因为我们设计时可能存在同样的Key,于是后面的同深度且同名的文件夹名字则被pass掉了,导致该深度下所有同名的文件夹都被添加到了第一颗根节点下。

    后来想了半天,才把这个【节点名字#深度】替换为【节点名字#XPath】,这个必须是唯一的了。

时间: 2024-10-31 07:49:39

将多个路径字符串转换成XML文档树的相关文章

挑逗你的智慧:mysql中的返回数据怎么转换成xml文档形式??

问题描述 我现在想要将mysql数据库中查询的结果以xml文档的形式返回给我,大家有没有好的办法,最好是mysql自带的FUNCTION:如在oracle中就可以 select DBMS_XMLGEN.GETXML('select * from user') from dual 至于mysql?????? 解决方案 http://www.zxbc.cn/html/20080906/65307.htmlShell> mysql -X -uroot -proot -e "use test; s

请教,VB.net 如何将xml文档转换成excel文档

问题描述 请教,VB.net如何将xml文档转换成excel文档,最好付上代码,谢谢! 解决方案 解决方案二:把xml数据放到内存表里再插入到新建的EXCEL表解决方案三:引用1楼notbb的回复: 把xml数据放到内存表里再插入到新建的EXCEL表 是用fastreport导出的excel文件,但实际上是一个xml文件,在手机上打不开.想把它转换成excel文件解决方案四:那简单啊.你直接用EXCEL打开方式打开你的报表文件,然后另存为EXCEL格式的文件就行了.或者新建个EXCEL文件,打开

PDF转换成Word文档方法总结

PDF转换成word文档方法总结 1.考虑到在生活工作中经常有朋友遇到将各种来源的pdf文档转化为word或txt的需求; 2.曾经有朋友发表过类似的软件,究其软件功能较简单,往往不能满足不同朋友的需求,发此文,旨在帮助朋友能更高效的完成相关工作并在提供一点思路. 如图示 说明 pdf 无法编辑,这不是缺点,而是它的定位. pdf 虽然无法编辑,但可以进行注释. 为什么转换PDF到其他格式?技术角度,是为了二次编辑和后续利用;但这样做的时候,请注意版权问题. 一定要转到word格式?不一定.如果

如何将pdf转换成word文档-pdf转换成word教程

如何将pdf转换成word文档?大家都知道,现在上网找一份资源相当的简单,大家直接在百度文库或新浪网盘中进行搜索,就可以找到各种各样的下载资源,然而有时候我们也会碰到一些问题.小编就拿之前遇到的事情举个例吧,当时小编想要找一份C语言题目的答案,当时搜索了好久终于找到了相关的下载资源,可下载下来小编突然发现,该资源是pdf格式的,小编很难直接对其内容进行复制利用,对此小编只能想办法将pdf转换成可编辑的word文档了.那么该使用什么方法呢? 当时小编通过朋友的介绍认识了迅捷PDF转换成Word转换

把wps文档转换成word文档的两种方法

  我们知道,电脑安装的是金山wps,那么,文件保存的就是wps文档了.如果要用wor打开的话,就需要将wps文档转换成word文档.今天,我们就来学习一下将wps转换成word的方法,包括了修改文件后缀名的方法.另外为doc格式的方法.下面就一起来看看具体的内容吧! 把wps转换成word的方法一: 第一步:点击我的电脑或者计算机,点击"工具",然后点击"文件夹选项"; 第二步:在对话框中点击"查看",把"隐藏已知类型文件的扩展名&q

PPT中文字转换成Word文档的4大绝招

  你是不是因为不能把PPT课件转换成Word讲义而感到烦恼?或者对大量的PPT幻灯片内容需要打印出来而犯愁呢?下面向大家介绍4种将PPT演示文稿里的文字转换成Word文档的方法,以供参考. 1.利用"大纲"视图 打开PPT演示文稿,单击"大纲",在左侧"幻灯片/大纲"任务窗格的"大纲"选项卡里单击一下鼠标,按"Ctrl+A"组合健全选内容,然后使用"Ctrl+C"组合键或右键单击在快捷

Office 2013将Excel表格转换成PDF文档的方法

  Office 2013将Excel表格转换成PDF文档的方法.提到将Excel表格转换成PDF文档,很多网友都知道金山wps就自带了这个功能,因此,就有不少微软Office用户非常不服,因此,他们发现:微软Office 2013也具有了这个功能,但是,太少人知道了.在今天的教程中,我们就一起来了解一下微软Office 2013将Excel表格转换成PDF文档的方法! 选取了两个表格来做演试(按住Ctrl+鼠标点击选取),选择后点击左上角的"文件". Office 2013 接下来将

教你怎么把pdf文件转换成word文档 轻松快速

话说,最近领导又有新要求了,要小编把一个产品的说明书PDF文件转换成Word 文档,然后可以保证编辑里面的内容和文字.小编在网上找了一些软件,结合自己的一些使用经验,把转换方法和软件介绍给大家. PDF转换成Word文档的基本转换思路: 如果是那种可以复制里面文字的PDF文档,一般都可以直接转换出来的,也可以做到修改,如果有密码限制,直接用软件去掉限制就可以了. 如果是遇到有转换出来是乱码的情况,一般建议尝试其它品牌的转换器,因为没有最好,只有最适合. 下面推荐相关的软件. 易捷pdf转换成wo

PDF文档转换成Word文档小妙招

一般情况下,PDF文档转换成Word文档很是麻烦,今天小编就教大家一个小妙招,利用win8系统自带的Skydrive就可以轻松将PDF文档转换成Word文档,不需要任何第三方转换软件. 1.打开 https://skydrive.live.com/ 2.上传你要转换成Word文档的PDF文件,然后点击 在 Word Web App 中打开 3.点击在 Word中编辑,开始转换 4.转换完成后就可以编辑了,也可以把转换好的Word文档下载到本地硬盘 简单的四个小步骤,不需要安装任何第三方转换软件,