| 1 | /* |
| 2 | * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"). |
| 5 | * You may not use this file except in compliance with the License. |
| 6 | * A copy of the License is located at |
| 7 | * |
| 8 | * http://aws.amazon.com/apache2.0 |
| 9 | * |
| 10 | * or in the "license" file accompanying this file. This file is distributed |
| 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either |
| 12 | * express or implied. See the License for the specific language governing |
| 13 | * permissions and limitations under the License. |
| 14 | */ |
| 15 | |
| 16 | #include <aws/core/utils/xml/XmlSerializer.h> |
| 17 | |
| 18 | #include <aws/core/utils/StringUtils.h> |
| 19 | #include <aws/core/external/tinyxml2/tinyxml2.h> |
| 20 | |
| 21 | #include <utility> |
| 22 | #include <algorithm> |
| 23 | #include <iostream> |
| 24 | |
| 25 | using namespace Aws::Utils::Xml; |
| 26 | using namespace Aws::Utils; |
| 27 | |
| 28 | Aws::String Aws::Utils::Xml::DecodeEscapedXmlText(const Aws::String& textToDecode) |
| 29 | { |
| 30 | Aws::String decodedString = textToDecode; |
| 31 | StringUtils::Replace(decodedString, """ , "\"" ); |
| 32 | StringUtils::Replace(decodedString, "'" , "'" ); |
| 33 | StringUtils::Replace(decodedString, "<" , "<" ); |
| 34 | StringUtils::Replace(decodedString, ">" , ">" ); |
| 35 | StringUtils::Replace(decodedString, "&" , "&" ); |
| 36 | |
| 37 | return decodedString; |
| 38 | } |
| 39 | |
| 40 | XmlNode::XmlNode(const XmlNode& other) : m_node(other.m_node), m_doc(other.m_doc) |
| 41 | { |
| 42 | } |
| 43 | |
| 44 | XmlNode& XmlNode::operator=(const XmlNode& other) |
| 45 | { |
| 46 | if(this == &other) |
| 47 | { |
| 48 | return *this; |
| 49 | } |
| 50 | |
| 51 | m_node = other.m_node; |
| 52 | m_doc = other.m_doc; |
| 53 | |
| 54 | return *this; |
| 55 | } |
| 56 | |
| 57 | const Aws::String XmlNode::GetName() const |
| 58 | { |
| 59 | return m_node->Value(); |
| 60 | } |
| 61 | |
| 62 | void XmlNode::SetName(const Aws::String& name) |
| 63 | { |
| 64 | m_node->SetValue(name.c_str(), false); |
| 65 | } |
| 66 | |
| 67 | const Aws::String XmlNode::GetAttributeValue(const Aws::String& name) const |
| 68 | { |
| 69 | auto pointer = m_node->ToElement()->Attribute(name.c_str(), nullptr); |
| 70 | return pointer ? pointer : "" ; |
| 71 | } |
| 72 | |
| 73 | void XmlNode::SetAttributeValue(const Aws::String& name, const Aws::String& value) |
| 74 | { |
| 75 | m_node->ToElement()->SetAttribute(name.c_str(), value.c_str()); |
| 76 | } |
| 77 | |
| 78 | bool XmlNode::HasNextNode() const |
| 79 | { |
| 80 | return m_node->NextSibling() != nullptr; |
| 81 | } |
| 82 | |
| 83 | XmlNode XmlNode::NextNode() const |
| 84 | { |
| 85 | return XmlNode(m_node->NextSiblingElement(), *m_doc); |
| 86 | } |
| 87 | |
| 88 | XmlNode XmlNode::NextNode(const char* name) const |
| 89 | { |
| 90 | return XmlNode(m_node->NextSiblingElement(name), *m_doc); |
| 91 | } |
| 92 | |
| 93 | XmlNode XmlNode::NextNode(const Aws::String& name) const |
| 94 | { |
| 95 | return NextNode(name.c_str()); |
| 96 | } |
| 97 | |
| 98 | XmlNode XmlNode::FirstChild() const |
| 99 | { |
| 100 | return XmlNode(m_node->FirstChildElement(), *m_doc); |
| 101 | } |
| 102 | |
| 103 | XmlNode XmlNode::FirstChild(const char* name) const |
| 104 | { |
| 105 | return XmlNode(m_node->FirstChildElement(name), *m_doc); |
| 106 | } |
| 107 | |
| 108 | XmlNode XmlNode::FirstChild(const Aws::String& name) const |
| 109 | { |
| 110 | return FirstChild(name.c_str()); |
| 111 | } |
| 112 | |
| 113 | bool XmlNode::HasChildren() const |
| 114 | { |
| 115 | return !m_node->NoChildren(); |
| 116 | } |
| 117 | |
| 118 | XmlNode XmlNode::Parent() const |
| 119 | { |
| 120 | return XmlNode(m_node->Parent()->ToElement(), *m_doc); |
| 121 | } |
| 122 | |
| 123 | Aws::String XmlNode::GetText() const |
| 124 | { |
| 125 | if (m_node != nullptr) |
| 126 | { |
| 127 | Aws::External::tinyxml2::XMLPrinter printer; |
| 128 | Aws::External::tinyxml2::XMLNode* node = m_node->FirstChild(); |
| 129 | while (node != nullptr) |
| 130 | { |
| 131 | node->Accept(&printer); |
| 132 | node = node->NextSibling(); |
| 133 | } |
| 134 | |
| 135 | return printer.CStr(); |
| 136 | } |
| 137 | |
| 138 | return {}; |
| 139 | } |
| 140 | |
| 141 | void XmlNode::SetText(const Aws::String& textValue) |
| 142 | { |
| 143 | if (m_node != nullptr) |
| 144 | { |
| 145 | Aws::External::tinyxml2::XMLText* text = m_doc->m_doc->NewText(textValue.c_str()); |
| 146 | m_node->InsertEndChild(text); |
| 147 | } |
| 148 | } |
| 149 | |
| 150 | XmlNode XmlNode::CreateChildElement(const Aws::String& name) |
| 151 | { |
| 152 | Aws::External::tinyxml2::XMLElement* element = m_doc->m_doc->NewElement(name.c_str()); |
| 153 | return XmlNode(m_node->InsertEndChild(element), *m_doc); |
| 154 | } |
| 155 | |
| 156 | XmlNode XmlNode::CreateSiblingElement(const Aws::String& name) |
| 157 | { |
| 158 | Aws::External::tinyxml2::XMLElement* element = m_doc->m_doc->NewElement(name.c_str()); |
| 159 | return XmlNode(m_node->Parent()->InsertEndChild(element), *m_doc); |
| 160 | } |
| 161 | |
| 162 | bool XmlNode::IsNull() |
| 163 | { |
| 164 | return m_node == nullptr; |
| 165 | } |
| 166 | |
| 167 | static const char* XML_SERIALIZER_ALLOCATION_TAG = "XmlDocument" ; |
| 168 | |
| 169 | XmlDocument::XmlDocument() |
| 170 | { |
| 171 | m_doc = Aws::New<Aws::External::tinyxml2::XMLDocument>(XML_SERIALIZER_ALLOCATION_TAG, true, Aws::External::tinyxml2::Whitespace::PRESERVE_WHITESPACE); |
| 172 | } |
| 173 | |
| 174 | XmlDocument::XmlDocument(XmlDocument&& doc) : m_doc{ doc.m_doc } // take the innards |
| 175 | { |
| 176 | doc.m_doc = nullptr; // leave nothing behind |
| 177 | } |
| 178 | |
| 179 | XmlDocument::~XmlDocument() |
| 180 | { |
| 181 | Aws::Delete(m_doc); |
| 182 | } |
| 183 | |
| 184 | XmlNode XmlDocument::GetRootElement() const |
| 185 | { |
| 186 | return XmlNode(m_doc->FirstChildElement(), *this); |
| 187 | } |
| 188 | |
| 189 | bool XmlDocument::WasParseSuccessful() const |
| 190 | { |
| 191 | return !m_doc->Error(); |
| 192 | } |
| 193 | |
| 194 | Aws::String XmlDocument::GetErrorMessage() const |
| 195 | { |
| 196 | return !WasParseSuccessful() ? m_doc->ErrorName() : "" ; |
| 197 | } |
| 198 | |
| 199 | Aws::String XmlDocument::ConvertToString() const |
| 200 | { |
| 201 | Aws::External::tinyxml2::XMLPrinter printer; |
| 202 | printer.PushHeader(false, true); |
| 203 | m_doc->Accept(&printer); |
| 204 | |
| 205 | return printer.CStr(); |
| 206 | } |
| 207 | |
| 208 | XmlDocument XmlDocument::CreateFromXmlStream(Aws::IOStream& xmlStream) |
| 209 | { |
| 210 | Aws::String xmlString((Aws::IStreamBufIterator(xmlStream)), Aws::IStreamBufIterator()); |
| 211 | return CreateFromXmlString(xmlString); |
| 212 | } |
| 213 | |
| 214 | XmlDocument XmlDocument::CreateFromXmlString(const Aws::String& xmlText) |
| 215 | { |
| 216 | XmlDocument xmlDocument; |
| 217 | xmlDocument.m_doc->Parse(xmlText.c_str(), xmlText.size()); |
| 218 | return xmlDocument; |
| 219 | } |
| 220 | |
| 221 | XmlDocument XmlDocument::CreateWithRootNode(const Aws::String& rootNodeName) |
| 222 | { |
| 223 | XmlDocument xmlDocument; |
| 224 | Aws::External::tinyxml2::XMLElement* rootNode = xmlDocument.m_doc->NewElement(rootNodeName.c_str()); |
| 225 | xmlDocument.m_doc->LinkEndChild(rootNode); |
| 226 | |
| 227 | return xmlDocument; |
| 228 | } |
| 229 | |
| 230 | |