00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 #include "GTools.hpp"
00032 #include "GException.hpp"
00033 #include "GFilename.hpp"
00034 #include "GXmlDocument.hpp"
00035 #include "GXmlElement.hpp"
00036
00037
00038 #define G_PARSE_START "GXmlElement::parse_start(std::string&)"
00039 #define G_PARSE_STOP "GXmlElement::parse_stop(std::string&)"
00040 #define G_PARSE_ATTRIBUTE "GXmlElement::parse_attribute(size_t*, "\
00041 "std::string&)"
00042
00043
00044 const int g_indent = 2;
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062 GXmlElement::GXmlElement(void) : GXmlNode()
00063 {
00064
00065 init_members();
00066
00067
00068 return;
00069 }
00070
00071
00072
00073
00074
00075
00076
00077 GXmlElement::GXmlElement(const GXmlElement& node) : GXmlNode(node)
00078 {
00079
00080 init_members();
00081
00082
00083 copy_members(node);
00084
00085
00086 return;
00087 }
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099 GXmlElement::GXmlElement(const std::string& segment) : GXmlNode()
00100 {
00101
00102 init_members();
00103
00104
00105 parse_start(segment);
00106
00107
00108 return;
00109 }
00110
00111
00112
00113
00114
00115 GXmlElement::~GXmlElement(void)
00116 {
00117
00118 free_members();
00119
00120
00121 return;
00122 }
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137 GXmlElement& GXmlElement::operator=(const GXmlElement& node)
00138 {
00139
00140 if (this != &node) {
00141
00142
00143 this->GXmlNode::operator=(node);
00144
00145
00146 free_members();
00147
00148
00149 init_members();
00150
00151
00152 copy_members(node);
00153
00154 }
00155
00156
00157 return *this;
00158 }
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172 void GXmlElement::clear(void)
00173 {
00174
00175 free_members();
00176 this->GXmlNode::free_members();
00177
00178
00179 this->GXmlNode::init_members();
00180 init_members();
00181
00182
00183 return;
00184 }
00185
00186
00187
00188
00189
00190
00191
00192 GXmlElement* GXmlElement::clone(void) const
00193 {
00194
00195 return new GXmlElement(*this);
00196 }
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208 std::string GXmlElement::attribute(const std::string& name) const
00209 {
00210
00211 std::string value = "";
00212
00213
00214 for (int i = 0; i < m_attr.size(); ++i) {
00215 if (m_attr[i]->name() == name) {
00216 value = m_attr[i]->value();
00217 break;
00218 }
00219 }
00220
00221
00222 return value;
00223 }
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239 void GXmlElement::attribute(const std::string& name, const std::string& value)
00240 {
00241
00242 GXmlAttribute* attr = NULL;
00243
00244
00245 for (int i = 0; i < m_attr.size(); ++i) {
00246 if (m_attr[i]->name() == name) {
00247 attr = m_attr[i];
00248 break;
00249 }
00250 }
00251
00252
00253
00254 if (attr == NULL) {
00255 attr = new GXmlAttribute;
00256 attr->name(name);
00257 m_attr.push_back(attr);
00258 }
00259
00260
00261 attr->value(value);
00262
00263
00264 return;
00265 }
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277 bool GXmlElement::has_attribute(const std::string& name) const
00278 {
00279
00280 bool found = false;
00281
00282
00283 for (int i = 0; i < m_attr.size(); ++i) {
00284 if (m_attr[i]->name() == name) {
00285 found = true;
00286 break;
00287 }
00288 }
00289
00290
00291 return found;
00292 }
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303 void GXmlElement::remove_attribute(const std::string& name)
00304 {
00305
00306 if (!m_attr.empty()) {
00307
00308
00309 int num = m_attr.size();
00310
00311
00312
00313
00314
00315 for (int i = 0; i < num; ++i) {
00316 if (m_attr[i]->name() == name) {
00317 m_attr.erase(m_attr.begin() + i);
00318 break;
00319 }
00320 }
00321
00322 }
00323
00324
00325 return;
00326 }
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337 void GXmlElement::write(GUrl& url, const int& indent) const
00338 {
00339
00340 for (int k = 0; k < indent; ++k) {
00341 url.printf(" ");
00342 }
00343
00344
00345 url.printf("<%s", m_name.c_str());
00346
00347
00348 for (int k = 0; k < m_attr.size(); ++k) {
00349 m_attr[k]->write(url);
00350 }
00351
00352
00353 if (is_empty()) {
00354 url.printf(" />\n");
00355 }
00356
00357
00358 else {
00359
00360
00361 if ((m_nodes.size() == 1) && (m_nodes[0]->type() == NT_TEXT)) {
00362
00363
00364 url.printf(">");
00365
00366
00367 m_nodes[0]->write(url, 0);
00368
00369
00370 url.printf("</%s>\n", m_name.c_str());
00371 }
00372
00373
00374 else {
00375
00376
00377 url.printf(">\n");
00378
00379
00380 for (int i = 0; i < m_nodes.size(); ++i) {
00381 m_nodes[i]->write(url, indent+g_indent);
00382 if (m_nodes[i]->type() == NT_TEXT) {
00383 url.printf("\n");
00384 }
00385 }
00386
00387
00388 for (int k = 0; k < indent; ++k) {
00389 url.printf(" ");
00390 }
00391 url.printf("</%s>\n", m_name.c_str());
00392
00393 }
00394
00395 }
00396
00397
00398 return;
00399 }
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409 std::string GXmlElement::print(const GChatter& chatter,
00410 const int& indent) const
00411 {
00412
00413 std::string result;
00414
00415
00416 if (chatter != SILENT) {
00417
00418
00419 result = gammalib::fill(" ", indent);
00420
00421
00422 result.append("GXmlElement::"+m_name);
00423 for (int k = 0; k < m_attr.size(); ++k) {
00424 result.append(m_attr[k]->print(chatter));
00425 }
00426
00427
00428 for (int i = 0; i < m_nodes.size(); ++i) {
00429 result.append("\n" + m_nodes[i]->print(chatter, indent+g_indent));
00430 }
00431
00432 }
00433
00434
00435 return result;
00436 }
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448 void GXmlElement::init_members(void)
00449 {
00450
00451 m_name.clear();
00452 m_attr.clear();
00453
00454
00455 return;
00456 }
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466 void GXmlElement::copy_members(const GXmlElement& node)
00467 {
00468
00469 m_name = node.m_name;
00470
00471
00472 m_attr.clear();
00473 for (int i = 0; i < node.m_attr.size(); ++i) {
00474 m_attr.push_back((node.m_attr[i]->clone()));
00475 }
00476
00477
00478 return;
00479 }
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489 void GXmlElement::free_members(void)
00490 {
00491
00492 for (int i = 0; i < m_attr.size(); ++i) {
00493 delete m_attr[i];
00494 m_attr[i] = NULL;
00495 }
00496
00497
00498 return;
00499 }
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514 void GXmlElement::parse_start(const std::string& segment)
00515 {
00516
00517 std::size_t pos_start = 0;
00518
00519
00520 int n = segment.length();
00521
00522
00523 if (n < 1) {
00524 throw GException::xml_syntax_error(G_PARSE_START, segment,
00525 "no element name specified");
00526 }
00527
00528
00529
00530 if (segment[0] == '<') {
00531 if (n < 2 || (segment.compare(0,1,"<") != 0) ||
00532 (segment.compare(n-1,1,">") != 0)) {
00533 throw GException::xml_syntax_error(G_PARSE_START, segment,
00534 "invalid tag brackets");
00535 }
00536 pos_start = 1;
00537 }
00538
00539
00540 std::size_t pos = segment.find_first_of("\x20\x09\x0d\x0a>", 1);
00541 if (pos == pos_start) {
00542 throw GException::xml_syntax_error(G_PARSE_START, segment,
00543 "no whitespace allowed before element name");
00544 }
00545 if (pos == std::string::npos) {
00546 if (pos_start == 1) {
00547 throw GException::xml_syntax_error(G_PARSE_START, segment,
00548 "element name not found");
00549 }
00550 }
00551 m_name = segment.substr(pos_start, pos-pos_start);
00552
00553
00554 while (pos != std::string::npos) {
00555 parse_attribute(&pos, segment);
00556 }
00557
00558
00559 return;
00560 }
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573 void GXmlElement::parse_stop(const std::string& segment)
00574 {
00575
00576 int n = segment.length();
00577
00578
00579 if (n < 3 || (segment.compare(0,2,"</") != 0) ||
00580 (segment.compare(n-1,1,">") != 0)) {
00581 throw GException::xml_syntax_error(G_PARSE_STOP, segment,
00582 "incorrect or missing tag brackets");
00583 }
00584
00585
00586 size_t pos = segment.find_first_of("\x20\x09\x0d\x0a>", 2);
00587 if (pos == 2) {
00588 throw GException::xml_syntax_error(G_PARSE_STOP, segment,
00589 "no whitespace allowed after \"</\"");
00590 }
00591 if (pos == std::string::npos) {
00592 throw GException::xml_syntax_error(G_PARSE_STOP, segment,
00593 "element name not found");
00594 }
00595 std::string name = segment.substr(2, pos-2);
00596 if (name != m_name) {
00597 throw GException::xml_syntax_error(G_PARSE_STOP, segment,
00598 "invalid name in element stop tag"
00599 " (found \""+name+"\", expected \""+m_name+"\"");
00600 }
00601
00602
00603 size_t pos2 = segment.find_first_of("\x20\x09\x0d\x0a>", pos);
00604 if (pos2 != n-1) {
00605 throw GException::xml_syntax_error(G_PARSE_STOP, segment,
00606 "invalid characters found after element name");
00607 }
00608
00609
00610 return;
00611 }
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628 void GXmlElement::parse_attribute(size_t* pos, const std::string& segment)
00629 {
00630
00631 do {
00632
00633 std::string error = segment.substr(*pos, segment.length()-*pos);
00634
00635
00636 std::size_t pos_name_start = segment.find_first_not_of("\x20\x09\x0d\x0a/>?", *pos);
00637 if (pos_name_start == std::string::npos) {
00638 *pos = std::string::npos;
00639 continue;
00640 }
00641
00642
00643 std::size_t pos_name_end = segment.find_first_of("\x20\x09\x0d\x0a=", pos_name_start);
00644 if (pos_name_end == std::string::npos) {
00645 throw GException::xml_syntax_error(G_PARSE_ATTRIBUTE, error,
00646 "invalid or missing attribute name");
00647 }
00648
00649
00650 std::size_t pos_equal = segment.find_first_of("=", pos_name_end);
00651 if (pos_equal == std::string::npos) {
00652 throw GException::xml_syntax_error(G_PARSE_ATTRIBUTE, error,
00653 "\"=\" sign not found for attribute");
00654 }
00655
00656
00657 std::size_t pos_value_start = segment.find_first_of("\x22\x27", pos_equal);
00658 if (pos_value_start == std::string::npos) {
00659 throw GException::xml_syntax_error(G_PARSE_ATTRIBUTE, error,
00660 "invalid or missing attribute value start hyphen");
00661 }
00662
00663
00664 std::string hyphen = segment.substr(pos_value_start, 1);
00665 pos_value_start++;
00666 if (pos_value_start >= segment.length()) {
00667 throw GException::xml_syntax_error(G_PARSE_ATTRIBUTE, error,
00668 "invalid or missing attribute value");
00669 }
00670
00671
00672 std::size_t pos_value_end = segment.find_first_of(hyphen, pos_value_start);
00673 if (pos_value_end == std::string::npos) {
00674 throw GException::xml_syntax_error(G_PARSE_ATTRIBUTE, error,
00675 "invalid or missing attribute value end hyphen");
00676 }
00677
00678
00679 std::size_t n_name = pos_name_end - pos_name_start;
00680 if (n_name < 1) {
00681 throw GException::xml_syntax_error(G_PARSE_ATTRIBUTE, error,
00682 "invalid or missing attribute name");
00683 }
00684 std::string name = segment.substr(pos_name_start, n_name);
00685
00686
00687
00688
00689 std::size_t n_value = pos_value_end - pos_value_start;
00690
00691
00692
00693
00694 std::string value = segment.substr(pos_value_start-1, n_value+2);
00695
00696
00697
00698
00699 GXmlAttribute* attr = new GXmlAttribute(name, value);
00700 m_attr.push_back(attr);
00701
00702
00703 pos_value_end++;
00704 if (pos_value_end >= segment.length()) {
00705 pos_value_end = std::string::npos;
00706 }
00707 *pos = pos_value_end;
00708
00709 } while (0);
00710
00711
00712 return;
00713 }