void XmlDocument::readChildElements (XmlElement& parent) { LinkedListPointer<XmlElement>::Appender childAppender (parent.firstChildElement); for (;;) { const String::CharPointerType preWhitespaceInput (input); skipNextWhiteSpace(); if (outOfData) { setLastError ("unmatched tags", false); break; } if (*input == '<') { const juce_wchar c1 = input[1]; if (c1 == '/') { // our close tag.. const int closeTag = input.indexOf ((juce_wchar) '>'); if (closeTag >= 0) input += closeTag + 1; break; } if (c1 == '!' && CharacterFunctions::compareUpTo (input + 2, CharPointer_ASCII ("[CDATA["), 7) == 0) { input += 9; const String::CharPointerType inputStart (input); for (;;) { const juce_wchar c0 = *input; if (c0 == 0) { setLastError ("unterminated CDATA section", false); outOfData = true; break; } else if (c0 == ']' && input[1] == ']' && input[2] == '>') { childAppender.append (XmlElement::createTextElement (String (inputStart, input))); input += 3; break; } ++input; } } else { // this is some other element, so parse and add it.. if (XmlElement* const n = readNextElement (true)) childAppender.append (n); else break; } } else // must be a character block { input = preWhitespaceInput; // roll back to include the leading whitespace MemoryOutputStream textElementContent; bool contentShouldBeUsed = ! ignoreEmptyTextElements; for (;;) { const juce_wchar c = *input; if (c == '<') { if (input[1] == '!' && input[2] == '-' && input[3] == '-') { input += 4; const int closeComment = input.indexOf (CharPointer_ASCII ("-->")); if (closeComment < 0) { setLastError ("unterminated comment", false); outOfData = true; return; } input += closeComment + 3; continue; } break; } if (c == 0) { setLastError ("unmatched tags", false); outOfData = true; return; } if (c == '&') { String entity; readEntity (entity); if (entity.startsWithChar ('<') && entity [1] != 0) { const String::CharPointerType oldInput (input); const bool oldOutOfData = outOfData; input = entity.getCharPointer(); outOfData = false; while (XmlElement* n = readNextElement (true)) childAppender.append (n); input = oldInput; outOfData = oldOutOfData; } else { textElementContent << entity; contentShouldBeUsed = contentShouldBeUsed || entity.containsNonWhitespaceChars(); } } else { for (;; ++input) { juce_wchar nextChar = *input; if (nextChar == '\r') { nextChar = '\n'; if (input[1] == '\n') continue; } if (nextChar == '<' || nextChar == '&') break; if (nextChar == 0) { setLastError ("unmatched tags", false); outOfData = true; return; } textElementContent.appendUTF8Char (nextChar); contentShouldBeUsed = contentShouldBeUsed || ! CharacterFunctions::isWhitespace (nextChar); } } } if (contentShouldBeUsed) childAppender.append (XmlElement::createTextElement (textElementContent.toUTF8())); } } }
void XmlDocument::readChildElements (XmlElement* parent) { LinkedListPointer<XmlElement>::Appender childAppender (parent->firstChildElement); for (;;) { const String::CharPointerType preWhitespaceInput (input); skipNextWhiteSpace(); if (outOfData) { setLastError ("unmatched tags", false); break; } if (*input == '<') { if (input[1] == '/') { // our close tag.. const int closeTag = input.indexOf ((juce_wchar) '>'); if (closeTag >= 0) input += closeTag + 1; break; } else if (input[1] == '!' && input[2] == '[' && input[3] == 'C' && input[4] == 'D' && input[5] == 'A' && input[6] == 'T' && input[7] == 'A' && input[8] == '[') { input += 9; const String::CharPointerType inputStart (input); size_t len = 0; for (;;) { if (*input == 0) { setLastError ("unterminated CDATA section", false); outOfData = true; break; } else if (input[0] == ']' && input[1] == ']' && input[2] == '>') { input += 3; break; } ++input; ++len; } childAppender.append (XmlElement::createTextElement (String (inputStart, len))); } else { // this is some other element, so parse and add it.. if (XmlElement* const n = readNextElement (true)) childAppender.append (n); else break; } } else // must be a character block { input = preWhitespaceInput; // roll back to include the leading whitespace String textElementContent; for (;;) { const juce_wchar c = *input; if (c == '<') break; if (c == 0) { setLastError ("unmatched tags", false); outOfData = true; return; } if (c == '&') { String entity; readEntity (entity); if (entity.startsWithChar ('<') && entity [1] != 0) { const String::CharPointerType oldInput (input); const bool oldOutOfData = outOfData; input = entity.getCharPointer(); outOfData = false; for (;;) { XmlElement* const n = readNextElement (true); if (n == nullptr) break; childAppender.append (n); } input = oldInput; outOfData = oldOutOfData; } else { textElementContent += entity; } } else { const String::CharPointerType start (input); size_t len = 0; for (;;) { const juce_wchar nextChar = *input; if (nextChar == '<' || nextChar == '&') { break; } else if (nextChar == 0) { setLastError ("unmatched tags", false); outOfData = true; return; } ++input; ++len; } textElementContent.appendCharPointer (start, len); } } if ((! ignoreEmptyTextElements) || textElementContent.containsNonWhitespaceChars()) { childAppender.append (XmlElement::createTextElement (textElementContent)); } } } }