📄 xmlparser.cpp
字号:
// Either a "<...>" or content begins next: if (*_current == '<') { _current++; _getElement(_current, entry); if (nullTerminator) *nullTerminator = '\0'; if (entry.type == XmlEntry::START_TAG) { if (_stack.isEmpty() && _foundRoot) throw XmlException(XmlException::MULTIPLE_ROOTS, _line); _foundRoot = true; _stack.push((char*)entry.text); } else if (entry.type == XmlEntry::END_TAG) { if (_stack.isEmpty()) throw XmlException(XmlException::START_END_MISMATCH, _line); if (strcmp(_stack.top(), entry.text) != 0) throw XmlException(XmlException::START_END_MISMATCH, _line); _stack.pop(); } return true; } else { // Normalize the content: char* start; _normalize(_line, _current, '<', start); // Get the content: entry.type = XmlEntry::CONTENT; entry.text = start; // Overwrite '<' with a null character (temporarily). _restoreChar = *_current; *_current = '\0'; if (nullTerminator) *nullTerminator = '\0'; return true; }}void XmlParser::putBack(XmlEntry& entry){ _putBackStack.push(entry);}XmlParser::~XmlParser(){ // Nothing to do!}// A-Za-z0-9_-:.static unsigned char _isInnerElementChar[] ={ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};Boolean XmlParser::_getElementName(char*& p){ if (!CharSet::isAlNumUnder(Uint8(*p))) throw XmlException(XmlException::BAD_START_TAG, _line); p++; while (*p && _isInnerElementChar[Uint8(*p)]) p++; // The next character must be a space: if (_isspace(*p)) { *p++ = '\0'; _skipWhitespace(_line, p); } if (*p == '>') { *p++ = '\0'; return true; } return false;}Boolean XmlParser::_getOpenElementName(char*& p, Boolean& openCloseElement){ openCloseElement = false; if (!CharSet::isAlNumUnder(Uint8(*p))) throw XmlException(XmlException::BAD_START_TAG, _line); p++; while (*p && _isInnerElementChar[Uint8(*p)]) p++; // The next character must be a space: if (_isspace(*p)) { *p++ = '\0'; _skipWhitespace(_line, p); } if (*p == '>') { *p++ = '\0'; return true; } if (p[0] == '/' && p[1] == '>') { openCloseElement = true; *p = '\0'; p += 2; return true; } return false;}void XmlParser::_getAttributeNameAndEqual(char*& p){ if (!CharSet::isAlNumUnder((Uint8)*p)) throw XmlException(XmlException::BAD_ATTRIBUTE_NAME, _line); p++; while (*p && _isInnerElementChar[Uint8(*p)]) p++; char* term = p; _skipWhitespace(_line, p); if (*p != '=') throw XmlException(XmlException::BAD_ATTRIBUTE_NAME, _line); p++; _skipWhitespace(_line, p); *term = '\0';}void XmlParser::_getComment(char*& p){ // Now p points to first non-whitespace character beyond "<--" sequence: for (; *p; p++) { if (p[0] == '-' && p[1] == '-') { if (p[2] != '>') { throw XmlException( XmlException::MINUS_MINUS_IN_COMMENT, _line); } // Find end of comment (excluding whitespace): *p = '\0'; p += 3; return; } } // If it got this far, then the comment is unterminated: throw XmlException(XmlException::UNTERMINATED_COMMENT, _line);}void XmlParser::_getCData(char*& p){ // At this point p points one past "<![CDATA[" sequence: for (; *p; p++) { if (p[0] == ']' && p[1] == ']' && p[2] == '>') { *p = '\0'; p += 3; return; } else if (*p == '\n') _line++; } // If it got this far, then the comment is unterminated: throw XmlException(XmlException::UNTERMINATED_CDATA, _line);}void XmlParser::_getDocType(char*& p){ // Just ignore the DOCTYPE command for now: for (; *p && *p != '>'; p++) { if (*p == '\n') _line++; } if (*p != '>') throw XmlException(XmlException::UNTERMINATED_DOCTYPE, _line); p++;}void XmlParser::_getElement(char*& p, XmlEntry& entry){ entry.attributeCount = 0; //-------------------------------------------------------------------------- // Get the element name (expect one of these: '?', '!', [A-Za-z_]) //-------------------------------------------------------------------------- if (*p == '?') { entry.type = XmlEntry::XML_DECLARATION; entry.text = ++p; Boolean openCloseElement = false; if (_getElementName(p)) return; } else if (*p == '!') { p++; // Expect a comment or CDATA: if (p[0] == '-' && p[1] == '-') { p += 2; entry.type = XmlEntry::COMMENT; entry.text = p; _getComment(p); return; } else if (memcmp(p, "[CDATA[", 7) == 0) { p += 7; entry.type = XmlEntry::CDATA; entry.text = p; _getCData(p); return; } else if (memcmp(p, "DOCTYPE", 7) == 0) { entry.type = XmlEntry::DOCTYPE; entry.text = ""; _getDocType(p); return; } throw(XmlException(XmlException::EXPECTED_COMMENT_OR_CDATA, _line)); } else if (*p == '/') { entry.type = XmlEntry::END_TAG; entry.text = ++p; if (!_getElementName(p)) throw(XmlException(XmlException::BAD_END_TAG, _line)); return; } else if ((((*p >= 'A') && (*p <= 'Z')) || ((*p >= 'a') && (*p <= 'z')) || (*p == '_'))) { entry.type = XmlEntry::START_TAG; entry.text = p; Boolean openCloseElement = false; if (_getOpenElementName(p, openCloseElement)) { if (openCloseElement) entry.type = XmlEntry::EMPTY_TAG; return; } } else throw XmlException(XmlException::BAD_START_TAG, _line); //-------------------------------------------------------------------------- // Grab all the attributes: //-------------------------------------------------------------------------- for (;;) { if (entry.type == XmlEntry::XML_DECLARATION) { if (p[0] == '?' && p[1] == '>') { p += 2; return; } } else if (entry.type == XmlEntry::START_TAG && p[0] == '/' && p[1] =='>') { entry.type = XmlEntry::EMPTY_TAG; p += 2; return; } else if (*p == '>') { p++; return; } XmlAttribute attr; attr.name = p; _getAttributeNameAndEqual(p); // Get the attribute value (e.g., "some value") { if ((*p != '"') && (*p != '\'')) { throw XmlException(XmlException::BAD_ATTRIBUTE_VALUE, _line); } char quote = *p++; char* start; _normalize(_line, p, quote, start); attr.value = start; if (*p != quote) { throw XmlException(XmlException::BAD_ATTRIBUTE_VALUE, _line); } // Overwrite the closing quote with a null-terminator: *p++ = '\0'; } if (entry.type == XmlEntry::XML_DECLARATION) { // The next thing must a space or a "?>": if (!(p[0] == '?' && p[1] == '>') && !_isspace(*p)) { throw XmlException( XmlException::BAD_ATTRIBUTE_VALUE, _line); } } else if (!(*p == '>' || (p[0] == '/' && p[1] == '>') || _isspace(*p))) { // The next thing must be a space or a '>': throw XmlException(XmlException::BAD_ATTRIBUTE_VALUE, _line); } _skipWhitespace(_line, p); if (entry.attributeCount == XmlEntry::MAX_ATTRIBUTES) throw XmlException(XmlException::TOO_MANY_ATTRIBUTES, _line); entry.attributes[entry.attributeCount++] = attr; }}static const char* _typeStrings[] ={ "XML_DECLARATION", "START_TAG", "EMPTY_TAG", "END_TAG", "COMMENT", "CDATA", "DOCTYPE", "CONTENT"};void XmlEntry::print() const{ PEGASUS_STD(cout) << "=== " << _typeStrings[type] << " "; Boolean needQuotes = type == XmlEntry::CDATA || type == XmlEntry::CONTENT; if (needQuotes) PEGASUS_STD(cout) << "\""; _printValue(text); if (needQuotes) PEGASUS_STD(cout) << "\""; PEGASUS_STD(cout) << '\n'; for (Uint32 i = 0; i < attributeCount; i++) { PEGASUS_STD(cout) << " " << attributes[i].name << "=\""; _printValue(attributes[i].value); PEGASUS_STD(cout) << "\"" << PEGASUS_STD(endl); }}const XmlAttribute* XmlEntry::findAttribute( const char* name) const{ for (Uint32 i = 0; i < attributeCount; i++) { if (strcmp(attributes[i].name, name) == 0) return &attributes[i]; } return 0;}// Find first non-whitespace character (set first) and last non-whitespace// character (set last one past this). For example, consider this string://// " 87 "//// The first pointer would point to '8' and the last pointer woudl point one// beyond '7'.static void _findEnds( const char* str, const char*& first, const char*& last){ first = str; while (_isspace(*first)) first++; if (!*first) { last = first; return; } last = first + strlen(first); while (last != first && _isspace(last[-1])) last--;}Boolean XmlEntry::getAttributeValue( const char* name, Uint32& value) const{ const XmlAttribute* attr = findAttribute(name); if (!attr) return false; const char* first; const char* last; _findEnds(attr->value, first, last); char* end = 0; long tmp = strtol(first, &end, 10); if (!end || end != last) return false; value = Uint32(tmp); return true;}Boolean XmlEntry::getAttributeValue( const char* name, Real32& value) const{ const XmlAttribute* attr = findAttribute(name); if (!attr) return false; const char* first; const char* last; _findEnds(attr->value, first, last); char* end = 0; double tmp = strtod(first, &end); if (!end || end != last) return false; value = static_cast<Real32>(tmp); return true;}Boolean XmlEntry::getAttributeValue( const char* name, const char*& value) const{ const XmlAttribute* attr = findAttribute(name); if (!attr) return false; value = attr->value; return true;}Boolean XmlEntry::getAttributeValue(const char* name, String& value) const{ const char* tmp; if (!getAttributeValue(name, tmp)) return false; value = String(tmp); return true;}void XmlAppendCString(Buffer& out, const char* str){ out.append(str, static_cast<Uint32>(strlen(str)));}PEGASUS_NAMESPACE_END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -