XMLWriter.cc 5.24 KB
/*
 * XMLWriter.cc
 *
 *  Created on: 7 août 2013
 *      Author: CS
 */

#include "XMLWriter.hh"
#include <libxml/encoding.h>
#include <cstring>

namespace TimeTableCatalog {

XMLWriter::XMLWriter(const std::string& pPath, const std::string& pName) :
		AbstractWriter(pPath, pName) {
}

XMLWriter::~XMLWriter() {
}
// ----------------- PUBLIC --------------------------

std::string XMLWriter::write(const TimeTable& pTT, const char* pEncoding) {

	/*
	 * this initialize the library and check potential ABI mismatches
	 * between the version it was compiled for and the actual shared
	 * library used.
	 */
	LIBXML_TEST_VERSION

	xmlTextWriterPtr writer;

	// -- create a new XmlWriter for uri, with no compression.
	std::string filePath = getFile(pTT);
	writer = xmlNewTextWriterFilename(filePath.c_str(), 0);
	if (writer == NULL) {
		LOG4CXX_WARN(logger, "Error creating the xml writer");
		return "";
	}

	// -- write <?xml ... line
	writeHeader(pTT, writer, pEncoding);

	writeContent(pTT, writer);

	xmlFreeTextWriter(writer);

	// -- cleanup function for the XML library.
	//cf. http://xmlsoft.org/html/libxml-parser.html#xmlCleanupParser
	//xmlCleanupParser();

	return filePath;
}

// -------------------- PROTECTED --------------------------

void XMLWriter::writeHeader(const TimeTable& pTT, xmlTextWriterPtr& writer,
		const char* pEncoding) {
	int rc;
	/* Start the document with the xml default for the version,
	 * encoding UTF-8 and the default for the standalone
	 * declaration. */
	rc = xmlTextWriterStartDocument(writer, "1.0", pEncoding, NULL);
	if (rc < 0) {
		LOG4CXX_WARN(logger, "Error while writing header for " + getFile(pTT));
		return;
	}
}

void XMLWriter::writeElement(const TimeTable& pTT, xmlTextWriterPtr& pWriter,
		std::string pTag, const std::string & pValue, const char* pEncoding) {
	int rc;
	xmlChar *tmp = convertInput(pTT, pValue.c_str(), pEncoding);

	// -- add element named "name" as child of timetable
	rc = xmlTextWriterWriteElement(pWriter, BAD_CAST pTag.c_str(), tmp);
	if (rc < 0) {
		logTagError(pTag, getFile(pTT));
		return;
	}
	if (tmp != NULL)
		xmlFree(tmp);
}

/**
 * Writes a start tag.
 */
void XMLWriter::openTag(const TimeTable& pTT, xmlTextWriterPtr& pWriter, std::string pTag) {
	int rc = xmlTextWriterStartElement(pWriter, BAD_CAST pTag.c_str());
	if (rc < 0) {
		logStartTagError(pTag, getFile(pTT));
		return;
	}
}

/**
 * Adds an attribute to the current tag.
 */
void XMLWriter::addAttribute(const TimeTable& pTT, xmlTextWriterPtr& pWriter,
		std::string pAttribute, const std::string &pValue,
		const char* pEncoding) {

	xmlChar *tmp = convertInput(pTT, pValue.c_str(), pEncoding);
	int rc = xmlTextWriterWriteAttribute(pWriter, BAD_CAST pAttribute.c_str(),
			tmp);
	if (rc < 0) {
		logAttributeError(pAttribute, getFile(pTT));
		return;
	}
	if (tmp != NULL)
		xmlFree(tmp);
}

/**
 * Writes a stop tag.
 */
void XMLWriter::closeTag(const TimeTable& pTT, xmlTextWriterPtr& pWriter, std::string pTag) {
	int rc = xmlTextWriterEndElement(pWriter);
	if (rc < 0) {
		logEndTagError(pTag, getFile(pTT));
		return;
	}
}

/**
 * ConvertInput:
 * @in: string in a given encoding
 * @encoding: the encoding used
 *
 * Converts @in into UTF-8 for processing with libxml2 APIs
 *
 * Returns the converted UTF-8 string, or NULL in case of error.
 */
xmlChar * XMLWriter::convertInput(const TimeTable& pTT, const char *in,
		const char *encoding) {
	xmlChar *out;
	int size;
	int out_size;
	int temp;
	xmlCharEncodingHandlerPtr handler;

	if (in == 0)
		return 0;

	handler = xmlFindCharEncodingHandler(encoding);

	if (!handler) {
		LOG4CXX_WARN(logger,
				"Error while converting : no encoding handler found for "
						+ std::string(encoding) + " for " + getFile(pTT));
		return 0;
	}

	size = (int) strlen(in) + 1;
	out_size = size * 2 - 1;
	out = (unsigned char *) xmlMalloc((size_t) out_size);

	if (out != 0) {
		temp = size - 1;
		int ret = handler->input(out, &out_size, (const xmlChar *) in, &temp);
		if ((ret < 0) || (temp - size + 1)) {
			if (ret < 0) {
				LOG4CXX_WARN(logger,
						"Error while converting : converting failed for "
								+ getFile(pTT));
			} else {
				std::ostringstream os;
				os << temp;
				LOG4CXX_WARN(logger,
						"Error while converting : converting failed ("
								+ os.str() + " octets) for " + getFile(pTT));
			}

			xmlFree(out);
			out = 0;
		} else {
			out = (unsigned char *) xmlRealloc(out, out_size + 1);
			out[out_size] = 0; /*null terminating out */
		}
	} else {
		LOG4CXX_WARN(logger, "Error while converting : no mem for " + getFile(pTT));
	}

	return out;
}

void XMLWriter::logEndTagError(const std::string& pTag,
		const std::string& pTTPath) {
	LOG4CXX_WARN(logger,
			"Error while writing end of " + pTag + " element for " + pTTPath);
}
void XMLWriter::logStartTagError(const std::string& pTag,
		const std::string& pTTPath) {
	LOG4CXX_WARN(logger,
			"Error while writing start of " + pTag + "element for " + pTTPath);
}
void XMLWriter::logTagError(const std::string& pTag,
		const std::string& pTTPath) {
	LOG4CXX_WARN(logger,
			"Error while writing tag " + pTag + "element for " + pTTPath);
}
void XMLWriter::logAttributeError(const std::string& pAttribute,
		const std::string& pTTPath) {
	LOG4CXX_WARN(logger,
			"Error while writing attribute " + pAttribute + "element for "
					+ pTTPath);
}

} /* namespace TimeTableCatalog */