Teuchos - Trilinos Tools Package Version of the Day
Teuchos_XMLParser.cpp
00001 // @HEADER
00002 // ***********************************************************************
00003 //
00004 //                    Teuchos: Common Tools Package
00005 //                 Copyright (2004) Sandia Corporation
00006 //
00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00008 // license for use of this work by or on behalf of the U.S. Government.
00009 //
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are
00012 // met:
00013 //
00014 // 1. Redistributions of source code must retain the above copyright
00015 // notice, this list of conditions and the following disclaimer.
00016 //
00017 // 2. Redistributions in binary form must reproduce the above copyright
00018 // notice, this list of conditions and the following disclaimer in the
00019 // documentation and/or other materials provided with the distribution.
00020 //
00021 // 3. Neither the name of the Corporation nor the names of the
00022 // contributors may be used to endorse or promote products derived from
00023 // this software without specific prior written permission.
00024 //
00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00036 //
00037 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
00038 //
00039 // ***********************************************************************
00040 // @HEADER
00041 
00042 // BUGS: There is a bug in Teuchos_XMLObjectImplem.cpp, line 82
00043 // when printing attribute values, one must check if the value contains quote
00044 // or apost; 
00045 // a quot'd attval cannot contain literal quot
00046 // a apos'd attval cannot contain literal apos
00047 // either they have to be matched appropriately or (easier) all quot and apos must
00048 // be replaced by " and '
00049 
00050 #include "Teuchos_XMLParser.hpp"
00051 #include "Teuchos_TreeBuildingXMLHandler.hpp"
00052 #include "Teuchos_Assert.hpp"
00053 #include <stack>
00054 
00055 using namespace Teuchos;
00056 
00057 // this parser currently does not support:
00058 // * processing instructions
00059 // * XML schemas
00060 // * CDATA sections...see http://www.w3.org/TR/2004/REC-xml-20040204/#dt-cdsection
00061 // * full Unicode support (we read unsigned bytes, so we get only 0x00 through 0xFF)
00062 // 
00063 // it tolerates (read: ignores) xml declarations, at any point in the file where a tag would be valid
00064 //
00065 // it currently does support:
00066 // * comments
00067 // * empty element tags, e.g.   <hello />
00068 // * entity references: &amp; &lt; &gt; &apos; &quot;
00069 // * numeric character references: &#32;
00070 // * std::exception/error handling on parse errors
00071 
00072 
00073 /* From the W3C XML 1.0 Third Edition
00074    http://www.w3.org/TR/2004/REC-xml-20040204/
00075   
00076    The following productions specify well-formed XML documents.
00077    These have been reduced to the support anticipated for support by this parser.
00078         
00079      element      ::=  EmptyElemTag
00080                        | STag content ETag 
00081      STag         ::=  '<' Name (S Attribute)* S? '>' 
00082      Attribute    ::=  Name Eq AttValue 
00083      ETag         ::=  '</' Name S? '>'
00084      content      ::=  CharData? ((element | Reference | CDSect | Comment) CharData?)*
00085      EmptyElemTag ::=  '<' Name (S Attribute)* S? '/>'
00086      
00087      AttValue     ::=  '"' ([^<&"] | Reference)* '"'
00088                        | "'" ([^<&'] | Reference)* "'"
00089      
00090      CharRef   ::= '&#' [0-9]+ ';'
00091      EntityRef ::= '&' Name ';'
00092      Reference ::= EntityRef | CharRef
00093      
00094      #x20 (space)
00095      #x9  (horizontal tab)
00096      #xD  (carriage return)
00097      #xA  (new line, new line line feed)
00098      
00099      S        ::=  (#x20 | #x9 | #xD | #xA)+
00100      Eq       ::=   S? '=' S?
00101      NameChar ::=  Letter | Digit | '.' | '-' | '_' | ':' | #x00B7
00102      Name     ::=  (Letter | '_' | ':') (NameChar)*
00103      
00104      Letter   ::= [#x0041-#x005A] | [#x0061-#x007A] 
00105                   | [#x00C0-#x00D6] | [#x00D8-#x00F6] 
00106                   | [#x00F8-#x00FF]
00107      Digit    ::= [#x0030-#x0039]
00108      
00109      Char      ::=  #x9 | #xA | #xD | [#x20-#xFF]   
00110      CharData  ::= [^<&]* - ([^<&]* ']]>' [^<&]*)
00111                    that is, some std::string of characters not containing '<' or '&' or ']]>'
00112      Comment   ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
00113                    that is, '<!--' txt '-->', where txt does not contain '--' 
00114      
00115      CDSect    ::= CDStart CData CDEnd
00116      CDStart   ::= '<![CDATA['
00117      CData     ::= (Char* - (Char* ']]>' Char*))
00118      CDEnd     ::= ']]>'
00119      
00120      document     ::=   prolog element Misc*
00121      prolog       ::=   XMLDecl? Misc*
00122      XMLDecl      ::=   '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
00123      Misc         ::=   Comment | S
00124 
00125      VersionInfo  ::=     S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"')
00126      Eq           ::=     S? '=' S?
00127      VersionNum   ::=    '1.' [0-9]+
00128      Misc         ::=     Comment | S
00129 
00130 
00131         
00132 */
00133 
00134 #define XMLPARSER_TFE( T , S ) \
00135   TEUCHOS_TEST_FOR_EXCEPTION( T, std::runtime_error, "XML parse error at line " << _lineNo << ": " << S )
00136 
00137 XMLObject XMLParser::parse() 
00138 {
00139   
00140   RCP<TreeBuildingXMLHandler> handler = rcp(new TreeBuildingXMLHandler());
00141   
00142   _entities.clear();
00143   _entities["apos"] = "'";
00144   _entities["quot"] = "\"";
00145   _entities["lt"]   = "<";
00146   _entities["gt"]   = ">";
00147   _entities["amp"]  = "&";
00148   
00149   bool done = false;
00150   int curopen = 0;  // number of currently open tags, or "do we process character data?"
00151   bool gotRoot = false;
00152   std::stack<long> tagLineStarts;
00153   std::stack<string> tags;
00154 
00155   while (!done) {
00156     
00157     std::string tag, cdata;
00158     unsigned char c1, c2;
00159     Teuchos::map<std::string,string> attrs;
00160     
00161     // Consume any whitespace
00162     if (curopen == 0) {
00163       // this will leave a lookahead in c1
00164       c1 = '\0';
00165       if ( getSpace(c1) ) {
00166         done = true;
00167         break;
00168       }
00169     }
00170     else {
00171       // need to manually lookahead
00172       if (_is->readBytes(&c1,1) < 1) {
00173         done = true;
00174         break;
00175       }
00176       if (c1 == '\n') ++_lineNo; // a newline while processing character data; not an error
00177     }
00178 
00179     if (c1 == '<') {
00180       // determine if it is a STag/EmptyElemTag or ETag or Comment
00181       // get lookahead
00182       XMLPARSER_TFE( _is->readBytes(&c2,1) < 1 , "stream ended in tag begin/end");
00183 
00184       if (c2 == '/') {
00185         // we have: </
00186         // try to get an ETag
00187         getETag(tag);
00188         // have to check whether we have an enclosing, otherwise tags and tagLineStarts have no top()
00189         XMLPARSER_TFE( curopen == 0,  "document not well-formed: encountered end element '" << tag << "' while not enclosed." );
00190         XMLPARSER_TFE( handler->endElement(tag)!=0, "document not well-formed: end element tag = '" << tag << "'"
00191                                                     << " did not match start element '" << tags.top() 
00192                                                     << "' from line " << tagLineStarts.top() );
00193         curopen--;
00194         tagLineStarts.pop();
00195         tags.pop();
00196       }
00197       else if (isLetter(c2) || c2==':' || c2=='_') {
00198         // it looks like a STag or an EmptyElemTag
00199         bool emptytag;
00200         tagLineStarts.push(_lineNo);
00201         getSTag(c2, tag, attrs, emptytag);
00202         tags.push(tag);
00203         handler->startElement(tag,attrs);
00204         if (curopen == 0) {
00205           XMLPARSER_TFE(gotRoot == true, "document not well-formed: more than one root element specified" );
00206           gotRoot = true;
00207         }
00208         curopen++;
00209         if (emptytag) {
00210           // we just open this tag, so we should have any trouble closing it
00211           XMLPARSER_TFE( handler->endElement(tag)!=0, "unknown failure from handler while processing tag '" << tag << "'" );
00212           curopen--;
00213           tagLineStarts.pop();
00214           tags.pop();
00215         }
00216       }
00217       else if (c2 == '?') {
00218         // it is starting to look like an xml declaration
00219         XMLPARSER_TFE( assertChar('x') != 0 , "was expecting an XML declaration; element not well-formed or exploits unsupported feature" );
00220         XMLPARSER_TFE( assertChar('m') != 0 , "was expecting an XML declaration; element not well-formed or exploits unsupported feature" );
00221         XMLPARSER_TFE( assertChar('l') != 0 , "was expecting an XML declaration; element not well-formed or exploits unsupported feature" );
00222         ignoreXMLDeclaration();
00223       }
00224       else if (c2 == '!') {
00225         // it is starting to look like a comment; we need '--'
00226         // if we don't get this, it means
00227         // * the document is not well-formed
00228         // * the document employs a feature not supported by this parser, 
00229         //   e.g. <!ELEMENT...  <!ATTLIST...  <!DOCTYPE...  <![CDATA[...
00230         XMLPARSER_TFE( assertChar('-') != 0 , "element not well-formed or exploits unsupported feature" );
00231         XMLPARSER_TFE( assertChar('-') != 0 , "element not well-formed or exploits unsupported feature" );
00232         getComment(_lineNo);
00233       }
00234       else {
00235         XMLPARSER_TFE(true,  "element not well-formed or exploits unsupported feature" );
00236       }
00237     }
00238     else if ( (curopen > 0) && (c1 == '&') ) {
00239       std::string chars = "";
00240       getReference(chars);
00241       handler->characters(chars);
00242     }
00243     else if ( (curopen > 0) ) {
00244       std::string chars = "";
00245       chars.push_back(c1);
00246       handler->characters(chars);
00247     }
00248     else {
00249       XMLPARSER_TFE(1 , "document not well-formed: character data outside of an enclosing tag");
00250     }
00251   }
00252 
00253   XMLPARSER_TFE( curopen != 0 ,  "file ended before closing element '" << tags.top() << "' from line " << tagLineStarts.top() );
00254 
00255   return handler->getObject();
00256 
00257 }
00258 
00259 
00260 void XMLParser::getETag(std::string &tag)
00261 {
00262   /* Recall from the specification:
00263         ETag  ::=  '</' Name S? '>'
00264         Name  ::=  (Letter | '_' | ':') (NameChar)*
00265     
00266      We have already consumed: </
00267   */
00268   
00269   bool tagover = false;
00270   unsigned char c;
00271   // clear tag
00272   tag = "";
00273   XMLPARSER_TFE( _is->readBytes(&c,1) < 1 ,  "EOF before end element was terminated");
00274   XMLPARSER_TFE( !isLetter(c) && c!='_' && c!=':' ,  "tag not well-formed");
00275   tag.push_back(c);
00276   while (1) {
00277     XMLPARSER_TFE( _is->readBytes(&c,1) < 1 ,  "EOF before end element was terminated");
00278     if ( isNameChar(c) ) {
00279       if (tagover) {
00280         XMLPARSER_TFE(1,  "end element not well-formed: expected '>'");
00281       }
00282       tag.push_back(c);
00283     }
00284     else if (isSpace(c)) {
00285       // mark the end of the tag and consume the whitespace
00286       // if it is ia newline, it isn't an error
00287       if (c == '\n') ++_lineNo;
00288       tagover = true;
00289     }
00290     else if (c == '>') {
00291       break; 
00292     }
00293     else {
00294       XMLPARSER_TFE(1,  "end element not well-formed");
00295     }
00296   }
00297 }
00298 
00299 
00300 void XMLParser::getSTag(unsigned char lookahead, std::string &tag, Teuchos::map<std::string,string> &attrs, bool &emptytag) 
00301 {
00302   
00303   /* Recall from the specification:
00304         
00305         STag         ::=  '<' Name (S Attribute)* S? '>' 
00306         EmptyElemTag ::=  '<' Name (S Attribute)* S? '/>'
00307         Name         ::=  (Letter | '_' | ':') (NameChar)*
00308         NameChar     ::=  Letter | Digit | '.' | '-' | '_' | ':' | #x00B7
00309         
00310         S            ::=  (#x20 | #x9 | #xD | #xA)+
00311         Attribute    ::=  Name Eq AttValue 
00312         Eq           ::=   S? '=' S?
00313         AttValue     ::=  '"' ([^<&"] | Reference)* '"'
00314                           | "'" ([^<&'] | Reference)* "'"
00315         Reference ::= EntityRef | CharRef
00316         CharRef   ::= '&#' [0-9]+ ';'
00317         EntityRef ::= '&' Name ';'
00318         
00319      We have already consumed: <lookahead
00320   */
00321   
00322   unsigned char c;
00323   attrs.clear();
00324   
00325   tag = lookahead;
00326   // get the rest of the tag: (NameChar)*
00327   while (1) {
00328     XMLPARSER_TFE( _is->readBytes(&c,1) < 1 ,  "EOF before start element was terminated");
00329     if (isNameChar(c)) {
00330       tag.push_back(c);
00331     }
00332     else {
00333       break; 
00334     }
00335   }
00336   
00337   // after the name: should be one of the following
00338   // (S Attribute) | S? '>' | S? '/>'
00339   do {
00340     
00341     bool hadspace = false;
00342     
00343     // if space, consume the whitespace
00344     if ( isSpace(c) ) {
00345       hadspace = true;
00346       XMLPARSER_TFE( getSpace(c)!=0, "EOF before start element was terminated");
00347     }
00348     
00349     // now, either Attribute | '>' | '/>'
00350     if ( (isLetter(c) || c=='_' || c==':') && hadspace ) {
00351       
00352       // Attribute
00353       // get attribute name, starting with contents of c
00354       std::string attname, attval;
00355       attname = c;
00356       do {
00357         XMLPARSER_TFE(_is->readBytes(&c,1) < 1,  "EOF before start element was terminated");
00358         if ( isNameChar(c) ) {
00359           attname.push_back(c);
00360         }
00361         else if ( isSpace(c) || c=='=' ) {
00362           break; 
00363         }
00364         else {
00365           XMLPARSER_TFE(1,  "attribute not well-formed: expected whitespace or '='");
00366         }
00367       } while (1);
00368       
00369       // if whitespace, consume it
00370       if (isSpace(c)) {
00371         getSpace(c);  
00372       }
00373       // should be on '='
00374       if (c != '=') {
00375         XMLPARSER_TFE(1,  "attribute not well-formed: expected '='");
00376       }
00377       
00378       // get any whitespace following the '='
00379       XMLPARSER_TFE(_is->readBytes(&c,1) < 1,  "EOF before start element was terminated");
00380       if (isSpace(c)) {
00381         getSpace(c);
00382       }
00383       
00384       // now get the quoted attribute value
00385       bool apost;
00386       attval = "";
00387       if (c == '\'') {
00388         apost = true;
00389       }
00390       else if (c == '\"') {
00391         apost = false;
00392       }
00393       else {
00394         XMLPARSER_TFE(1,  "attribute value must be quoted with either ''' or '\"'");
00395       }
00396       do {
00397         XMLPARSER_TFE(_is->readBytes(&c,1) < 1,  "EOF before start element was terminated");
00398         if (apost && c=='\'') {
00399           // end of attval
00400           break;
00401         }
00402         else if (!apost && c=='\"') {
00403           // end of attval
00404           break;
00405         }
00406         else if ( c == '&' ) {
00407           // finish: need to add support for Reference
00408           std::string refstr;
00409           getReference(refstr);
00410           attval += refstr;
00411         }
00412         else if ( c!='<' ) {
00413           // valid character for attval
00414           attval.push_back(c);
00415         }
00416         else {
00417           XMLPARSER_TFE(1,  "invalid character in attribute value");
00418         }
00419       } while(1);
00420       
00421       // add attribute to list
00422       XMLPARSER_TFE( attrs.find(attname) != attrs.end() ,  "cannot have two attributes with the same name");
00423       attrs[attname] = attval;
00424     }
00425     else if (c == '>') {
00426       emptytag = false;
00427       break;
00428     }
00429     else if (c == '/') {
00430       XMLPARSER_TFE(assertChar('>')!=0, "empty element tag not well-formed: expected '>'");
00431       emptytag = true;
00432       break;
00433     }
00434     else {
00435       XMLPARSER_TFE(1,  "start element not well-formed: invalid character");
00436     }
00437   
00438     // get next char
00439     XMLPARSER_TFE(_is->readBytes(&c,1) < 1,  "EOF before start element was terminated");
00440   
00441   } while(1);
00442 }
00443 
00444 
00445 void XMLParser::getComment(long startLine) 
00446 {
00447   /* Recall from the specification:
00448         Comment   ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
00449                       that is, '<!--' txt '-->', where txt does not contain '--' 
00450      We have already consumed: <!--
00451      
00452      Be wary here of the fact that c=='-' implies isChar(c)
00453   */
00454   unsigned char c;
00455   while (1) {
00456     XMLPARSER_TFE(_is->readBytes(&c,1) < 1,  "EOF before terminating comment begun at line " << _lineNo );
00457     if (c == '\n') ++_lineNo;
00458     // if we have a -
00459     if (c=='-') {
00460       // then it must be the end of the comment or be a Char
00461       XMLPARSER_TFE(_is->readBytes(&c,1) < 1,  "EOF before terminating comment begun at line " << _lineNo );
00462       if (c == '\n') ++_lineNo;
00463       if (c=='-') {
00464         // this had better be leading to the end of the comment
00465         XMLPARSER_TFE( assertChar('>')!=0, "comment not well-formed: missing expected '>' at line " << _lineNo );
00466         break;
00467       }
00468       else if (!isChar(c)) {
00469         XMLPARSER_TFE(1,  "comment not well-formed: invalid character at line " << _lineNo );
00470       }
00471     }
00472     else if (!isChar(c)) {
00473       XMLPARSER_TFE(1,  "comment not well-formed: invalid character at line " << _lineNo );
00474     }
00475   } 
00476 }
00477 
00478 
00479 void XMLParser::getReference(std::string &refstr) {
00480   // finish: does CharRef support only dec, or hex as well?
00481   unsigned char c;
00482   unsigned int num, base;
00483   refstr = "";
00484   // none of these bytes read are allowed to be a newline, so don't do any incrementing of _lineNo
00485   XMLPARSER_TFE(_is->readBytes(&c,1) < 1,  "EOF before reference was terminated");
00486   if (c == '#') {
00487     // get a CharRef
00488     // CharRef   ::= '&#' [0-9]+ ';'
00489     //               | '&#x' [0-9]+ ';'
00490     // get first number
00491     XMLPARSER_TFE(_is->readBytes(&c,1) < 1,  "EOF before reference was terminated");
00492     if (c == 'x') {
00493       base = 16;
00494       num = 0;
00495     }
00496     else if ('0' <= c && c <= '9') {
00497       base = 10;
00498       num = c - '0';
00499     }
00500     else {
00501       XMLPARSER_TFE(1,  "invalid character in character reference: expected 'x' or [0-9]");
00502     }
00503 
00504     do {
00505       XMLPARSER_TFE(_is->readBytes(&c,1) < 1,  "EOF before reference was terminated");
00506       XMLPARSER_TFE( c != ';' && !('0' <= c && c <= '9') ,  "invalid character in character reference: expected [0-9] or ';'");
00507       if (c == ';') {
00508         break;
00509       }
00510       num = num*base + (c-'0');
00511     } while (1);
00512     XMLPARSER_TFE(num > 0xFF,  "character reference value out of range");
00513     refstr.push_back( (unsigned char)num );
00514   }
00515   else if (isLetter(c) || c=='_' || c==':') {
00516     // get an EntityRef
00517     // EntityRef ::= '&' Name ';'
00518     std::string entname = "";
00519     entname.push_back(c);
00520     do {
00521       XMLPARSER_TFE(_is->readBytes(&c,1) < 1,  "EOF before reference was terminated");
00522       if (c==';') {
00523         break;
00524       }
00525       else if ( isLetter(c) || ('0' <= c && c <= '9')
00526                 || c=='.' || c=='-' || c=='_' || c==':' 
00527                 || c==0xB7 ) {
00528         entname.push_back(c);
00529       }
00530       else {
00531         XMLPARSER_TFE(1,  "entity reference not well-formed: invalid character");
00532       }
00533     } while (1);
00534     XMLPARSER_TFE( _entities.find(entname) == _entities.end(),  "entity reference not well-formed: undefined entity");
00535     refstr = _entities[entname];  
00536   }
00537   else {
00538     XMLPARSER_TFE(1,  "reference not well-formed: expected name or '#'");
00539   }
00540 }
00541 
00542 
00543 int XMLParser::getSpace(unsigned char &lookahead) {
00544   // if space, consume the whitespace
00545   do {
00546     if (lookahead == '\n') ++_lineNo;
00547     if (_is->readBytes(&lookahead,1) < 1) {
00548       return 1; // inform caller that we reached the end
00549     }
00550   }
00551   while (isSpace(lookahead));
00552   return 0;
00553 }
00554 
00555 
00556 bool XMLParser::isLetter(unsigned char c) {
00557   if ( (0x41 <= c && c <= 0x5A) || (0x61 <= c && c <= 0x7A) ||
00558        (0xC0 <= c && c <= 0xD6) || (0xD8 <= c && c <= 0xF6) ||
00559        (0xF8 <= c) /* unsigned char must be <= 0xFF */         )
00560   {
00561     return true;
00562   }
00563   return false;
00564 }
00565 
00566 
00567 bool XMLParser::isNameChar(unsigned char c) {
00568   if ( isLetter(c) || ('0' <= c && c <= '9') ||
00569        c=='.' || c=='-' || c=='_' || c==':' || c==0xB7 ) 
00570   {
00571     return true;
00572   }
00573   return false;
00574 }
00575 
00576 
00577 bool XMLParser::isSpace(unsigned char c) {
00578   if ( c==0x20 || c==0x9 || c==0xD || c==0xA )
00579   {
00580     return true;
00581   }
00582   return false;
00583 }
00584 
00585 
00586 bool XMLParser::isChar(unsigned char c) {
00587   if ( c==0x9 || c==0xA || c==0xD || 0x20 <= c) {  // unsigned char must be <= 0xFF
00588     return true;
00589   }
00590   return false;
00591 }
00592 
00593 
00594 int XMLParser::assertChar(unsigned char cexp) 
00595 {
00596   // pull the next character off the stream and verify that it is what is expected
00597   // if not, return an error to the caller
00598   unsigned char c;
00599   // don't worry about newlines; assertChar is always wrapped in TEST_FOR_EXCEPTION, so we don't want to advance the line counter
00600   if (_is->readBytes(&c,1) < 1) {
00601     return 1;
00602   }
00603   if (c != cexp) {
00604     return 2;
00605   }
00606   return 0; 
00607 }
00608 
00609 void XMLParser::ignoreXMLDeclaration() 
00610 {
00611   /* Be a little lax on the spec here; read until we get to '?', then assert '>'
00612      We have already consumed: <xml
00613   */
00614   unsigned char c;
00615   while (1) {
00616     XMLPARSER_TFE(_is->readBytes(&c,1) < 1,  "EOF before terminating XML declaration begun at line " << _lineNo );
00617     if (c == '\n') ++_lineNo;
00618     // if we have a -
00619     if (c=='?') {
00620       // this had better be leading to the end of the declaration
00621       XMLPARSER_TFE( assertChar('>')!=0, "XML declaration not well-formed: missing expected '>' at line " << _lineNo );
00622       break;
00623     }
00624   } 
00625 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines