tamlXmlWriter.cpp
Engine/source/persistence/taml/xml/tamlXmlWriter.cpp
Detailed Description
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2013 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "persistence/taml/xml/tamlXmlWriter.h" 25 26// Debug Profiling. 27#include "platform/profiler.h" 28#include "persistence/taml/fsTinyXml.h" 29 30//----------------------------------------------------------------------------- 31 32bool TamlXmlWriter::write( FileStream& stream, const TamlWriteNode* pTamlWriteNode ) 33{ 34 // Debug Profiling. 35 PROFILE_SCOPE(TamlXmlWriter_Write); 36 37 // Create document. 38 fsTiXmlDocument xmlDocument; 39 40 // Compile the root element. 41 TiXmlElement* pRootElement = compileElement( pTamlWriteNode ); 42 43 // Fetch any TAML Schema file reference. 44 const char* pTamlSchemaFile = Con::getVariable( TAML_SCHEMA_VARIABLE ); 45 46 // Do we have a schema file reference? 47 if ( pTamlSchemaFile != NULL && *pTamlSchemaFile != 0 ) 48 { 49 // Yes, so add namespace attribute to root. 50 pRootElement->SetAttribute( "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance" ); 51 52 // Expand the file-path reference. 53 char schemaFilePathBuffer[1024]; 54 Con::expandToolScriptFilename( schemaFilePathBuffer, sizeof(schemaFilePathBuffer), pTamlSchemaFile ); 55 56 // Fetch the output path for the Taml file. 57 char outputFileBuffer[1024]; 58 dSprintf( outputFileBuffer, sizeof(outputFileBuffer), "%s", mpTaml->getFilePathBuffer() ); 59 char* pFileStart = dStrrchr( outputFileBuffer, '/' ); 60 if ( pFileStart == NULL ) 61 *outputFileBuffer = 0; 62 else 63 *pFileStart = 0; 64 65 // Fetch the schema file-path relative to the output file. 66 StringTableEntry relativeSchemaFilePath = Platform::makeRelativePathName( schemaFilePathBuffer, outputFileBuffer ); 67 68 // Add schema location attribute to root. 69 pRootElement->SetAttribute( "xsi:noNamespaceSchemaLocation", relativeSchemaFilePath ); 70 } 71 72 // Link the root element. 73 xmlDocument.LinkEndChild( pRootElement ); 74 75 // Save document to stream. 76 return xmlDocument.SaveFile( stream ); 77} 78 79//----------------------------------------------------------------------------- 80 81TiXmlElement* TamlXmlWriter::compileElement( const TamlWriteNode* pTamlWriteNode ) 82{ 83 // Debug Profiling. 84 PROFILE_SCOPE(TamlXmlWriter_CompileElement); 85 86 // Fetch object. 87 SimObject* pSimObject = pTamlWriteNode->mpSimObject; 88 89 // Fetch element name. 90 const char* pElementName = pSimObject->getClassName(); 91 92 // Create element. 93 TiXmlElement* pElement = new fsTiXmlElement( pElementName ); 94 95 // Fetch reference Id. 96 const U32 referenceId = pTamlWriteNode->mRefId; 97 98 // Do we have a reference Id? 99 if ( referenceId != 0 ) 100 { 101 // Yes, so set reference Id attribute. 102 pElement->SetAttribute( tamlRefIdName, referenceId ); 103 } 104 105 // Do we have a reference to node? 106 else if ( pTamlWriteNode->mRefToNode != NULL ) 107 { 108 // Yes, so fetch reference to Id. 109 const U32 referenceToId = pTamlWriteNode->mRefToNode->mRefId; 110 111 // Sanity! 112 AssertFatal( referenceToId != 0, "Taml: Invalid reference to Id." ); 113 114 // Set reference to Id attribute. 115 pElement->SetAttribute( tamlRefToIdName, referenceToId ); 116 117 // Finish because we're a reference to another object. 118 return pElement; 119 } 120 121 // Fetch object name. 122 const char* pObjectName = pTamlWriteNode->mpObjectName; 123 124 // Do we have a name? 125 if ( pObjectName != NULL ) 126 { 127 // Yes, so set name attribute. 128 pElement->SetAttribute( tamlNamedObjectName, pObjectName ); 129 } 130 131 // Compile attributes. 132 compileAttributes( pElement, pTamlWriteNode ); 133 134 // Fetch children. 135 Vector<TamlWriteNode*>* pChildren = pTamlWriteNode->mChildren; 136 137 // Do we have any children? 138 if ( pChildren ) 139 { 140 // Yes, so iterate children. 141 for( Vector<TamlWriteNode*>::iterator itr = pChildren->begin(); itr != pChildren->end(); ++itr ) 142 { 143 // Write child element. 144 pElement->LinkEndChild( compileElement( (*itr) ) ); 145 } 146 } 147 148 // Compile custom elements. 149 compileCustomElements( pElement, pTamlWriteNode ); 150 151 return pElement; 152} 153 154//----------------------------------------------------------------------------- 155 156void TamlXmlWriter::compileAttributes( TiXmlElement* pXmlElement, const TamlWriteNode* pTamlWriteNode ) 157{ 158 // Debug Profiling. 159 PROFILE_SCOPE(TamlXmlWriter_CompileAttributes); 160 161 // Fetch fields. 162 const Vector<TamlWriteNode::FieldValuePair*>& fields = pTamlWriteNode->mFields; 163 164 // Ignore if no fields. 165 if ( fields.size() == 0 ) 166 return; 167 168 // Iterate fields. 169 for( Vector<TamlWriteNode::FieldValuePair*>::const_iterator itr = fields.begin(); itr != fields.end(); ++itr ) 170 { 171 // Fetch field/value pair. 172 TamlWriteNode::FieldValuePair* pFieldValue = (*itr); 173 174 // Set field attribute. 175 pXmlElement->SetAttribute( pFieldValue->mName, pFieldValue->mpValue ); 176 } 177} 178 179//----------------------------------------------------------------------------- 180 181void TamlXmlWriter::compileCustomElements( TiXmlElement* pXmlElement, const TamlWriteNode* pTamlWriteNode ) 182{ 183 // Debug Profiling. 184 PROFILE_SCOPE(TamlXmlWriter_CompileCustomElements); 185 186 // Fetch custom nodes. 187 const TamlCustomNodes& customNodes = pTamlWriteNode->mCustomNodes; 188 189 // Fetch custom nodes. 190 const TamlCustomNodeVector& nodes = customNodes.getNodes(); 191 192 // Finish if no custom nodes to process. 193 if ( nodes.size() == 0 ) 194 return; 195 196 // Iterate custom nodes. 197 for( TamlCustomNodeVector::const_iterator customNodesItr = nodes.begin(); customNodesItr != nodes.end(); ++customNodesItr ) 198 { 199 // Fetch the custom node. 200 TamlCustomNode* pCustomNode = *customNodesItr; 201 202 // Format extended element name. 203 char extendedElementNameBuffer[256]; 204 dSprintf( extendedElementNameBuffer, sizeof(extendedElementNameBuffer), "%s.%s", pXmlElement->Value(), pCustomNode->getNodeName() ); 205 StringTableEntry extendedElementName = StringTable->insert( extendedElementNameBuffer ); 206 207 // Create element. 208 TiXmlElement* pExtendedPropertyElement = new fsTiXmlElement( extendedElementName ); 209 210 // Fetch node children. 211 const TamlCustomNodeVector& nodeChildren = pCustomNode->getChildren(); 212 213 // Iterate children nodes. 214 for( TamlCustomNodeVector::const_iterator childNodeItr = nodeChildren.begin(); childNodeItr != nodeChildren.end(); ++childNodeItr ) 215 { 216 // Fetch child node. 217 const TamlCustomNode* pChildNode = *childNodeItr; 218 219 // Compile the custom node. 220 compileCustomNode( pExtendedPropertyElement, pChildNode ); 221 } 222 223 // Finish if the node is set to ignore if empty and it is empty. 224 if ( pCustomNode->getIgnoreEmpty() && pExtendedPropertyElement->NoChildren() ) 225 { 226 // Yes, so delete the extended element. 227 delete pExtendedPropertyElement; 228 pExtendedPropertyElement = NULL; 229 } 230 else 231 { 232 // No, so add elementt as child. 233 pXmlElement->LinkEndChild( pExtendedPropertyElement ); 234 } 235 } 236} 237 238//----------------------------------------------------------------------------- 239 240void TamlXmlWriter::compileCustomNode( TiXmlElement* pXmlElement, const TamlCustomNode* pCustomNode ) 241{ 242 // Finish if the node is set to ignore if empty and it is empty. 243 if ( pCustomNode->getIgnoreEmpty() && pCustomNode->isEmpty() ) 244 return; 245 246 // Is the node a proxy object? 247 if ( pCustomNode->isProxyObject() ) 248 { 249 // Yes, so write the proxy object. 250 pXmlElement->LinkEndChild( compileElement( pCustomNode->getProxyWriteNode() ) ); 251 return; 252 } 253 254 // Create element. 255 TiXmlElement* pNodeElement = new fsTiXmlElement( pCustomNode->getNodeName() ); 256 257 // Is there any node text? 258 if ( !pCustomNode->getNodeTextField().isValueEmpty() ) 259 { 260 // Yes, so add a text node. 261 pNodeElement->LinkEndChild( new TiXmlText( pCustomNode->getNodeTextField().getFieldValue() ) ); 262 } 263 264 // Fetch fields. 265 const TamlCustomFieldVector& fields = pCustomNode->getFields(); 266 267 // Iterate fields. 268 for ( TamlCustomFieldVector::const_iterator fieldItr = fields.begin(); fieldItr != fields.end(); ++fieldItr ) 269 { 270 // Fetch field. 271 const TamlCustomField* pField = *fieldItr; 272 273 // Set field. 274 pNodeElement->SetAttribute( pField->getFieldName(), pField->getFieldValue() ); 275 } 276 277 // Fetch node children. 278 const TamlCustomNodeVector& nodeChildren = pCustomNode->getChildren(); 279 280 // Iterate children nodes. 281 for( TamlCustomNodeVector::const_iterator childNodeItr = nodeChildren.begin(); childNodeItr != nodeChildren.end(); ++childNodeItr ) 282 { 283 // Fetch child node. 284 const TamlCustomNode* pChildNode = *childNodeItr; 285 286 // Compile the child node. 287 compileCustomNode( pNodeElement, pChildNode ); 288 } 289 290 // Finish if the node is set to ignore if empty and it is empty (including fields). 291 if ( pCustomNode->getIgnoreEmpty() && fields.size() == 0 && pNodeElement->NoChildren() ) 292 { 293 // Yes, so delete the extended element. 294 delete pNodeElement; 295 pNodeElement = NULL; 296 } 297 else 298 { 299 // Add node element as child. 300 pXmlElement->LinkEndChild( pNodeElement ); 301 } 302} 303