source: s10k/XmlTools/utilxmltools.cpp@ 1077

Last change on this file since 1077 was 1073, checked in by s10k, 7 years ago

added XML Tools latest version (2.0d) and s10k's common libs

File size: 10.2 KB
Line 
1#include "utilxmltools.h"
2
3namespace UtilXmlTools{
4
5// As this will not likely be modified we use QVector instead of QList since it is more cache friendly
6QVector<QString> getAllXmlFilesByWildcard(const QString &wildcard){
7 QStringList validFilesMatching;
8 QStringList filesMatching;
9
10 // Get all files matching the wildcard
11
12 filesMatching=UtilXmlTools::getAllFilesByWildcard(wildcard);
13
14 // Check if all are XmlFiles, only return valid XmlFiles
15
16 for(int i=0; i<filesMatching.size(); i++){
17 if(filesMatching[i].endsWith(".xml",Qt::CaseInsensitive)){
18 validFilesMatching << filesMatching[i];
19 }
20 }
21
22 return validFilesMatching.toVector();
23
24}
25
26QVector<QString> getAllPatchFilesByWildcard(const QString &wildcard){
27 QStringList validFilesMatching;
28 QStringList filesMatching;
29
30 // Get all files matching the wildcard
31
32 filesMatching=UtilXmlTools::getAllFilesByWildcard(wildcard);
33
34 // Check if all are PatchFiles, only return valid PatchFiles
35
36 for(int i=0; i<filesMatching.size(); i++){
37 if(filesMatching[i].endsWith(".patch",Qt::CaseInsensitive) || filesMatching[i].endsWith(".oni-patch",Qt::CaseInsensitive)){
38 validFilesMatching << filesMatching[i];
39 }
40 }
41
42 return validFilesMatching.toVector();
43
44}
45
46void backupFile(const QString &file, bool verboseEnabled){
47 if(!QFile::exists(file+".bak")){
48 if(!Util::FileSystem::backupFile(file)){
49 std::cerr << "Couldn't back up file '" << file.toUtf8().constData() << "'. Aborting." << std::endl;
50 exit(1);
51 }
52 }
53 else{
54 if(verboseEnabled){
55 std::cout << "Backup file '" << file.toUtf8().constData() << "'' already exists. Skipping..." << std::endl;
56 }
57 }
58}
59
60void getAllXpathElements(const QString &xPathExpression, pugi::xml_document &doc, QList<pugi::xml_node> &result){
61
62 pugi::xpath_node_set selectedNodes;
63 pugi::xpath_node node;
64
65 try
66 {
67 selectedNodes = doc.select_nodes(xPathExpression.toUtf8().constData());
68 }
69
70 catch (const pugi::xpath_exception& e)
71 {
72 displayErrorMessage("XPath element selection","Selection of elements using the XPathExpression: '" + xPathExpression + "' failed:\n" + e.what());
73 }
74
75 for (pugi::xpath_node_set::const_iterator currNode = selectedNodes.begin(); currNode != selectedNodes.end(); ++currNode)
76 {
77 node = *currNode;
78 if(node){ // if node != null
79 result << node.node();
80 }
81 }
82
83 if(result.isEmpty()){
84 result << pugi::xml_node(); // add an empty node if none found
85 }
86
87}
88
89pugi::xml_node getFirstXpathElement(const QString &xPathExpression, pugi::xml_document &doc){
90 pugi::xpath_node selectedNode;
91
92 try
93 {
94 selectedNode = doc.select_single_node(xPathExpression.toUtf8().constData());
95 }
96
97 catch (const pugi::xpath_exception& e)
98 {
99 displayErrorMessage("XPath element selection","Selection of element using the XPathExpression: '" + xPathExpression + "' failed:\n" + e.what());
100 }
101
102 return selectedNode.node();
103}
104
105void getAllNamedElements(pugi::xml_node &node, QList<pugi::xml_node> &result, XmlFilter &filters){
106 for (pugi::xml_node_iterator currNode = node.begin(); currNode != node.end(); ++currNode)
107 {
108
109 if ((*currNode).name() == filters.getElementName() && (filters.getParentElementName() == "" || filters.getParentElementName() == (*currNode).parent().name())
110 && (filters.getAttributeName() == "" ||
111 QString((*currNode).attribute(filters.getAttributeName().toUtf8().constData()).value()) == filters.getAttributeValue()) ){ // Seems node attribute must be converted to qtsring to remove \r\n needs to check in future!
112
113 result << *currNode;
114 continue;
115 }
116 getAllNamedElements(*currNode,result,filters);
117 }
118}
119
120pugi::xml_node getFirstNamedElement(pugi::xml_node &node, XmlFilter &filters){
121
122 pugi::xml_node foundNode;
123
124 for (pugi::xml_node_iterator currNode = node.begin(); currNode != node.end(); ++currNode)
125 {
126 if ((*currNode).name() == filters.getElementName() && (filters.getParentElementName() == "" || filters.getParentElementName() == (*currNode).parent().name())
127 && (filters.getAttributeName() == "" ||
128 QString((*currNode).attribute(filters.getAttributeName().toUtf8().constData()).value()) == filters.getAttributeValue()) ){
129 return *currNode;
130 }
131
132 foundNode=getFirstNamedElement(*currNode,filters);
133
134 if(foundNode.type()!=pugi::node_null){
135 return foundNode;
136 }
137
138 }
139
140 return foundNode;
141}
142
143void displaySuccessMessage(const int numberOperations, const QString &operation){
144 std::cout << "------------------------------------------------------------------------" << std::endl;
145 std::cout << numberOperations << " " << operation.toUtf8().constData() << " operation(s) completed with success!" << std::endl;
146 std::cout << "------------------------------------------------------------------------" << std::endl;
147}
148
149void displayErrorMessage(const QString& operation, const QString &message, bool exitProgram){
150 std::cerr << "************************************************************************" << std::endl;
151 std::cerr << operation.toUtf8().constData() << " operation failed!" << std::endl << std::endl;
152 std::cerr << message.toUtf8().constData() << std::endl << std::endl;
153 if(exitProgram) std::cerr << "Aborting..." << std::endl;
154 std::cerr << "************************************************************************" << std::endl;
155 if(exitProgram) exit(1);
156}
157
158QStringList qStringListFromSpacedString(const QString &mySpacedString){
159 return mySpacedString.split(" ");
160}
161
162QList<int> qListIntFromSpacedString(const QString &mySpacedString){
163 QStringList stringList;
164 QList<int> intList;
165
166 stringList = mySpacedString.split(" ");
167
168 foreach(QString value, stringList){
169 bool ok;
170
171 intList << value.toInt(&ok);
172
173 if(!ok){
174 throw std::runtime_error(QString("Impossible to convert string '" + value + "' to int!").toUtf8().constData());
175 }
176 }
177
178 return intList;
179}
180
181QList<double> qListDoubleFromSpacedString(const QString &mySpacedString){
182 QStringList stringList;
183 QList<double> doubleList;
184
185 stringList = mySpacedString.split(" ");
186
187 foreach(QString value, stringList){
188 bool ok;
189
190 doubleList << value.toDouble(&ok);
191
192 if(!ok){
193 throw std::runtime_error(QString("Impossible to convert string '" + value + "' to double!").toUtf8().constData());
194 }
195 }
196
197 return doubleList;
198}
199
200void loadXmlFile(const QString &file, pugi::xml_document &document, pugi::xml_node &rootNode, bool backupsEnabled, bool verboseEnabled, const QString &operationForErrorMessage){
201
202 pugi::xml_parse_result result = document.load_file(file.toUtf8().constData());
203 rootNode=document.root();
204
205 if(result.status==pugi::status_ok){
206 if(verboseEnabled){
207 std::cout << "File '" << file.toUtf8().constData() << "' loaded with sucess." << std::endl;
208 }
209 }
210 else{
211 UtilXmlTools::displayErrorMessage(operationForErrorMessage,"An error ocurred while loading '" +file + "' XML file\n" + result.description());
212 }
213
214 if(backupsEnabled){
215 UtilXmlTools::backupFile(file,verboseEnabled); // bake a backup of the file.
216 }
217
218}
219
220void saveXmlFile(const QString &file, pugi::xml_document &document, const QString &operationForErrorMessage){
221 if(!document.save_file(file.toUtf8().constData(), "\t", pugi::format_indent | pugi::format_save_file_text | pugi::format_no_escapes)){ // output as the system new lines ending
222 UtilXmlTools::displayErrorMessage(operationForErrorMessage,"An error ocurred while saving '" + file + "' XML file");
223 }
224}
225
226//TODO Needs optimization
227QStringList QStringToArgsArray(const QString &args){
228 QStringList result;
229 int startIdx=0, endIdx=0;
230
231 if(!args.isEmpty()){ // if non empty arguments
232
233 while(endIdx<args.length()){
234
235 startIdx=endIdx;
236
237 if(args.at(startIdx)==' '){ // Ignore spaces until a different char is found
238 endIdx++;
239 continue;
240 }
241 else if(args.at(startIdx)!='"'){ // if first character is different from quote it ends with space
242 endIdx=args.indexOf(' ',startIdx+1);
243 }
244 else{ // If is a quote try to get the all the string until next quote
245 endIdx=args.indexOf('"',startIdx+1);
246 }
247
248 if(endIdx==-1) break;
249
250 endIdx++;
251
252 result << args.mid(startIdx,endIdx-startIdx).replace("\"","").trimmed(); // remove quotes
253 }
254
255 }
256
257 return result;
258}
259
260// TODO: Replace later with a more generic function and put in util library
261// Supports wildcards, and directory with wildcard e.g.:
262// *.xml
263// C:/myXmls/*.xml
264QStringList getAllFilesByWildcard(const QString &wildcard){
265
266 QString pathNormalized;
267 QStringList nameWildCard; // entryList requires a QStringList
268 QStringList resultFiles; // result files with absolute path
269 int endOfPathIdx;
270 QDir directory;
271
272 if(wildcard==""){
273 std::cout << "You need to specify a wildcard! Aborting..." << std::endl;
274 exit(1);
275 }
276
277 pathNormalized=Util::FileSystem::normalizePath(wildcard); // Convert slashes to work in both mac and windows
278
279 if(pathNormalized.contains("/")){ // If contains full path
280 endOfPathIdx=pathNormalized.lastIndexOf("/"); // get last slash
281
282 nameWildCard.append(pathNormalized.right(pathNormalized.size()-1-endOfPathIdx)); // get the names wildcard // -1 because starts with zeo
283
284 pathNormalized=pathNormalized.left(endOfPathIdx); // get the complete path
285
286 directory=QDir(pathNormalized);
287 }
288 else{ // if relative
289 nameWildCard << wildcard;
290 }
291
292 foreach (QFileInfo fileInfo, directory.entryInfoList(nameWildCard)){
293 resultFiles << fileInfo.absoluteFilePath();
294 }
295
296 return resultFiles;
297}
298
299}
Note: See TracBrowser for help on using the repository browser.