📄 tinyxmlparser.cpp
字号:
if ( doc )
doc->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0 );
}
return returnNode;
}
#ifdef TIXML_USE_STL
void TiXmlElement::StreamIn (TIXML_ISTREAM * in, TIXML_STRING * tag)
{
// We're called with some amount of pre-parsing. That is, some of "this"
// element is in "tag". Go ahead and stream to the closing ">"
while( in->good() )
{
int c = in->get();
(*tag) += (char) c ;
if ( c == '>' )
break;
}
if ( tag->length() < 3 ) return;
// Okay...if we are a "/>" tag, then we're done. We've read a complete tag.
// If not, identify and stream.
if ( tag->at( tag->length() - 1 ) == '>'
&& tag->at( tag->length() - 2 ) == '/' )
{
// All good!
return;
}
else if ( tag->at( tag->length() - 1 ) == '>' )
{
// There is more. Could be:
// text
// closing tag
// another node.
for ( ;; )
{
StreamWhiteSpace( in, tag );
// Do we have text?
if ( in->good() && in->peek() != '<' )
{
// Yep, text.
TiXmlText text( "" );
text.StreamIn( in, tag );
// What follows text is a closing tag or another node.
// Go around again and figure it out.
continue;
}
// We now have either a closing tag...or another node.
// We should be at a "<", regardless.
if ( !in->good() ) return;
assert( in->peek() == '<' );
int tagIndex = tag->length();
bool closingTag = false;
bool firstCharFound = false;
for( ;; )
{
if ( !in->good() )
return;
int c = in->peek();
if ( c == '>' )
break;
*tag += c;
in->get();
if ( !firstCharFound && c != '<' && !IsWhiteSpace( c ) )
{
firstCharFound = true;
if ( c == '/' )
closingTag = true;
}
}
// If it was a closing tag, then read in the closing '>' to clean up the input stream.
// If it was not, the streaming will be done by the tag.
if ( closingTag )
{
int c = in->get();
assert( c == '>' );
*tag += c;
// We are done, once we've found our closing tag.
return;
}
else
{
// If not a closing tag, id it, and stream.
const char* tagloc = tag->c_str() + tagIndex;
TiXmlNode* node = Identify( tagloc );
if ( !node )
return;
node->StreamIn( in, tag );
delete node;
node = 0;
// No return: go around from the beginning: text, closing tag, or node.
}
}
}
}
#endif
const char* TiXmlElement::Parse( const char* p, TiXmlParsingData* data )
{
p = SkipWhiteSpace( p );
TiXmlDocument* document = GetDocument();
if ( !p || !*p )
{
if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, 0, 0 );
return 0;
}
// TiXmlParsingData data( p, prevData );
if ( data )
{
data->Stamp( p );
location = data->Cursor();
}
if ( *p != '<' )
{
if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, p, data );
return 0;
}
p = SkipWhiteSpace( p+1 );
// Read the name.
const char* pErr = p;
p = ReadName( p, &value );
if ( !p || !*p )
{
if ( document ) document->SetError( TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, pErr, data );
return 0;
}
TIXML_STRING endTag ("</");
endTag += value;
endTag += ">";
// Check for and read attributes. Also look for an empty
// tag or an end tag.
while ( p && *p )
{
pErr = p;
p = SkipWhiteSpace( p );
if ( !p || !*p )
{
if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data );
return 0;
}
if ( *p == '/' )
{
++p;
// Empty tag.
if ( *p != '>' )
{
if ( document ) document->SetError( TIXML_ERROR_PARSING_EMPTY, p, data );
return 0;
}
return (p+1);
}
else if ( *p == '>' )
{
// Done with attributes (if there were any.)
// Read the value -- which can include other
// elements -- read the end tag, and return.
++p;
p = ReadValue( p, data ); // Note this is an Element method, and will set the error if one happens.
if ( !p || !*p )
return 0;
// We should find the end tag now
if ( StringEqual( p, endTag.c_str(), false ) )
{
p += endTag.length();
return p;
}
else
{
if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data );
return 0;
}
}
else
{
// Try to read an attribute:
TiXmlAttribute* attrib = new TiXmlAttribute();
if ( !attrib )
{
if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, pErr, data );
return 0;
}
attrib->SetDocument( document );
const char* pErr = p;
p = attrib->Parse( p, data );
if ( !p || !*p )
{
if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data );
delete attrib;
return 0;
}
// Handle the strange case of double attributes:
TiXmlAttribute* node = attributeSet.Find( attrib->Name() );
if ( node )
{
node->SetValue( attrib->Value() );
delete attrib;
return 0;
}
attributeSet.Add( attrib );
}
}
return p;
}
const char* TiXmlElement::ReadValue( const char* p, TiXmlParsingData* data )
{
TiXmlDocument* document = GetDocument();
// Read in text and elements in any order.
p = SkipWhiteSpace( p );
while ( p && *p )
{
if ( *p != '<' )
{
// Take what we have, make a text element.
TiXmlText* textNode = new TiXmlText( "" );
if ( !textNode )
{
if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0 );
return 0;
}
p = textNode->Parse( p, data );
if ( !textNode->Blank() )
LinkEndChild( textNode );
else
delete textNode;
}
else
{
// We hit a '<'
// Have we hit a new element or an end tag?
if ( StringEqual( p, "</", false ) )
{
return p;
}
else
{
TiXmlNode* node = Identify( p );
if ( node )
{
p = node->Parse( p, data );
LinkEndChild( node );
}
else
{
return 0;
}
}
}
p = SkipWhiteSpace( p );
}
if ( !p )
{
if ( document ) document->SetError( TIXML_ERROR_READING_ELEMENT_VALUE, 0, 0 );
}
return p;
}
#ifdef TIXML_USE_STL
void TiXmlUnknown::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
{
while ( in->good() )
{
int c = in->get();
(*tag) += c;
if ( c == '>' )
{
// All is well.
return;
}
}
}
#endif
const char* TiXmlUnknown::Parse( const char* p, TiXmlParsingData* data )
{
TiXmlDocument* document = GetDocument();
p = SkipWhiteSpace( p );
// TiXmlParsingData data( p, prevData );
if ( data )
{
data->Stamp( p );
location = data->Cursor();
}
if ( !p || !*p || *p != '<' )
{
if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, p, data );
return 0;
}
++p;
value = "";
while ( p && *p && *p != '>' )
{
value += *p;
++p;
}
if ( !p )
{
if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, 0, 0 );
}
if ( *p == '>' )
return p+1;
return p;
}
#ifdef TIXML_USE_STL
void TiXmlComment::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
{
while ( in->good() )
{
int c = in->get();
(*tag) += c;
if ( c == '>'
&& tag->at( tag->length() - 2 ) == '-'
&& tag->at( tag->length() - 3 ) == '-' )
{
// All is well.
return;
}
}
}
#endif
const char* TiXmlComment::Parse( const char* p, TiXmlParsingData* data )
{
TiXmlDocument* document = GetDocument();
value = "";
p = SkipWhiteSpace( p );
// TiXmlParsingData data( p, prevData );
if ( data )
{
data->Stamp( p );
location = data->Cursor();
}
const char* startTag = "<!--";
const char* endTag = "-->";
if ( !StringEqual( p, startTag, false ) )
{
document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data );
return 0;
}
p += strlen( startTag );
p = ReadText( p, &value, false, endTag, false );
return p;
}
const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data )
{
p = SkipWhiteSpace( p );
if ( !p || !*p ) return 0;
int tabsize = 4;
if ( document )
tabsize = document->TabSize();
// TiXmlParsingData data( p, prevData );
if ( data )
{
data->Stamp( p );
location = data->Cursor();
}
// Read the name, the '=' and the value.
const char* pErr = p;
p = ReadName( p, &name );
if ( !p || !*p )
{
if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data );
return 0;
}
p = SkipWhiteSpace( p );
if ( !p || !*p || *p != '=' )
{
if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data );
return 0;
}
++p; // skip '='
p = SkipWhiteSpace( p );
if ( !p || !*p )
{
if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data );
return 0;
}
const char* end;
if ( *p == '\'' )
{
++p;
end = "\'";
p = ReadText( p, &value, false, end, false );
}
else if ( *p == '"' )
{
++p;
end = "\"";
p = ReadText( p, &value, false, end, false );
}
else
{
// All attribute values should be in single or double quotes.
// But this is such a common error that the parser will try
// its best, even without them.
value = "";
while ( p && *p // existence
&& !isspace( *p ) && *p != '\n' && *p != '\r' // whitespace
&& *p != '/' && *p != '>' ) // tag end
{
value += *p;
++p;
}
}
return p;
}
#ifdef TIXML_USE_STL
void TiXmlText::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
{
while ( in->good() )
{
int c = in->peek();
if ( c == '<' )
return;
(*tag) += c;
in->get();
}
}
#endif
const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data )
{
value = "";
// TiXmlParsingData data( p, prevData );
if ( data )
{
data->Stamp( p );
location = data->Cursor();
}
bool ignoreWhite = true;
const char* end = "<";
p = ReadText( p, &value, ignoreWhite, end, false );
if ( p )
return p-1; // don't truncate the '<'
return 0;
}
#ifdef TIXML_USE_STL
void TiXmlDeclaration::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
{
while ( in->good() )
{
int c = in->get();
(*tag) += c;
if ( c == '>' )
{
// All is well.
return;
}
}
}
#endif
const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data )
{
p = SkipWhiteSpace( p );
// Find the beginning, find the end, and look for
// the stuff in-between.
TiXmlDocument* document = GetDocument();
if ( !p || !*p || !StringEqual( p, "<?xml", true ) )
{
if ( document ) document->SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0 );
return 0;
}
// TiXmlParsingData data( p, prevData );
if ( data )
{
data->Stamp( p );
location = data->Cursor();
}
p += 5;
version = "";
encoding = "";
standalone = "";
while ( p && *p )
{
if ( *p == '>' )
{
++p;
return p;
}
p = SkipWhiteSpace( p );
if ( StringEqual( p, "version", true ) )
{
TiXmlAttribute attrib;
p = attrib.Parse( p, data );
version = attrib.Value();
}
else if ( StringEqual( p, "encoding", true ) )
{
TiXmlAttribute attrib;
p = attrib.Parse( p, data );
encoding = attrib.Value();
}
else if ( StringEqual( p, "standalone", true ) )
{
TiXmlAttribute attrib;
p = attrib.Parse( p, data );
standalone = attrib.Value();
}
else
{
// Read over whatever it is.
while( p && *p && *p != '>' && !isspace( *p ) )
++p;
}
}
return 0;
}
bool TiXmlText::Blank() const
{
for ( unsigned i=0; i<value.length(); i++ )
if ( !isspace( value[i] ) )
return false;
return true;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -