示例#1
0
文件: xml.cpp 项目: markettwp/Epiar
xmlNodePtr XMLFile::FindNode( const string& path, bool createIfMissing ) {
	xmlNodePtr cur,parent;
	string tokens = "/";
	vector<string> tokenized;
	vector<string>::iterator iter;
	string partialPath;

	// Check previously memoized values
	map<string,xmlNodePtr>::iterator val = values.find( path );
	if( val != values.end() ){ // If we found it
		// Check that we don't return memoized NULL values when instructed to createIfMissing.
		if( !((val->second==NULL) && createIfMissing) )
		{
			return val->second;
		}
	}

	if( xmlPtr == NULL ) {
		return( (xmlNodePtr)NULL );
	}

	// Initialize the xml navigation cursor
	cur = xmlDocGetRootElement( xmlPtr );
	if( cur == NULL ) {
		LogMsg(WARN, "XML file (%s) appears to be empty.", filename.c_str() );
		return( (xmlNodePtr)NULL );
	}
	
	tokenized = TokenizedString(path, tokens);
	iter = tokenized.begin();

	// The root is optional since it isn't a Child.
	if( !xmlStrcmp(cur->name, (const xmlChar *)(tokenized.front().c_str()) ) ) {
		++iter;
	}

	// Walk the tokenized path
	// If FirstChildNamed() doesn't find the path, it will return NULL
	for(; iter != tokenized.end() && cur != NULL; ++iter) {
		partialPath = *iter;
		if( partialPath.find_first_of(tokens) != string::npos) {
			continue;
		}
		parent = cur;
		cur = FirstChildNamed(parent, partialPath.c_str());
		if( (createIfMissing) && (cur==NULL) )
		{
			cur = xmlNewChild(parent, NULL, BAD_CAST partialPath.c_str(), NULL );
		}
	}

	// Memoize this result for later
	values[path] = cur;

	return( cur );
}
示例#2
0
/**\brief Search this Container for a Widget
 *
 * \see Container::Search
 */
Widget *Container::Search( string full_query ) {
	int section = 0;
	char token;
	string subquery;
	string tokens = "/[]\"'(,)";
	vector<string> tokenized;
	vector<string>::iterator iter;
	list<Widget *>::iterator i;

	Container *current = this;

	// Temporary query values
	typedef struct {
		union {
			int flags;
			struct {
				int FOUND_COORD :1;
				int FOUND_TYPE  :1;
				int FOUND_NAME  :1;
				int FOUND_INDEX :1;
			};
		};
		int x,y;
		string type;
		string name;
		int index;
	} Query;
	Query query = {{0},0,0,"","",0};

	// Tokenize the String
	tokenized = TokenizedString( full_query, tokens );

	// Check the Start of the Query
	iter = tokenized.begin();
	if( (tokenized.size() >= 2) && (tokenized[0] == "") && (tokenized[1] == "/") ) {
		++iter; ++iter;
		++section;
	} else {
		LogMsg(ERR, "Query '%s' does not start with '/'.", full_query.c_str() );
		return NULL;
	}
	
	// Search all the tokens
	LogMsg(INFO, "QUERY: '%s'", full_query.c_str() );
	for(; iter != tokenized.end(); ++iter ) {
		subquery = (*iter);
		// LogMsg(INFO, "token: '%s'", (*iter).c_str() );
		token = subquery[0];
		if( subquery == "" ) { continue; }

		// If we're checking a Token, we need to be in a Container
		if( !( (current->GetMask()) & WIDGET_CONTAINER ) ) {
			LogMsg(INFO, "The query '%s' reached a non-container Widget and aborted at section %d.", full_query.c_str(), section );
			return NULL;
		}

		// If this is not a token then it is Widget Type
		if( subquery.find_first_of(tokens) != string::npos) {
			assert( subquery.size() == 1 );

			switch( token ) {
				// Boundary: Search the Children
				case '/':
				{
					int ind = 0;
					assert( (current->GetMask()) & WIDGET_CONTAINER );
					for( i = current->children.begin(); i != current->children.end(); ++i ) {
						// LogMsg(DEBUG1, "Checking %s %s (%d,%d) 0x%08X\n", (*i)->GetName().c_str(), (*i)->GetType().c_str(), (*i)->GetX(), (*i)->GetY(), (*i)->GetMask() );
						if( query.FOUND_NAME && (query.name != (*i)->GetName()) ) {
							continue;
						}
						if( query.FOUND_TYPE && (query.type != (*i)->GetType()) ) {
							continue;
						}
						if( query.FOUND_COORD && ((*i)->Contains(query.x, query.y) == false) ) {
							continue;
						}
						if( query.FOUND_INDEX && (query.index != ind) ) {
							ind++;
							continue;
						} 
						// Found a match!
						current = (Container*)(*i);
						// Forget about the current query
						query.flags = 0;
						break;
					}
					
					if( i == current->children.end() ) {
						LogMsg(INFO, "The query '%s' failed to find a widget at section %d", full_query.c_str(), section );
						return NULL;
					}
					++section;
					break;
				}

				// Bracketed number: Container Index
				case '[':
				{
					query.FOUND_INDEX = 1;
					query.index = convertTo<int>( *(++iter) );
					assert( *(++iter) == "]" );
					break;
				}

				// Quoted String: Widget Name
				case '\'':
				case '"':
				{
					query.FOUND_NAME = 1;
					query.name = *(++iter);
					++iter;
					assert( (*(iter) == "\"") || (*(iter) == "'") );
					break;
				}

				// Paren Tuple: Widget's Relative coordinate
				case '(': 
				{
					query.FOUND_COORD = 1;
					query.x = convertTo<int>( *(++iter) );
					assert( *(++iter) == "," );
					query.y = convertTo<int>( *(++iter) );
					assert( *(++iter) == ")" );
					break;
				}

				default:
					LogMsg(ERR, "Unexpected token '%c' in query '%s'", token, full_query.c_str() );
					assert(0);
					return NULL;
			}
		}

		// Plain String: Widget Type
		else if( subquery.size() > 0 ) {
			query.FOUND_TYPE = 1;
			query.type = subquery;
		}

		// Empty String, skip it.
		else { }
	}

	if( query.flags != 0 ) {
		LogMsg(WARN, "Query '%s' did not end with a '/'", full_query.c_str() );
	}

	LogMsg(DEBUG1, "Found %s %s (%d,%d) 0x%08X\n", (*i)->GetName().c_str(), (*i)->GetType().c_str(), (*i)->GetX(), (*i)->GetY(), (*i)->GetMask() );
	return current;
}