XdmfWriter.cpp 8.24 KB
Newer Older
1 2 3
// Kenneth Leiter
// Xdmf Smart Pointer Test

4
#include <libxml/tree.h>
5
#include <sstream>
6
#include "XdmfArray.hpp"
7
#include "XdmfItem.hpp"
8
#include "XdmfHDF5Controller.hpp"
9
#include "XdmfHDF5Writer.hpp"
10
#include "XdmfSystemUtils.hpp"
11
#include "XdmfWriter.hpp"
12

13 14 15
/**
 * PIMPL
 */
16
class XdmfWriter::XdmfWriterImpl {
17 18 19

public:

20
	XdmfWriterImpl(const std::string & xmlFilePath, const boost::shared_ptr<XdmfHDF5Writer> hdf5Writer) :
21
		mHDF5Writer(hdf5Writer),
22
		mLastXPathed(false),
23
		mLightDataLimit(100),
24
		mMode(Default),
25
		mWriteXPaths(true),
26 27
		mXMLCurrentNode(NULL),
		mXMLDocument(NULL),
28
		mXMLFilePath(XdmfSystemUtils::getRealPath(xmlFilePath)),
29
		mXPathCount(0),
30 31 32 33
		mXPathString(""),
		mDocumentTitle("Xdmf"),
		mVersionString("2.0"),
		mDepth(0)
34 35
	{
	};
36

37
	~XdmfWriterImpl()
38 39
	{
	};
40 41 42 43 44 45 46 47 48 49 50 51

	void closeFile()
	{
		mXPath.clear();
		xmlSaveFormatFile(mXMLFilePath.c_str(), mXMLDocument, 1);
		xmlFreeDoc(mXMLDocument);
		xmlCleanupParser();
	};

	void openFile()
	{
		mXMLDocument = xmlNewDoc((xmlChar*)"1.0");
52
		mXMLCurrentNode = xmlNewNode(NULL, (xmlChar*)mDocumentTitle.c_str());
53
		xmlNewProp(mXMLCurrentNode, (xmlChar*)"xmlns:xi", (xmlChar*)"http://www.w3.org/2001/XInclude");
54
		xmlNewProp(mXMLCurrentNode, (xmlChar*)"Version", (xmlChar*)mVersionString.c_str());
55 56 57
		xmlDocSetRootElement(mXMLDocument, mXMLCurrentNode);
	}

58
	boost::shared_ptr<XdmfHDF5Writer> mHDF5Writer;
59
	bool mLastXPathed;
60
	unsigned int mLightDataLimit;
61
	Mode mMode;
62
	bool mWriteXPaths;
63
	xmlNodePtr mXMLCurrentNode;
64
	xmlDocPtr mXMLDocument;
65
	std::string mXMLFilePath;
66 67 68
	std::map<const XdmfItem * const, std::string> mXPath;
	unsigned int mXPathCount;
	std::string mXPathString;
69 70 71
	std::string mDocumentTitle;
	std::string mVersionString;
	int mDepth;
72 73
};

74 75 76 77 78 79 80 81 82 83 84 85 86
boost::shared_ptr<XdmfWriter> XdmfWriter::New(const std::string & xmlFilePath)
{
	boost::shared_ptr<XdmfWriter> p(new XdmfWriter(xmlFilePath));
	return p;
}

boost::shared_ptr<XdmfWriter> XdmfWriter::New(const std::string & xmlFilePath, const boost::shared_ptr<XdmfHDF5Writer> hdf5Writer)
{
	boost::shared_ptr<XdmfWriter> p(new XdmfWriter(xmlFilePath, hdf5Writer));
	return p;
}

XdmfWriter::XdmfWriter(const std::string & xmlFilePath)
87 88 89 90 91 92 93 94 95 96 97 98
{
	std::stringstream heavyFileName;
	size_t extension = xmlFilePath.rfind(".");
	if(extension != std::string::npos)
	{
		heavyFileName << xmlFilePath.substr(0, extension) << ".h5";
	}
	else
	{
		heavyFileName << xmlFilePath << ".h5";
	}
	boost::shared_ptr<XdmfHDF5Writer> hdf5Writer = XdmfHDF5Writer::New(heavyFileName.str());
99
	mImpl = new XdmfWriterImpl(xmlFilePath, hdf5Writer);
100 101
}

102 103
XdmfWriter::XdmfWriter(const std::string & xmlFilePath, boost::shared_ptr<XdmfHDF5Writer> hdf5Writer) :
	mImpl(new XdmfWriterImpl(xmlFilePath, hdf5Writer))
104 105 106
{
}

107
XdmfWriter::~XdmfWriter()
108
{
109
	delete mImpl;
110
}
111

112
boost::shared_ptr<XdmfHDF5Writer> XdmfWriter::getHDF5Writer()
113
{
114
	return boost::const_pointer_cast<XdmfHDF5Writer>(static_cast<const XdmfWriter &>(*this).getHDF5Writer());
115 116
}

117
boost::shared_ptr<const XdmfHDF5Writer> XdmfWriter::getHDF5Writer() const
118 119 120 121
{
	return mImpl->mHDF5Writer;
}

122
std::string XdmfWriter::getFilePath() const
123 124 125 126
{
	return mImpl->mXMLFilePath;
}

127
unsigned int XdmfWriter::getLightDataLimit() const
128
{
129
	return mImpl->mLightDataLimit;
130 131
}

132
XdmfWriter::Mode XdmfWriter::getMode() const
133 134 135 136
{
	return mImpl->mMode;
}

137
bool XdmfWriter::getWriteXPaths() const
138
{
139
	return mImpl->mWriteXPaths;
140 141
}

142
void XdmfWriter::setLightDataLimit(const unsigned int numValues)
143
{
144
	mImpl->mLightDataLimit = numValues;
145 146
}

147
void XdmfWriter::setMode(const Mode mode)
148 149 150 151
{
	mImpl->mMode = mode;
}

152 153 154 155 156
void XdmfWriter::setWriteXPaths(const bool writeXPaths)
{
	mImpl->mWriteXPaths = writeXPaths;
}

157 158 159 160 161 162 163 164 165 166
void XdmfWriter::setDocumentTitle(const std::string title)
{
	mImpl->mDocumentTitle = title;
}

void XdmfWriter::setVersionString(const std::string version)
{
	mImpl->mVersionString = version;
}

167
void XdmfWriter::visit(XdmfArray & array, const boost::shared_ptr<XdmfBaseVisitor> visitor)
168
{
169 170 171 172 173 174 175
	bool isSubclassed = array.getItemTag().compare(XdmfArray::ItemTag) != 0;

	if(isSubclassed)
	{
		this->visit(dynamic_cast<XdmfItem &>(array), visitor);
	}

176
	if(array.getSize() > 0 && !(mImpl->mLastXPathed && isSubclassed))
177
	{
178 179
		std::stringstream xmlTextValues;

180 181
		// Take care of writing to single HDF5 file (Default behavior)
		if(!array.isInitialized() && array.getHDF5Controller() && array.getHDF5Controller()->getFilePath().compare(mImpl->mHDF5Writer->getFilePath()) != 0 && mImpl->mMode == Default)
182 183 184 185
		{
			array.read();
		}

186
		if(array.getHDF5Controller() || array.getSize() > mImpl->mLightDataLimit)
187
		{
188
			// Write values to HDF5
189
			mImpl->mHDF5Writer->visit(array, mImpl->mHDF5Writer);
190 191 192 193

			std::string hdf5Path = array.getHDF5Controller()->getFilePath();
			size_t index = hdf5Path.find_last_of("/\\");
			if(index != std::string::npos)
194
			{
195 196
				std::string hdf5Dir = hdf5Path.substr(0, index + 1);
				if(mImpl->mXMLFilePath.find(hdf5Dir) == 0)
197
				{
198
					hdf5Path = hdf5Path.substr(hdf5Dir.size(), hdf5Path.size() - hdf5Dir.size());
199 200
				}
			}
201 202

			xmlTextValues << hdf5Path << ":" << array.getHDF5Controller()->getDataSetPath();
203 204 205
		}
		else
		{
206
			// Write values to XML
207 208 209
			xmlTextValues << array.getValuesString();
		}

210 211 212
		bool oldWriteXPaths = mImpl->mWriteXPaths;
		mImpl->mWriteXPaths = false;

213
		// Write XML (metadata) description
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
		if(isSubclassed)
		{
			boost::shared_ptr<XdmfArray> arrayToWrite = XdmfArray::New();
			array.swap(arrayToWrite);
			mImpl->mXMLCurrentNode = mImpl->mXMLCurrentNode->last;
			this->visit(dynamic_cast<XdmfItem &>(*arrayToWrite.get()), visitor);
			xmlAddChild(mImpl->mXMLCurrentNode->last, xmlNewText((xmlChar*)xmlTextValues.str().c_str()));
			mImpl->mXMLCurrentNode = mImpl->mXMLCurrentNode->parent;
			array.swap(arrayToWrite);
		}
		else
		{
			this->visit(dynamic_cast<XdmfItem &>(array), visitor);
			xmlAddChild(mImpl->mXMLCurrentNode->last, xmlNewText((xmlChar*)xmlTextValues.str().c_str()));
		}
229 230

		mImpl->mWriteXPaths = oldWriteXPaths;
231 232 233
	}
}

234
void XdmfWriter::visit(XdmfItem & item, const boost::shared_ptr<XdmfBaseVisitor> visitor)
235
{
236 237
	if (mImpl->mDepth == 0) {
		 mImpl->openFile();
238
	}
239
	mImpl->mDepth++;
240

241 242
	std::string tag = item.getItemTag();
	if (tag.length() == 0)
243
	{
244 245 246 247 248 249 250
		item.traverse(visitor);
	}
	else
	{
		if(mImpl->mWriteXPaths)
		{
			mImpl->mXPathCount++;
251

252
			std::string parentXPathString = mImpl->mXPathString;
253

254 255 256
			std::stringstream newXPathString;
			newXPathString << mImpl->mXPathString << "/" << mImpl->mXPathCount;
			mImpl->mXPathString = newXPathString.str();
257

258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
			std::map<const XdmfItem * const, std::string>::const_iterator iter = mImpl->mXPath.find(&item);
			if(iter != mImpl->mXPath.end())
			{
				// Inserted before --- just xpath location of previously written node
				mImpl->mXMLCurrentNode = xmlNewChild(mImpl->mXMLCurrentNode, NULL, (xmlChar*)"xi:include", NULL);
				xmlNewProp(mImpl->mXMLCurrentNode, (xmlChar*)"xpointer", (xmlChar*)iter->second.c_str());
				mImpl->mLastXPathed = true;
			}
			else
			{
				// Not inserted before --- need to write all data and traverse.
				mImpl->mXMLCurrentNode = xmlNewChild(mImpl->mXMLCurrentNode, NULL, (xmlChar *)tag.c_str(), NULL);
				std::stringstream xPathProp;
				xPathProp << "element(/1" << mImpl->mXPathString << ")";
				mImpl->mXPath[&item] = xPathProp.str();
				const std::map<std::string, std::string> itemProperties = item.getItemProperties();
				for(std::map<std::string, std::string>::const_iterator iter = itemProperties.begin(); iter != itemProperties.end(); ++iter)
				{
					xmlNewProp(mImpl->mXMLCurrentNode, (xmlChar*)iter->first.c_str(), (xmlChar*)iter->second.c_str());
				}
				unsigned int parentCount = mImpl->mXPathCount;
				mImpl->mXPathCount = 0;
				item.traverse(visitor);
				mImpl->mXPathCount = parentCount;
				mImpl->mLastXPathed = false;
			}

			mImpl->mXPathString = parentXPathString;
286 287 288 289
		}
		else
		{
			// Not inserted before --- need to write all data and traverse.
290
			mImpl->mXMLCurrentNode = xmlNewChild(mImpl->mXMLCurrentNode, NULL, (xmlChar*)tag.c_str(), NULL);
291 292 293 294 295 296 297 298
			const std::map<std::string, std::string> itemProperties = item.getItemProperties();
			for(std::map<std::string, std::string>::const_iterator iter = itemProperties.begin(); iter != itemProperties.end(); ++iter)
			{
				xmlNewProp(mImpl->mXMLCurrentNode, (xmlChar*)iter->first.c_str(), (xmlChar*)iter->second.c_str());
			}
			item.traverse(visitor);
		}

299
		mImpl->mXMLCurrentNode = mImpl->mXMLCurrentNode->parent;
300
	}
301

302 303
	mImpl->mDepth--;
	if(mImpl->mDepth <= 0)
304
	{
305
		mImpl->closeFile();
306
	}
307
}