llxmltree.cpp

Go to the documentation of this file.
00001 
00032 #include "linden_common.h"
00033 
00034 #include "llxmltree.h"
00035 #include "v3color.h"
00036 #include "v4color.h"
00037 #include "v4coloru.h"
00038 #include "v3math.h"
00039 #include "v3dmath.h"
00040 #include "v4math.h"
00041 #include "llquaternion.h"
00042 #include "lluuid.h"
00043 
00045 // LLXmlTree
00046 
00047 // static
00048 LLStdStringTable LLXmlTree::sAttributeKeys(1024);
00049 
00050 LLXmlTree::LLXmlTree()
00051         : mRoot( NULL ),
00052           mNodeNames(512)
00053 {
00054 }
00055 
00056 LLXmlTree::~LLXmlTree()
00057 {
00058         cleanup();
00059 }
00060 
00061 void LLXmlTree::cleanup()
00062 {
00063         delete mRoot;
00064         mRoot = NULL;
00065         mNodeNames.cleanup();
00066 }
00067 
00068 
00069 BOOL LLXmlTree::parseFile(const std::string &path, BOOL keep_contents)
00070 {
00071         delete mRoot;
00072         mRoot = NULL;
00073 
00074         LLXmlTreeParser parser(this);
00075         BOOL success = parser.parseFile( path, &mRoot, keep_contents );
00076         if( !success )
00077         {
00078                 S32 line_number = parser.getCurrentLineNumber();
00079                 const char* error =  parser.getErrorString();
00080                 llwarns << "LLXmlTree parse failed.  Line " << line_number << ": " << error << llendl;
00081         }
00082         return success;
00083 }
00084 
00085 void LLXmlTree::dump()
00086 {
00087         if( mRoot )
00088         {
00089                 dumpNode( mRoot, "    " );
00090         }
00091 }
00092 
00093 void LLXmlTree::dumpNode( LLXmlTreeNode* node, const LLString& prefix )
00094 {
00095         node->dump( prefix );
00096 
00097         LLString new_prefix = prefix + "    ";
00098         for( LLXmlTreeNode* child = node->getFirstChild(); child; child = node->getNextChild() )
00099         {
00100                 dumpNode( child, new_prefix );
00101         }
00102 }
00103 
00105 // LLXmlTreeNode
00106 
00107 LLXmlTreeNode::LLXmlTreeNode( const std::string& name, LLXmlTreeNode* parent, LLXmlTree* tree )
00108         : mName(name),
00109           mParent(parent),
00110           mTree(tree)
00111 {
00112 }
00113 
00114 LLXmlTreeNode::~LLXmlTreeNode()
00115 {
00116         attribute_map_t::iterator iter;
00117         for (iter=mAttributes.begin(); iter != mAttributes.end(); iter++)
00118                 delete iter->second;
00119         child_list_t::iterator child_iter;
00120         for (child_iter=mChildList.begin(); child_iter != mChildList.end(); child_iter++)
00121                 delete *child_iter;
00122 }
00123  
00124 void LLXmlTreeNode::dump( const LLString& prefix )
00125 {
00126         llinfos << prefix << mName ;
00127         if( !mContents.empty() )
00128         {
00129                 llcont << " contents = \"" << mContents << "\"";
00130         }
00131         attribute_map_t::iterator iter;
00132         for (iter=mAttributes.begin(); iter != mAttributes.end(); iter++)
00133         {
00134                 LLStdStringHandle key = iter->first;
00135                 const LLString* value = iter->second;
00136                 llcont << prefix << " " << key << "=" << (value->empty() ? "NULL" : *value);
00137         }
00138         llcont << llendl;
00139 } 
00140 
00141 BOOL LLXmlTreeNode::hasAttribute(const std::string& name)
00142 {
00143         LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00144         attribute_map_t::iterator iter = mAttributes.find(canonical_name);
00145         return (iter == mAttributes.end()) ? false : true;
00146 }
00147 
00148 void LLXmlTreeNode::addAttribute(const std::string& name, const std::string& value)
00149 {
00150         LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00151         const LLString *newstr = new LLString(value);
00152         mAttributes[canonical_name] = newstr; // insert + copy
00153 }
00154 
00155 LLXmlTreeNode*  LLXmlTreeNode::getFirstChild()
00156 {
00157         mChildListIter = mChildList.begin();
00158         return getNextChild();
00159 }
00160 LLXmlTreeNode*  LLXmlTreeNode::getNextChild()
00161 {
00162         if (mChildListIter == mChildList.end())
00163                 return 0;
00164         else
00165                 return *mChildListIter++;
00166 }
00167 
00168 LLXmlTreeNode* LLXmlTreeNode::getChildByName(const std::string& name)
00169 {
00170         LLStdStringHandle tableptr = mTree->mNodeNames.checkString(name);
00171         mChildMapIter = mChildMap.lower_bound(tableptr);
00172         mChildMapEndIter = mChildMap.upper_bound(tableptr);
00173         return getNextNamedChild();
00174 }
00175 
00176 LLXmlTreeNode* LLXmlTreeNode::getNextNamedChild()
00177 {
00178         if (mChildMapIter == mChildMapEndIter)
00179                 return NULL;
00180         else
00181                 return (mChildMapIter++)->second;
00182 }
00183 
00184 void LLXmlTreeNode::appendContents(const std::string& str)
00185 {
00186         mContents.append( str );
00187 }
00188 
00189 void LLXmlTreeNode::addChild(LLXmlTreeNode* child)
00190 {
00191         llassert( child );
00192         mChildList.push_back( child );
00193 
00194         // Add a name mapping to this node
00195         LLStdStringHandle tableptr = mTree->mNodeNames.insert(child->mName);
00196         mChildMap.insert( child_map_t::value_type(tableptr, child));
00197         
00198         child->mParent = this;
00199 }
00200 
00202 
00203 // These functions assume that name is already in mAttritrubteKeys
00204 
00205 BOOL LLXmlTreeNode::getFastAttributeBOOL(LLStdStringHandle canonical_name, BOOL& value)
00206 {
00207         const LLString *s = getAttribute( canonical_name );
00208         return s && LLString::convertToBOOL( *s, value );
00209 }
00210 
00211 BOOL LLXmlTreeNode::getFastAttributeU8(LLStdStringHandle canonical_name, U8& value)
00212 {
00213         const LLString *s = getAttribute( canonical_name );
00214         return s && LLString::convertToU8( *s, value );
00215 }
00216 
00217 BOOL LLXmlTreeNode::getFastAttributeS8(LLStdStringHandle canonical_name, S8& value)
00218 {
00219         const LLString *s = getAttribute( canonical_name );
00220         return s && LLString::convertToS8( *s, value );
00221 }
00222 
00223 BOOL LLXmlTreeNode::getFastAttributeS16(LLStdStringHandle canonical_name, S16& value)
00224 {
00225         const LLString *s = getAttribute( canonical_name );
00226         return s && LLString::convertToS16( *s, value );
00227 }
00228 
00229 BOOL LLXmlTreeNode::getFastAttributeU16(LLStdStringHandle canonical_name, U16& value)
00230 {
00231         const LLString *s = getAttribute( canonical_name );
00232         return s && LLString::convertToU16( *s, value );
00233 }
00234 
00235 BOOL LLXmlTreeNode::getFastAttributeU32(LLStdStringHandle canonical_name, U32& value)
00236 {
00237         const LLString *s = getAttribute( canonical_name );
00238         return s && LLString::convertToU32( *s, value );
00239 }
00240 
00241 BOOL LLXmlTreeNode::getFastAttributeS32(LLStdStringHandle canonical_name, S32& value)
00242 {
00243         const LLString *s = getAttribute( canonical_name );
00244         return s && LLString::convertToS32( *s, value );
00245 }
00246 
00247 BOOL LLXmlTreeNode::getFastAttributeF32(LLStdStringHandle canonical_name, F32& value)
00248 {
00249         const LLString *s = getAttribute( canonical_name );
00250         return s && LLString::convertToF32( *s, value );
00251 }
00252 
00253 BOOL LLXmlTreeNode::getFastAttributeF64(LLStdStringHandle canonical_name, F64& value)
00254 {
00255         const LLString *s = getAttribute( canonical_name );
00256         return s && LLString::convertToF64( *s, value );
00257 }
00258 
00259 BOOL LLXmlTreeNode::getFastAttributeColor(LLStdStringHandle canonical_name, LLColor4& value)
00260 {
00261         const LLString *s = getAttribute( canonical_name );
00262         return s ? LLColor4::parseColor(s->c_str(), &value) : FALSE;
00263 }
00264 
00265 BOOL LLXmlTreeNode::getFastAttributeColor4(LLStdStringHandle canonical_name, LLColor4& value)
00266 {
00267         const LLString *s = getAttribute( canonical_name );
00268         return s ? LLColor4::parseColor4(s->c_str(), &value) : FALSE;
00269 }
00270 
00271 BOOL LLXmlTreeNode::getFastAttributeColor4U(LLStdStringHandle canonical_name, LLColor4U& value)
00272 {
00273         const LLString *s = getAttribute( canonical_name );
00274         return s ? LLColor4U::parseColor4U(s->c_str(), &value ) : FALSE;
00275 }
00276 
00277 BOOL LLXmlTreeNode::getFastAttributeVector3(LLStdStringHandle canonical_name, LLVector3& value)
00278 {
00279         const LLString *s = getAttribute( canonical_name );
00280         return s ? LLVector3::parseVector3(s->c_str(), &value ) : FALSE;
00281 }
00282 
00283 BOOL LLXmlTreeNode::getFastAttributeVector3d(LLStdStringHandle canonical_name, LLVector3d& value)
00284 {
00285         const LLString *s = getAttribute( canonical_name );
00286         return s ? LLVector3d::parseVector3d(s->c_str(),  &value ) : FALSE;
00287 }
00288 
00289 BOOL LLXmlTreeNode::getFastAttributeQuat(LLStdStringHandle canonical_name, LLQuaternion& value)
00290 {
00291         const LLString *s = getAttribute( canonical_name );
00292         return s ? LLQuaternion::parseQuat(s->c_str(), &value ) : FALSE;
00293 }
00294 
00295 BOOL LLXmlTreeNode::getFastAttributeUUID(LLStdStringHandle canonical_name, LLUUID& value)
00296 {
00297         const LLString *s = getAttribute( canonical_name );
00298         return s ? LLUUID::parseUUID(s->c_str(), &value ) : FALSE;
00299 }
00300 
00301 BOOL LLXmlTreeNode::getFastAttributeString(LLStdStringHandle canonical_name, LLString& value)
00302 {
00303         const LLString *s = getAttribute( canonical_name );
00304         if( !s )
00305         {
00306                 return FALSE;
00307         }
00308 
00309         value = *s;
00310         return TRUE;
00311 }
00312 
00313 
00315 
00316 BOOL LLXmlTreeNode::getAttributeBOOL(const std::string& name, BOOL& value)
00317 {
00318         LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00319         return getFastAttributeBOOL(canonical_name, value);
00320 }
00321 
00322 BOOL LLXmlTreeNode::getAttributeU8(const std::string& name, U8& value)
00323 {
00324         LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00325         return getFastAttributeU8(canonical_name, value);
00326 }
00327 
00328 BOOL LLXmlTreeNode::getAttributeS8(const std::string& name, S8& value)
00329 {
00330         LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00331         return getFastAttributeS8(canonical_name, value);
00332 }
00333 
00334 BOOL LLXmlTreeNode::getAttributeS16(const std::string& name, S16& value)
00335 {
00336         LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00337         return getFastAttributeS16(canonical_name, value);
00338 }
00339 
00340 BOOL LLXmlTreeNode::getAttributeU16(const std::string& name, U16& value)
00341 {
00342         LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00343         return getFastAttributeU16(canonical_name, value);
00344 }
00345 
00346 BOOL LLXmlTreeNode::getAttributeU32(const std::string& name, U32& value)
00347 {
00348         LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00349         return getFastAttributeU32(canonical_name, value);
00350 }
00351 
00352 BOOL LLXmlTreeNode::getAttributeS32(const std::string& name, S32& value)
00353 {
00354         LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00355         return getFastAttributeS32(canonical_name, value);
00356 }
00357 
00358 BOOL LLXmlTreeNode::getAttributeF32(const std::string& name, F32& value)
00359 {
00360         LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00361         return getFastAttributeF32(canonical_name, value);
00362 }
00363 
00364 BOOL LLXmlTreeNode::getAttributeF64(const std::string& name, F64& value)
00365 {
00366         LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00367         return getFastAttributeF64(canonical_name, value);
00368 }
00369 
00370 BOOL LLXmlTreeNode::getAttributeColor(const std::string& name, LLColor4& value)
00371 {
00372         LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00373         return getFastAttributeColor(canonical_name, value);
00374 }
00375 
00376 BOOL LLXmlTreeNode::getAttributeColor4(const std::string& name, LLColor4& value)
00377 {
00378         LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00379         return getFastAttributeColor4(canonical_name, value);
00380 }
00381 
00382 BOOL LLXmlTreeNode::getAttributeColor4U(const std::string& name, LLColor4U& value)
00383 {
00384         LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00385         return getFastAttributeColor4U(canonical_name, value);
00386 }
00387 
00388 BOOL LLXmlTreeNode::getAttributeVector3(const std::string& name, LLVector3& value)
00389 {
00390         LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00391         return getFastAttributeVector3(canonical_name, value);
00392 }
00393 
00394 BOOL LLXmlTreeNode::getAttributeVector3d(const std::string& name, LLVector3d& value)
00395 {
00396         LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00397         return getFastAttributeVector3d(canonical_name, value);
00398 }
00399 
00400 BOOL LLXmlTreeNode::getAttributeQuat(const std::string& name, LLQuaternion& value)
00401 {
00402         LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00403         return getFastAttributeQuat(canonical_name, value);
00404 }
00405 
00406 BOOL LLXmlTreeNode::getAttributeUUID(const std::string& name, LLUUID& value)
00407 {
00408         LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00409         return getFastAttributeUUID(canonical_name, value);
00410 }
00411 
00412 BOOL LLXmlTreeNode::getAttributeString(const std::string& name, LLString& value)
00413 {
00414         LLStdStringHandle canonical_name = LLXmlTree::sAttributeKeys.addString( name );
00415         return getFastAttributeString(canonical_name, value);
00416 }
00417 
00418 /*
00419   The following xml <message> nodes will all return the string from getTextContents():
00420   "The quick brown fox\n  Jumps over the lazy dog"
00421 
00422   1. HTML paragraph format:
00423                 <message>
00424                 <p>The quick brown fox</p>
00425                 <p>  Jumps over the lazy dog</p>
00426                 </message>
00427   2. Each quoted section -> paragraph:
00428                 <message>
00429                 "The quick brown fox"
00430                 "  Jumps over the lazy dog"
00431                 </message>
00432   3. Literal text with beginning and trailing whitespace removed:
00433                 <message>
00434 The quick brown fox
00435   Jumps over the lazy dog
00436                 </message>
00437   
00438 */
00439 
00440 LLString LLXmlTreeNode::getTextContents()
00441 {
00442         std::string msg;
00443         LLXmlTreeNode* p = getChildByName("p");
00444         if (p)
00445         {
00446                 // Case 1: node has <p>text</p> tags
00447                 while (p)
00448                 {
00449                         msg += p->getContents() + "\n";
00450                         p = getNextNamedChild();
00451                 }
00452         }
00453         else
00454         {
00455                 std::string::size_type n = mContents.find_first_not_of(" \t\n");
00456                 if (n != std::string::npos && mContents[n] == '\"')
00457                 {
00458                         // Case 2: node has quoted text
00459                         S32 num_lines = 0;
00460                         while(1)
00461                         {
00462                                 // mContents[n] == '"'
00463                                 ++n;
00464                                 std::string::size_type t = n;
00465                                 std::string::size_type m = 0;
00466                                 // fix-up escaped characters
00467                                 while(1)
00468                                 {
00469                                         m = mContents.find_first_of("\\\"", t); // find first \ or "
00470                                         if ((m == std::string::npos) || (mContents[m] == '\"'))
00471                                         {
00472                                                 break;
00473                                         }
00474                                         mContents.erase(m,1);
00475                                         t = m+1;
00476                                 }
00477                                 if (m == std::string::npos)
00478                                 {
00479                                         break;
00480                                 }
00481                                 // mContents[m] == '"'
00482                                 num_lines++;
00483                                 msg += mContents.substr(n,m-n) + "\n";
00484                                 n = mContents.find_first_of("\"", m+1);
00485                                 if (n == std::string::npos)
00486                                 {
00487                                         if (num_lines == 1)
00488                                         {
00489                                                 msg.erase(msg.size()-1); // remove "\n" if only one line
00490                                         }
00491                                         break;
00492                                 }
00493                         }
00494                 }
00495                 else
00496                 {
00497                         // Case 3: node has embedded text (beginning and trailing whitespace trimmed)
00498                         msg = mContents;
00499                 }
00500         }
00501         return msg;
00502 }
00503         
00504 
00506 // LLXmlTreeParser
00507 
00508 LLXmlTreeParser::LLXmlTreeParser(LLXmlTree* tree) 
00509         : mTree(tree),
00510           mRoot( NULL ),
00511           mCurrent( NULL ),
00512           mDump( FALSE )
00513 {
00514 }
00515 
00516 LLXmlTreeParser::~LLXmlTreeParser() 
00517 {
00518 }
00519 
00520 BOOL LLXmlTreeParser::parseFile(const std::string &path, LLXmlTreeNode** root, BOOL keep_contents)
00521 {
00522         llassert( !mRoot );
00523         llassert( !mCurrent );
00524 
00525         mKeepContents = keep_contents;
00526 
00527         BOOL success = LLXmlParser::parseFile(path);
00528 
00529         *root = mRoot;
00530         mRoot = NULL;
00531 
00532         if( success )
00533         {
00534                 llassert( !mCurrent );
00535         }
00536         mCurrent = NULL;
00537         
00538         return success;
00539 }
00540 
00541 
00542 const std::string& LLXmlTreeParser::tabs()
00543 {
00544         static LLString s;
00545         s = "";
00546         S32 num_tabs = getDepth() - 1;
00547         for( S32 i = 0; i < num_tabs; i++)
00548         {
00549                 s += "    ";
00550         }
00551         return s;
00552 }
00553 
00554 void LLXmlTreeParser::startElement(const char* name, const char **atts) 
00555 {
00556         if( mDump )
00557         {
00558                 llinfos << tabs() << "startElement " << name << llendl;
00559                 
00560                 S32 i = 0;
00561                 while( atts[i] && atts[i+1] )
00562                 {
00563                         llinfos << tabs() << "attribute: " << atts[i] << "=" << atts[i+1] << llendl;
00564                         i += 2;
00565                 }
00566         }
00567 
00568         LLXmlTreeNode* child = CreateXmlTreeNode( std::string(name), mCurrent );
00569 
00570         S32 i = 0;
00571         while( atts[i] && atts[i+1] )
00572         {
00573                 child->addAttribute( atts[i], atts[i+1] );
00574                 i += 2;
00575         }
00576 
00577         if( mCurrent )
00578         {
00579                 mCurrent->addChild( child );
00580 
00581         }
00582         else
00583         {
00584                 llassert( !mRoot );
00585                 mRoot = child;
00586         }
00587         mCurrent = child;
00588 }
00589 
00590 LLXmlTreeNode* LLXmlTreeParser::CreateXmlTreeNode(const std::string& name, LLXmlTreeNode* parent)
00591 {
00592         return new LLXmlTreeNode(name, parent, mTree);
00593 }
00594 
00595 
00596 void LLXmlTreeParser::endElement(const char* name) 
00597 {
00598         if( mDump )
00599         {
00600                 llinfos << tabs() << "endElement " << name << llendl;
00601         }
00602 
00603         if( !mCurrent->mContents.empty() )
00604         {
00605                 LLString::trim(mCurrent->mContents);
00606                 LLString::removeCRLF(mCurrent->mContents);
00607         }
00608 
00609         mCurrent = mCurrent->getParent();
00610 }
00611 
00612 void LLXmlTreeParser::characterData(const char *s, int len) 
00613 {
00614         LLString str(s, len);
00615         if( mDump )
00616         {
00617                 llinfos << tabs() << "CharacterData " << str << llendl;
00618         }
00619 
00620         if (mKeepContents)
00621         {
00622                 mCurrent->appendContents( str );
00623         }
00624 }
00625 
00626 void LLXmlTreeParser::processingInstruction(const char *target, const char *data)
00627 {
00628         if( mDump )
00629         {
00630                 llinfos << tabs() << "processingInstruction " << data << llendl;
00631         }
00632 }
00633 
00634 void LLXmlTreeParser::comment(const char *data)
00635 {
00636         if( mDump )
00637         {
00638                 llinfos << tabs() << "comment " << data << llendl;
00639         }
00640 }
00641 
00642 void LLXmlTreeParser::startCdataSection()
00643 {
00644         if( mDump )
00645         {
00646                 llinfos << tabs() << "startCdataSection" << llendl;
00647         }
00648 }
00649 
00650 void LLXmlTreeParser::endCdataSection()
00651 {
00652         if( mDump )
00653         {
00654                 llinfos << tabs() << "endCdataSection" << llendl;
00655         }
00656 }
00657 
00658 void LLXmlTreeParser::defaultData(const char *s, int len)
00659 {
00660         if( mDump )
00661         {
00662                 LLString str(s, len);
00663                 llinfos << tabs() << "defaultData " << str << llendl;
00664         }
00665 }
00666 
00667 void LLXmlTreeParser::unparsedEntityDecl(
00668         const char* entity_name,
00669         const char* base,
00670         const char* system_id,
00671         const char* public_id,
00672         const char* notation_name)
00673 {
00674         if( mDump )
00675         {
00676                 llinfos << tabs() << "unparsed entity:"                 << llendl;
00677                 llinfos << tabs() << "    entityName "                  << entity_name  << llendl;
00678                 llinfos << tabs() << "    base "                                << base                 << llendl;
00679                 llinfos << tabs() << "    systemId "                    << system_id    << llendl;
00680                 llinfos << tabs() << "    publicId "                    << public_id    << llendl;
00681                 llinfos << tabs() << "    notationName "                << notation_name<< llendl;
00682         }
00683 }
00684 
00685 void test_llxmltree()
00686 {
00687         LLXmlTree tree;
00688         BOOL success = tree.parseFile( "test.xml" );
00689         if( success )
00690         {
00691                 tree.dump();
00692         }
00693 }
00694 

Generated on Thu Jul 1 06:09:49 2010 for Second Life Viewer by  doxygen 1.4.7