XmlNode* XmlNode::ReplaceChild( XmlNode* replaceThis, const XmlNode& withThis ) { if ( !replaceThis ) return 0; if ( replaceThis->parent != this ) return 0; if ( withThis.ToDocument() ) { // A document can never be a child. Thanks to Noam. XmlDocument* document = GetDocument(); if ( document ) document->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); return 0; } XmlNode* node = withThis.Clone(); if ( !node ) return 0; node->next = replaceThis->next; node->prev = replaceThis->prev; if ( replaceThis->next ) replaceThis->next->prev = node; else lastChild = node; if ( replaceThis->prev ) replaceThis->prev->next = node; else firstChild = node; delete replaceThis; node->parent = this; return node; }
/** * @brief * Reads the "value" of the element -- another element, or text */ const char *XmlElement::ReadValue(const char *pszData, XmlParsingData *pData, EEncoding nEncoding) { // Read in text and elements in any order const char *pWithWhiteSpace = pszData; pszData = SkipWhiteSpace(pszData, nEncoding); while (pszData && *pszData) { if (*pszData != '<') { // Take what we have, make a text element XmlText *pTextNode = new XmlText(""); if (IsWhiteSpaceCondensed()) pszData = pTextNode->Parse(pszData, pData, nEncoding); else { // Special case: we want to keep the white space so that leading spaces aren't removed pszData = pTextNode->Parse(pWithWhiteSpace, pData, nEncoding); } // Does the text value only contain white spaces? bool bIsBlank = true; { const String sValue = pTextNode->GetValue(); for (uint32 i=0; i<sValue.GetLength(); i++) { if (!IsWhiteSpace(sValue[i])) { bIsBlank = false; break; } } } if (bIsBlank) delete pTextNode; else LinkEndChild(*pTextNode); } else { // We hit a '<' // Have we hit a new element or an end tag? This could also be a XmlText in the "CDATA" style if (StringEqual(pszData, "</", false, nEncoding)) return pszData; else { XmlNode *pNode = Identify(pszData, nEncoding); if (pNode) { pszData = pNode->Parse(pszData, pData, nEncoding); LinkEndChild(*pNode); } else { return nullptr; } } } pWithWhiteSpace = pszData; pszData = SkipWhiteSpace(pszData, nEncoding); } if (!pszData) { // Set error code XmlDocument *pDocument = GetDocument(); if (pDocument) pDocument->SetError(ErrorReadingElementValue, 0, 0, nEncoding); } // Done return pszData; }
const char *XmlElement::Parse(const char *pszData, XmlParsingData *pData, EEncoding nEncoding) { pszData = SkipWhiteSpace(pszData, nEncoding); if (!pszData || !*pszData) { // Set error code XmlDocument *pDocument = GetDocument(); if (pDocument) pDocument->SetError(ErrorParsingElement, 0, 0, nEncoding); // Error! return nullptr; } if (pData) { pData->Stamp(pszData, nEncoding); m_cCursor = pData->Cursor(); } if (*pszData != '<') { // Set error code XmlDocument *pDocument = GetDocument(); if (pDocument) pDocument->SetError(ErrorParsingElement, pszData, pData, nEncoding); // Error! return nullptr; } pszData = SkipWhiteSpace(pszData + 1, nEncoding); // Read the name const char *pszError = pszData; pszData = ReadName(pszData, m_sValue, nEncoding); if (!pszData || !*pszData) { // Set error code XmlDocument *pDocument = GetDocument(); if (pDocument) pDocument->SetError(ErrorFailedToReadElementName, pszError, pData, nEncoding); // Error! return nullptr; } String sEndTag = "</"; sEndTag += m_sValue; // Check for and read attributes. Also look for an empty tag or an end tag while (pszData && *pszData) { pszError = pszData; pszData = SkipWhiteSpace(pszData, nEncoding); if (!pszData || !*pszData) { // Set error code XmlDocument *pDocument = GetDocument(); if (pDocument) pDocument->SetError(ErrorReadingAttributes, pszError, pData, nEncoding); // Error! return nullptr; } if (*pszData == '/') { ++pszData; // Empty tag if (*pszData != '>') { // Set error code XmlDocument *pDocument = GetDocument(); if (pDocument) pDocument->SetError(ErrorParsingEmpty, pszData, pData, nEncoding); // Error! return nullptr; } return (pszData + 1); } else if (*pszData == '>') { // Done with attributes (if there were any) // Read the value -- which can include other elements -- read the end tag, and return ++pszData; pszData = ReadValue(pszData, pData, nEncoding); // Note this is an Element method, and will set the error if one happens if (!pszData || !*pszData) { // We were looking for the end tag, but found nothing XmlDocument *pDocument = GetDocument(); if (pDocument) pDocument->SetError(ErrorReadingEndTag, pszData, pData, nEncoding); // Error! return nullptr; } // We should find the end tag now // Note that: // </foo > and // </foo> // are both valid end tags if (StringEqual(pszData, sEndTag, false, nEncoding)) { pszData += sEndTag.GetLength(); pszData = SkipWhiteSpace(pszData, nEncoding); if (pszData && *pszData && *pszData == '>') { ++pszData; return pszData; } // Set error code XmlDocument *pDocument = GetDocument(); if (pDocument) pDocument->SetError(ErrorReadingEndTag, pszData, pData, nEncoding); // Error! return nullptr; } else { // Set error code XmlDocument *pDocument = GetDocument(); if (pDocument) pDocument->SetError(ErrorReadingEndTag, pszData, pData, nEncoding); // Error! return nullptr; } } else { // Try to read an attribute XmlAttribute *pAttribute = new XmlAttribute(); pAttribute->m_pDocument = GetDocument(); pszError = pszData; pszData = pAttribute->Parse(pszData, pData, nEncoding); if (!pszData || !*pszData) { // Set error code XmlDocument *pDocument = GetDocument(); if (pDocument) pDocument->SetError(ErrorParsingElement, pszError, pData, nEncoding); // Destroy the created attribute delete pAttribute; // Error! return nullptr; } // Handle the strange case of double attributes XmlAttribute *pNode = m_cAttributeSet.Find(pAttribute->GetName()); if (pNode) { // Set error code XmlDocument *pDocument = GetDocument(); if (pDocument) pDocument->SetError(ErrorParsingElement, pszError, pData, nEncoding); // Destroy the created attribute delete pAttribute; // Error! return nullptr; } // Register the created attribute m_cAttributeSet.Add(*pAttribute); } } // Done return pszData; }