DSQSS
1.1
|
00001 00002 // Known bugs: 00003 // (1) Tags must be separated from other words by one or more spaces or 00004 // line breaks. Otherwise they are not recognized. 00005 // (2) The comment identifiers <!-- and --> must be separated by spaces or 00006 // line breaks, too. 00007 00008 #ifndef XML_H 00009 #define XML_H 00010 00011 #include "io.h" 00012 #include "array.h" 00013 00014 namespace XML { 00015 00016 //####################################################################### 00017 00018 class Block; 00019 00020 //====================================================================== 00021 00022 inline bool isCommentOpening(const string& key) { 00023 string sopen = "<!--"; 00024 int n = key.length(); 00025 if ( n < 4 ) return false; 00026 if ( key.substr(0,4) == sopen ) return true; 00027 return false; 00028 } 00029 00030 //====================================================================== 00031 00032 inline bool isOpening(const string& key) { 00033 int n = key.length(); 00034 if ( key[0] != '<' ) return false; 00035 if ( key[1] == '/' ) return false; 00036 if ( key[n-1] != '>' ) return false; 00037 return true; 00038 } 00039 00040 //====================================================================== 00041 00042 inline bool isClosing(const string& key) { 00043 int n = key.length(); 00044 if ( key[0] != '<' ) return false; 00045 if ( key[1] != '/' ) return false; 00046 if ( key[n-1] != '>' ) return false; 00047 return true; 00048 } 00049 00050 //====================================================================== 00051 00052 inline const string getOpeningName(const string& key) { 00053 if ( !isOpening(key) ) exit(0); 00054 int n = key.length(); 00055 string ans = key.substr(1,n-2); 00056 return ans; 00057 } 00058 00059 //====================================================================== 00060 00061 inline const string getClosingName(const string& key) { 00062 if ( ! isClosing(key) ) exit(0); 00063 int n = key.length(); 00064 string ans = key.substr(2,n-3); 00065 return ans; 00066 } 00067 00068 //####################################################################### 00069 00070 class Block { 00071 00072 private: 00073 00074 string Name; // the name of the element 00075 string* Word; // the whole list of words to be processed 00076 string Open; // the key at which to start the process 00077 string Close; // the key at which to terminate the process 00078 int NB; // the number of subelements 00079 Array<Block> SubBlock; 00080 int NV; // the number of values 00081 Array<string> Value; 00082 00083 public: 00084 00085 void initialize( string* word , const string& name = "" ); 00086 void initialize( const string& FNAME , const string& name = "" ); 00087 00088 Block () { 00089 NB = 0; 00090 NV = 0; 00091 }; 00092 00093 Block (const string& FNAME, const string& BNAME="") { 00094 NB = 0; 00095 NV = 0; 00096 initialize(FNAME, BNAME); 00097 }; 00098 00099 ~Block () { 00100 // printf("*** Destroying XML::Block (%s)\n", Name.c_str()); 00101 }; 00102 00103 const int& NumberOfBlocks() const { return NB; }; 00104 const int& NumberOfValues() const { return NV; }; 00105 string getJoinedString(); 00106 const string& getName() const; 00107 bool syntax_error(); 00108 void read(); 00109 int getInteger(const int i=0); 00110 double getDouble(const int i=0); 00111 string& getString(const int i=0); 00112 Block& getElement(const int i); 00113 Block& getElement(const string& name); 00114 Block& getElement( 00115 const string& name, const string& idkey, const int id ); 00116 Block& operator[] (const int& i) { return SubBlock[i]; }; 00117 Block& operator[] (const string& name); 00118 void dump(const string& prompt=""); 00119 00120 }; 00121 00122 //====================================================================== 00123 00124 inline string Block::getJoinedString() { 00125 string s=""; 00126 if ( NV == 0 ) return s; 00127 s = Value[0]; 00128 for (int i=1; i<NV; i++) { 00129 s += " "; 00130 s += Value[i]; 00131 } 00132 return s; 00133 } 00134 00135 //====================================================================== 00136 00137 inline const string& Block::getName() const { return Name; } 00138 00139 //====================================================================== 00140 00141 inline void Block::initialize( string* word , const string& name ) { 00142 // printf("Block::initialize> Pass 1\n"); 00143 Name = name; 00144 Word = word; 00145 if ( name == "" ) { 00146 Open = ""; 00147 Close = ""; 00148 } else { 00149 Open = "<"+name+">"; 00150 Close = "</"+name+">"; 00151 } 00152 read(); 00153 } 00154 00155 //====================================================================== 00156 00157 void Block::initialize( const string& FNAME , const string& name ) { 00158 // printf("Block::initialize> Pass 2\n"); // koko 00159 00160 FileReader F; 00161 F.open(FNAME.c_str()); 00162 int NW; 00163 string* W; 00164 F.getWordList( NW , W ); //単語の数、最初の括弧<algorithm> 00165 initialize( W , name ); 00166 delete [] W; 00167 } 00168 00169 //====================================================================== 00170 00171 inline bool Block::syntax_error() { 00172 NB = 0; 00173 NV = 0; 00174 int depth = 0; 00175 bool open = false; 00176 string SkipTo = ""; 00177 int i=0; 00178 while(Word[i] != EOL) { 00179 string& w = Word[i++]; 00180 if ( Name == "" ) { 00181 if ( isOpening(w) ) { 00182 const string name = getOpeningName(w); 00183 Name = name; 00184 Open = "<"+name+">"; 00185 Close = "</"+name+">"; 00186 } 00187 } 00188 if ( w == Open ) { 00189 depth++; 00190 open = true; 00191 continue; 00192 } 00193 if ( ! open ) continue; 00194 if ( w == Close ) { 00195 depth--; 00196 break; 00197 } 00198 if ( SkipTo != "" && w != SkipTo ) continue; 00199 if ( SkipTo != "" && w == SkipTo ) { 00200 depth--; 00201 SkipTo = ""; 00202 continue; 00203 } 00204 if ( isCommentOpening(w) ) { 00205 //cout << " ... beginning of a comment" << endl; 00206 depth++; 00207 SkipTo = "-->"; 00208 continue; 00209 } 00210 if ( isOpening(w) ) { 00211 //cout << " ... beginning of a subelement [" << w << "]" << endl; 00212 depth++; 00213 const string name = getOpeningName(w); 00214 //cout << "opening name : " << name << endl; 00215 SkipTo = "</" + name + ">"; 00216 NB++; 00217 continue; 00218 } 00219 if ( isClosing(w) ) { 00220 printf("Block::read> Error.\n"); 00221 printf(" An unexpected closing tag %s\n", w.c_str()); 00222 printf(" is detected in reading an element of name [%s].\n", 00223 getName().c_str()); 00224 return true; 00225 } 00226 //cout << " ... a value" << endl; 00227 NV++; 00228 } 00229 00230 if ( depth != 0 ) { 00231 printf("Block::read> Error.\n"); 00232 string expected = SkipTo; 00233 if ( expected == "" ) { 00234 expected = Close; 00235 } 00236 printf(" A missing closing tag %s\n", expected.c_str()); 00237 printf(" is detected in reading an element of name [%s].\n", 00238 getName().c_str()); 00239 return true; 00240 } 00241 00242 return false; 00243 00244 } 00245 00246 //====================================================================== 00247 00248 void Block::read() { 00249 00250 // printf("Block::read> Pass 1\n"); 00251 if ( syntax_error() ) exit(0); 00252 00253 if ( NV > 0 ) Value.init("Value",1,NV); 00254 if ( NB > 0 ) SubBlock.init("SubBlock",1,NB); 00255 00256 bool open = false; 00257 string SkipTo = ""; 00258 int ib = 0; 00259 int iv = 0; 00260 int i=0; 00261 while(true) { 00262 string& w = Word[i++]; 00263 // cout << "### " << w << endl; 00264 if ( w == Open ) { 00265 //printf("Opened. %s\n", w.c_str()); 00266 open = true; 00267 continue; 00268 } 00269 if ( ! open ) continue; 00270 if ( w == Close ) break; 00271 if ( SkipTo != "" && w != SkipTo ) continue; 00272 if ( SkipTo != "" && w == SkipTo ) { 00273 SkipTo = ""; 00274 continue; 00275 } 00276 if ( isCommentOpening(w) ) { 00277 SkipTo = "-->"; 00278 continue; 00279 } 00280 if ( isOpening(w) ) { 00281 const string name = getOpeningName(w); 00282 SubBlock[ib].initialize(&w,name); 00283 ib++; 00284 SkipTo = "</" + name + ">"; 00285 continue; 00286 } 00287 Value[iv] = w; 00288 iv++; 00289 } 00290 } 00291 00292 //====================================================================== 00293 00294 inline string& Block::getString(const int i) { 00295 #ifdef DEB 00296 if ( i < 0 || i >= NV ) { 00297 printf("Block::getString> Error.\n"); 00298 printf(" The argument (= %d) is out of the bounds [0,%d).\n", i, NV); 00299 exit(0); 00300 } 00301 #endif 00302 return Value[i]; 00303 } 00304 00305 //====================================================================== 00306 00307 inline int Block::getInteger(const int i) { 00308 #ifdef DEB 00309 if ( i < 0 || i >= NV ) { 00310 printf("Block::getInteger> Error.\n"); 00311 printf(" The argument (= %d) is out of the bounds [0,%d).\n", i, NV); 00312 exit(0); 00313 } 00314 #endif 00315 string& s = getString(i); 00316 return atoi(s.c_str()); 00317 } 00318 00319 //====================================================================== 00320 00321 inline double Block::getDouble(const int i) { 00322 #ifdef DEB 00323 if ( i < 0 || i >= NV ) { 00324 printf("Block::getDouble> Error.\n"); 00325 printf(" The argument (= %d) is out of the bounds [0,%d).\n", i, NV); 00326 exit(0); 00327 } 00328 #endif 00329 string& s = getString(i); 00330 return (double)atof(s.c_str()); 00331 } 00332 00333 //====================================================================== 00334 00335 inline Block& Block::getElement(const int i) { 00336 return SubBlock[i]; 00337 } 00338 00339 //====================================================================== 00340 00341 inline Block& Block::getElement(const string& name) { 00342 int ib; 00343 for (ib=0; ib<NB; ib++) { 00344 if ( name == SubBlock[ib].getName() ) break; 00345 } 00346 if ( ib < NB ) { 00347 return SubBlock[ib]; 00348 } else { 00349 printf("Block::getElement> Error.\n"); 00350 printf(" Tried to find a subblock '%s',\n", 00351 name.c_str()); 00352 printf(" but no such block exists in a block '%s'.\n", 00353 getName().c_str()); 00354 exit(0); 00355 } 00356 } 00357 00358 //====================================================================== 00359 00360 inline Block& Block::getElement( 00361 const string& name, const string& idkey, const int id ) { 00362 int ib; 00363 for (ib=0; ib<NB; ib++) { 00364 if ( name == SubBlock[ib].getName() ) { 00365 Block& E = SubBlock[ib]; 00366 // E.dump(); 00367 int id0 = E[idkey].getInteger(); 00368 // printf("id0 = %d, id = %d\n", id0, id); 00369 if ( id0 == id ) break; 00370 } 00371 } 00372 if ( ib < NB ) { 00373 return SubBlock[ib]; 00374 } else { 00375 printf("Block::getElement> Error.\n"); 00376 printf(" Tried to find a subblock '%s',\n", 00377 name.c_str()); 00378 printf(" but no such block exists in a block '%s'.\n", 00379 getName().c_str()); 00380 exit(0); 00381 } 00382 } 00383 00384 //====================================================================== 00385 00386 Block& Block::operator[] (const string& name) { 00387 Block& B = getElement(name); 00388 return B; 00389 } 00390 00391 //====================================================================== 00392 00393 inline void Block::dump(const string& prompt) { 00394 if ( NV == 1 && NB == 0 ) { 00395 printf("%s" , prompt.c_str()); 00396 printf("<%s>" , Name.c_str()); 00397 printf(" %s" , Value[0].c_str()); 00398 printf(" </%s>" , Name.c_str()); 00399 printf("\n"); 00400 } else { 00401 printf("%s<%s>\n", prompt.c_str(), Name.c_str()); 00402 for (int i=0; i<NV; i++) { 00403 printf("%s (%2d) %s\n", prompt.c_str(), i, Value[i].c_str()); 00404 } 00405 for (int i=0; i<NB; i++) { 00406 // printf("%s subelement %2d:\n", prompt.c_str(), i); 00407 SubBlock[i].dump(prompt+" "); 00408 } 00409 printf("%s</%s>\n", prompt.c_str(), Name.c_str()); 00410 } 00411 } 00412 00413 //####################################################################### 00414 00415 } // 先頭の namespace XML { と対になる } . 00416 00417 #endif