高效XML格式化工具的实现与优化

在处理大量XML文件时,经常会遇到文件格式混乱、难以阅读的问题。为了解决这个问题,编写了一个高效的XML格式化工具,它能够快速地将混乱的XML文件整理成易于阅读的格式。这个工具最初是为了解决工作中遇到的一个问题:需要处理大约40MB的XML文件,这些文件全部在一行上,没有换行和缩进,这使得阅读和编辑变得非常困难。虽然Notepad++有一个插件可以完成这项工作,但它处理一个文件需要大约45分钟,而工具只需要5秒钟。

由于只有XML文件用于测试,可能有些情况没有考虑到。如果发现有些XML文件没有正确地换行或缩进,请发送一个样本文件给。

使用代码

这个小函数接受两个参数:输入流和输出流。它将读取输入流,格式化内容,然后写入输出流。

编写了一个非常基础的Win32 API输入和输出选择区域,用于简单的使用。最初的版本只需要将EXE文件放入包含XML文件的目录中,双击它,它就会处理该目录中的每个XML文件。

虽然界面显然是仅限Windows的,但实际的函数本身应该是平台无关的。

要调用这个函数,请使用以下代码:

C++tidyXML(inputFile, outputFile);

其中inputFileoutputFileifstreamofstream的引用。

函数本身

以下是函数本身。有点懒于写注释。如果不明白为什么某个部分是这样实现的,或者只是想让在特定地方添加注释,请在下面的评论中告诉,会尝试添加更多。但代码应该是相当直观的。

C++void tidyXML(ifstream &input, ofstream &output) { char currChar; char nextChar; int indent = -1; string currKeyStore = ""; string lastKeyStore = ""; string valueOrJunkStore = ""; bool inKey = false; bool skipNextIndent = false; enum keyType { unset, infoLine, entryKey, exitKey, emptyValue, }; keyType lastKeyType = unset, currKeyType = unset; while (true) { currChar = input.get(); if (!input.good()) { output << currKeyStore; break; } // 看看接下来是什么 nextChar = input.peek(); if (!input.good()) nextChar = '\0'; if (currChar == '<') { inKey = true; lastKeyType = currKeyType; lastKeyStore = currKeyStore; currKeyType = unset; currKeyStore = ""; // 如果不能在这里确定,需要等到nextChar是'>“才能决定 if (nextChar == '/') currKeyType = exitKey; else if (nextChar == '?' || nextChar == '!') currKeyType = infoLine; } if (currKeyType == unset && nextChar == '>') { // 现在可以确定这是什么了 :) if (currChar == '/') currKeyType = emptyValue; else currKeyType = entryKey; } if (inKey) currKeyStore += currChar; else valueOrJunkStore += currChar; if (currChar == '>') { inKey = false; if (!skipNextIndent) for (int i = 0; i < indent; ++i) output << '\t'; output << lastKeyStore; skipNextIndent = false; if (lastKeyType == entryKey && currKeyType == exitKey) { // 值行 skipNextIndent = true; output << valueOrJunkStore; } else if (lastKeyType != unset) { // 所以不要在文件开头添加行 output << endl; } valueOrJunkStore = ""; if (lastKeyType == exitKey || lastKeyType == emptyValue) --indent; if (currKeyType == entryKey || currKeyType == emptyValue) ++indent; } } }

编译示例

使用MinGW编译了带有简单Win32界面的示例版本。使用以下命令:

mingw32-g++ --std=c++0x -Wall -fno-builtin -O3 -static *.cpp -lcomdlg32 -o tidyxml.exe

已经静态链接了它,所以它应该可以立即运行,而不需要依赖地狱。

还提供了一个双击构建的build.bat文件。它也会去掉调试符号。

要点

编写这个的主要痛苦在于,必须总是读取下一个标签,然后才知道如何处理当前的标签。或者更好的说法是,保存当前标签,读取下一个标签,这样就可以决定如何处理保存的标签。

最初的版本充满了布尔值来规划和跟踪所有事情。这些被枚举替换了,使代码更干净、更容易理解。至少是这么认为的。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485