framework2
498 строк · 11.6 Кб
1#include "ofXml.h"
2#include "ofUtils.h"
3#include <clocale>
4
5using std::string;
6
7ofXml::ofXml()
8:doc(new pugi::xml_document){
9xml = doc->root();
10}
11
12ofXml::ofXml(std::shared_ptr<pugi::xml_document> doc, const pugi::xml_node & xml)
13:doc(doc)
14,xml(xml){
15
16}
17
18bool ofXml::load(const of::filesystem::path & file){
19auto auxDoc = std::make_shared<pugi::xml_document>();
20auto p = ofToDataPath(file);
21auto res = auxDoc->load_file(ofToDataPath(file).c_str());
22if( res ){
23doc = auxDoc;
24xml = doc->root();
25return true;
26}else{
27ofLogWarning("ofXml") << "Cannot load file " << file << ": " << res.description();
28return false;
29}
30}
31
32bool ofXml::load(const ofBuffer & buffer){
33return parse(buffer.getText());
34}
35
36bool ofXml::parse(const std::string & xmlStr){
37auto auxDoc = std::make_shared<pugi::xml_document>();
38#if ( defined(PUGIXML_VERSION) && PUGIXML_VERSION >= 150 )
39if(auxDoc->load_string(xmlStr.c_str())){
40#else
41if(auxDoc->load(xmlStr.c_str())){
42#endif
43doc = auxDoc;
44xml = doc->root();
45return true;
46}else{
47return false;
48}
49}
50
51bool ofXml::save(const of::filesystem::path & file) const{
52if(xml == doc->root()){
53auto res = doc->save_file(ofToDataPath(file).c_str());
54ofLogVerbose("ofXml")<<"ofXML Save : "<< res;
55ofLogVerbose("ofXml")<<this->toString();
56return res;
57}else{
58pugi::xml_document doc;
59if(doc.append_copy(xml.root())){
60return doc.save_file(ofToDataPath(file).c_str());
61}
62}
63return false;
64}
65
66void ofXml::clear(){
67doc.reset(new pugi::xml_document);
68xml = doc->root();
69}
70
71std::string ofXml::toString(const std::string & indent) const{
72std::ostringstream stream;
73if(xml == doc->root()){
74doc->print(stream, indent.c_str());
75}else{
76pugi::xml_document doc;
77doc.append_copy(xml.root());
78}
79return stream.str();
80}
81
82ofXml ofXml::getChild(const std::string & name) const{
83return ofXml(doc, xml.child(name.c_str()));
84}
85
86ofXml::Range<ofXmlIterator<pugi::xml_node_iterator>> ofXml::getChildren() const{
87return ofXml::Range<ofXmlIterator<pugi::xml_node_iterator>>(doc, xml.children());
88}
89
90ofXml::Range<ofXmlIterator<pugi::xml_named_node_iterator>> ofXml::getChildren(const std::string & name) const{
91return ofXml::Range<ofXmlIterator<pugi::xml_named_node_iterator>>(doc, xml.children(name.c_str()));
92}
93
94ofXml ofXml::appendChild(const ofXml & xml){
95return ofXml(doc, this->xml.append_copy(xml.xml));
96}
97
98ofXml ofXml::prependChild(const ofXml & xml){
99return ofXml(doc, this->xml.prepend_copy(xml.xml));
100}
101
102#if PUGIXML_VERSION>=170
103ofXml ofXml::appendChild(ofXml && xml){
104return ofXml(doc, this->xml.append_move(xml.xml));
105}
106
107ofXml ofXml::prependChild(ofXml && xml){
108return ofXml(doc, this->xml.prepend_move(xml.xml));
109}
110
111bool ofXml::removeChild(ofXml && node){
112return xml.remove_child(node.xml);
113}
114#endif
115
116ofXml ofXml::appendChild(const std::string & name){
117return ofXml(doc, this->xml.append_child(name.c_str()));
118}
119
120ofXml ofXml::prependChild(const std::string & name){
121return ofXml(doc, this->xml.prepend_child(name.c_str()));
122}
123
124ofXml ofXml::insertChildAfter(const std::string & name, const ofXml & after){
125return ofXml(doc, this->xml.insert_child_after(name.c_str(), after.xml));
126}
127
128ofXml ofXml::insertChildBefore(const std::string & name, const ofXml & before){
129return ofXml(doc, this->xml.insert_child_before(name.c_str(), before.xml));
130}
131
132bool ofXml::removeChild(const std::string & name){
133return xml.remove_child(name.c_str());
134}
135
136bool ofXml::removeChild(const ofXml & node){
137return xml.remove_child(node.xml);
138}
139
140ofXml ofXml::getNextSibling() const{
141return ofXml(doc, this->xml.next_sibling());
142}
143
144ofXml ofXml::getPreviousSibling() const{
145return ofXml(doc, this->xml.previous_sibling());
146}
147
148ofXml ofXml::getNextSibling(const std::string & name) const{
149return ofXml(doc, this->xml.next_sibling(name.c_str()));
150}
151
152ofXml ofXml::getPreviousSibling(const std::string & name) const{
153return ofXml(doc, this->xml.previous_sibling(name.c_str()));
154}
155
156ofXml ofXml::getFirstChild() const{
157return ofXml(doc, this->xml.first_child());
158}
159
160ofXml ofXml::getLastChild() const{
161return ofXml(doc, this->xml.last_child());
162}
163
164ofXml ofXml::getParent() const {
165return ofXml(doc, this->xml.parent());
166}
167
168ofXml::Attribute ofXml::getAttribute(const std::string & name) const{
169return this->xml.attribute(name.c_str());
170}
171
172ofXml::Range<ofXmlAttributeIterator> ofXml::getAttributes() const{
173return ofXml::Range<ofXmlAttributeIterator>(doc, this->xml.attributes());
174}
175
176ofXml::Attribute ofXml::getFirstAttribute() const{
177return this->xml.first_attribute();
178}
179
180ofXml::Attribute ofXml::getLastAttribute() const{
181return this->xml.last_attribute();
182}
183
184ofXml::Attribute ofXml::appendAttribute(const std::string & name){
185return this->xml.append_attribute(name.c_str());
186}
187
188ofXml::Attribute ofXml::prependAttribute(const std::string & name){
189return this->xml.prepend_attribute(name.c_str());
190}
191
192bool ofXml::removeAttribute(const std::string & name){
193auto attr = getAttribute(name);
194if(attr){
195return xml.remove_attribute(attr.attr);
196}else{
197return false;
198}
199}
200
201bool ofXml::removeAttribute(const ofXml::Attribute & attr){
202return xml.remove_attribute(attr.attr);
203}
204
205bool ofXml::removeAttribute(ofXml::Attribute && attr){
206return xml.remove_attribute(attr.attr);
207}
208
209ofXml ofXml::findFirst(const std::string & path) const{
210try{
211return ofXml(doc, this->xml.select_node(path.c_str()).node());
212}catch(pugi::xpath_exception & e){
213return ofXml();
214}
215}
216
217ofXml::Search ofXml::find(const std::string & path) const{
218try{
219return ofXml::Search(doc, this->xml.select_nodes(path.c_str()));
220}catch(pugi::xpath_exception & e){
221ofLogError() << e.what();
222return ofXml::Search();
223}
224}
225
226std::string ofXml::getValue() const{
227return this->xml.text().as_string();
228}
229
230std::string ofXml::getName() const{
231return this->xml.name();
232}
233
234void ofXml::setName(const std::string & name){
235if(xml==doc->document_element()){
236xml = doc->append_child(pugi::node_element);
237}
238this->xml.set_name(name.c_str());
239}
240
241int ofXml::getIntValue() const{
242return this->xml.text().as_int();
243}
244
245unsigned int ofXml::getUintValue() const{
246return this->xml.text().as_uint();
247}
248
249float ofXml::getFloatValue() const{
250auto loc = std::setlocale( LC_NUMERIC, NULL );
251std::setlocale( LC_NUMERIC, "C" );
252float f = this->xml.text().as_float();
253std::setlocale( LC_NUMERIC, loc );
254return f;
255}
256
257double ofXml::getDoubleValue() const{
258auto loc = std::setlocale( LC_NUMERIC, NULL );
259std::setlocale( LC_NUMERIC, "C" );
260float d = this->xml.text().as_double();
261std::setlocale( LC_NUMERIC, loc );
262return d;
263}
264
265bool ofXml::getBoolValue() const{
266return this->xml.text().as_bool();
267}
268
269ofXml::operator bool() const{
270return this->xml;
271}
272
273
274
275//--------------------------------------------------------
276// Attribute
277
278ofXml::Attribute::Attribute(const pugi::xml_attribute & attr)
279:attr(attr){}
280
281std::string ofXml::Attribute::getValue() const{
282return this->attr.as_string();
283}
284
285void ofXml::Attribute::setName(const std::string & name){
286this->attr.set_name(name.c_str());
287}
288
289std::string ofXml::Attribute::getName() const{
290return this->attr.name();
291}
292
293int ofXml::Attribute::getIntValue() const{
294return this->attr.as_int();
295}
296
297unsigned int ofXml::Attribute::getUintValue() const{
298return this->attr.as_uint();
299}
300
301float ofXml::Attribute::getFloatValue() const{
302auto loc = std::setlocale( LC_NUMERIC, NULL );
303std::setlocale( LC_NUMERIC, "C" );
304float f = this->attr.as_float();
305std::setlocale( LC_NUMERIC, loc );
306return f;
307}
308
309double ofXml::Attribute::getDoubleValue() const{
310auto loc = std::setlocale( LC_NUMERIC, NULL );
311std::setlocale( LC_NUMERIC, "C" );
312float d = this->attr.as_double();
313std::setlocale( LC_NUMERIC, loc );
314return d;
315}
316
317bool ofXml::Attribute::getBoolValue() const{
318return this->attr.as_bool();
319}
320
321ofXml::Attribute::operator bool() const{
322return this->attr;
323}
324
325ofXml::Attribute ofXml::Attribute::getNextAttribute() const{
326return this->attr.next_attribute();
327}
328
329ofXml::Attribute ofXml::Attribute::getPreviousAttribute() const{
330return this->attr.previous_attribute();
331}
332
333
334//-----------------------------------------------
335// Search
336
337// Get collection type
338pugi::xpath_node_set::type_t ofXml::Search::type() const{
339return search.type();
340}
341
342// Get collection size
343size_t ofXml::Search::size() const{
344return search.size();
345}
346
347// Indexing operator
348ofXml ofXml::Search::operator[](size_t index) const{
349return ofXml(doc, search[index].node());
350}
351
352// Collection iterators
353ofXmlSearchIterator ofXml::Search::begin() const{
354return ofXmlSearchIterator(doc, search.begin());
355}
356
357ofXmlSearchIterator ofXml::Search::end() const{
358return ofXmlSearchIterator(doc, search.end());
359}
360
361// Sort the collection in ascending/descending order by document order
362void ofXml::Search::sort(bool reverse){
363search.sort(reverse);
364}
365
366// Get first node in the collection by document order
367ofXml ofXml::Search::getFirst() const{
368return ofXml(doc, search.first().node());
369}
370
371// Check if collection is empty
372bool ofXml::Search::empty() const{
373return search.empty();
374}
375
376
377ofXml::Search::Search(std::shared_ptr<pugi::xml_document> doc, pugi::xpath_node_set set)
378:doc(doc)
379,search(set){}
380
381//----------------------------------------------------
382// SearchIterator
383ofXmlSearchIterator::ofXmlSearchIterator(){}
384
385// Iterator operators
386bool ofXmlSearchIterator::operator==(const ofXmlSearchIterator& rhs) const{
387return this->node == rhs.node;
388}
389
390bool ofXmlSearchIterator::operator!=(const ofXmlSearchIterator& rhs) const{
391return this->node != rhs.node;
392}
393
394ofXml & ofXmlSearchIterator::operator*() const{
395return xml;
396}
397
398ofXml * ofXmlSearchIterator::operator->() const{
399return &xml;
400}
401
402const ofXmlSearchIterator& ofXmlSearchIterator::operator++(){
403if(node){
404node = node + 1;
405if(node){
406xml.xml = node->node();
407}
408}
409return *this;
410}
411
412ofXmlSearchIterator ofXmlSearchIterator::operator++(int){
413if(node){
414auto now = *this;
415++(*this);
416return now;
417}else{
418return *this;
419}
420}
421
422const ofXmlSearchIterator& ofXmlSearchIterator::operator--(){
423if(node){
424node = node - 1;
425if(node){
426xml.xml = node->node();
427}
428}
429return *this;
430}
431
432ofXmlSearchIterator ofXmlSearchIterator::operator--(int){
433if(node){
434auto now = *this;
435--(*this);
436return now;
437}else{
438return *this;
439}
440}
441
442void ofSerialize(ofXml & xml, const ofAbstractParameter & parameter){
443if(!parameter.isSerializable()){
444return;
445}
446string name = parameter.getEscapedName();
447if(name == ""){
448name = "UnknownName";
449}
450ofXml child = xml.findFirst(name);
451
452if(!child){
453child = xml.appendChild(name);
454ofLogVerbose("ofXml") << "creating group " << name;
455}
456if(parameter.type() == typeid(ofParameterGroup).name()){
457const ofParameterGroup & group = static_cast <const ofParameterGroup &>(parameter);
458
459ofLogVerbose("ofXml") << "group " << name;
460for(auto & p: group){
461ofSerialize(child, *p);
462}
463ofLogVerbose("ofXml") << "end group " << name;
464}else{
465string value = parameter.toString();
466child.set(value);
467}
468}
469
470
471void ofDeserialize(const ofXml & xml, ofAbstractParameter & parameter){
472if(!parameter.isSerializable()){
473return;
474}
475string name = parameter.getEscapedName();
476
477ofXml child = xml.findFirst(name);
478if(child){
479if(parameter.type() == typeid(ofParameterGroup).name()){
480ofParameterGroup & group = static_cast <ofParameterGroup &>(parameter);
481for(auto & p: group){
482ofDeserialize(child, *p);
483}
484}else{
485if(parameter.type() == typeid(ofParameter <int> ).name()){
486parameter.cast <int>() = child.getIntValue();
487}else if(parameter.type() == typeid(ofParameter <float> ).name()){
488parameter.cast <float>() = child.getFloatValue();
489}else if(parameter.type() == typeid(ofParameter <bool> ).name()){
490parameter.cast <bool>() = child.getBoolValue();
491}else if(parameter.type() == typeid(ofParameter <string> ).name()){
492parameter.cast <string>() = child.getValue();
493}else{
494parameter.fromString(child.getValue());
495}
496}
497}
498}
499