原文链接:
最近在搞XML解析优化,公司引擎用了tinyxml1和tinyxml2两个XML库,后者的效率比前者高60%吧,tinyxml1解析大文件是很慢的,可以淘汰了,tinyxml2还勉强,快的话还得算pugixml或者rapidxml吧。
奈何一些引擎代码根深蒂固,无法更换为pugixml,只能局部修改一下tinyxml库的源代码企图优化一下
今天在优化的时候碰到一个坑,就是解析出错的时候,XML库是如何处理的,比如某个节点有两个同名的属性,以下是各XML库的处理:
tinyxml1:按XML文本的顺序解析,在解析到同名属性的时候,停止解析,返回已经解析好了的那部分,并且在document对象里的 errorLocation.row 和 errorLocation.col 表明出错的位置(行和列)
tinyxml2:貌似是递归解析,碰到同名属性时,一下子全蹦了,返回的document啥子都没有,在document对象里的 _errorStr1 里存储了那个同名的属性的名字, _errorStr2 指向那个同名属性后的位置。其实不是很好分辨
pugixml:非常高效,所以没看懂是如何解析的。在给element添加属性时应该是没有见检查是否存在同名属性,能正常解析完的,最后断点观察那两个同名属性都被加进了element的
解析比较:tinyxml1使用的是逐字符扫描,tinyxml2使用的划分成块解析吧,pugixml没看懂。除了解析的方式不同造成效率有差别之外,另外一个重要的原因则是字符串的操作了;还有一个就是冗余的安全性检查,效率和安全总是对立的。。
tinyxml1:区分是否使用了STL宏,如果使用了,里面的字符串都是使用sdt::string类型,否则就是用自定义的一个字符串类 tinystr。把XML文件读取到内存后,在解析的时候,每涉及到字符串操作时,比如设置属性的名字、属性等,都会有分配内存然后把字符串拷贝过来赋值(如果使用了STL则由STL::string负责内存的分配和管理) 。一个XML文件里有N多的节点、M的属性、非常多的字符串,每次都要分配内存、拷贝,慢是必然的了。每一次添加节点或者属性时,都会进行检查是否已有同名的节点或者属性。
tinyxml2:使用了自定义的字符串类 StrPair 。XML文件被读取到内存后,tinyxml2会分配内存(假设是A内存)把XML文件的内容拷贝过来,在解析的时候,涉及到XMLElement或者XMLAttribue等之外的name、value的时候,tinyxml2并没有再次分配内存把字符串拷贝过去,而是把strpair的 _start 指针 直接指向A内存里对应的位置,整个过程,只分配了一次内存~~ 解析完了之后,如果你添加了节点或者更改某属性的value等等时,tinyxml2则会分配新的内存,strpair类里有标记位来分辨是第一次解析还是后面的增加或者修改的。每一次添加节点或者属性时,都会进行检查是否已有同名的节点或者属性。
pugixml:貌似是自己负责了所有的内存管理,没太看懂~~每一次添加节点或者属性时,应该没有进行检查是否已有同名的节点或者属性~~
今天被坑在,某个XML文件某个节点有属性同名了,但引擎库是用了tinyxml1来解析的,所以返回的document的全半部分是正常的,而我是用tinyxml2来测试的优化代码的,发现~~~被坑大了,各种检查自己写的优化的代码~~~
刚好还发现那个XML文件里有中文,搞得又怀疑是编码的问题,顺便又恶补了一下编码的基础知识,顺便用了用比较了一下 sublime text、notepad++、UltraEdit~~~发现UltraEdit是用Unicode编码来显示的,对于黏贴进去的字符串会当成是Unicode编码格式下的来处理;sublime text 可以用utf8、大头小头Unicode-16、16进制等编码格式来显示,对于拷贝进去的字符串,会被当做是utf8编码格式下的来处理;notePad++ 可以用 ansi、utf8等编码格式来显示,对于拷贝进去的字符串,看你当前选择了什么格式,你选择了什么格式,拷贝进去的字符串就会当作那个编码格式下的来处理。
擦,都得又乱了,虽然原本也没清楚。。苦逼
原文链接: