Exemplo n.º 1
0
	char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
	{
		// This is a recursive method, but thinking about it "at the current level"
		// it is a pretty simple flat list:
		//		<foo/>
		//		<!-- comment -->
		//
		// With a special case:
		//		<foo>
		//		</foo>
		//		<!-- comment -->
		//
		// Where the closing element (/foo) *must* be the next thing after the opening
		// element, and the names must match. BUT the tricky bit is that the closing
		// element will be read by the child.
		//
		// 'endTag' is the end tag for this node, it is returned by a call to a child.
		// 'parentEnd' is the end tag for the parent, which is filled in and returned.

		while( p && *p ) {
			XMLNode* node = 0;

			p = _document->Identify( p, &node );
			if ( p == 0 || node == 0 ) {
				break;
			}

			StrPair endTag;
			p = node->ParseDeep( p, &endTag );
			if ( !p ) {
				DELETE_NODE( node );
				node = 0;
				if ( !_document->Error() ) {
					_document->SetError( XML_ERROR_PARSING, 0, 0 );
				}
				break;
			}

			// We read the end tag. Return it to the parent.
			if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
				if ( parentEnd ) {
					*parentEnd = static_cast<XMLElement*>(node)->_value;
				}
				node->_memPool->SetTracked();	// created and then immediately deleted.
				DELETE_NODE( node );
				return p;
			}

			// Handle an end tag returned to this level.
			// And handle a bunch of annoying errors.
			XMLElement* ele = node->ToElement();
			if ( ele ) {
				if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
					_document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
					p = 0;
				}
				else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
					_document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
					p = 0;
				}
				else if ( !endTag.Empty() ) {
					if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
						_document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
						p = 0;
					}
				}
			}
			if ( p == 0 ) {
				DELETE_NODE( node );
				node = 0;
			}
			if ( node ) {
				this->InsertEndChild( node );
			}
		}
		return 0;
	}